fix(probe): wait for login form values
This commit is contained in:
@@ -332,7 +332,7 @@ async function collectFailureDomEvidence(page) {
|
||||
cardVisible: Boolean(document.querySelector(".login-card")),
|
||||
usernameVisible: Boolean(document.querySelector('#login-username, input[autocomplete="username"]')),
|
||||
passwordVisible: Boolean(document.querySelector('#login-password, input[autocomplete="current-password"], input[type="password"]')),
|
||||
errorText: text(".login-error, [role='alert'], .error, .text-red-500, .text-destructive")
|
||||
errorText: text(".form-error, .login-error, [role='alert'], .error, .text-red-500, .text-destructive")
|
||||
},
|
||||
requiredSelectors: {
|
||||
workspace: Boolean(document.querySelector("#workspace")),
|
||||
@@ -520,15 +520,39 @@ async function submitCurrentLoginForm(page, args, actions, selectorMode) {
|
||||
}
|
||||
await username.fill(args.user);
|
||||
await password.fill(args.pass);
|
||||
const valuesReady = await waitForCurrentLoginValues(page, args);
|
||||
await Promise.allSettled([
|
||||
page.waitForURL(/\/workbench/u, { timeout: Math.min(args.timeoutMs, 15000) }),
|
||||
submit.click()
|
||||
]);
|
||||
actions.push({ action: "login", user: args.user, selectorMode });
|
||||
actions.push({ action: "login", user: args.user, selectorMode, valuesReady });
|
||||
const outcome = await waitForLoginOutcome(page, args);
|
||||
if (outcome?.kind === "error") throw new Error(`login failed: ${outcome.errorText || "unknown login error"}`);
|
||||
await page.locator("#command-input").waitFor({ state: "visible", timeout: args.timeoutMs });
|
||||
assertNoCredentialLeak(page.url());
|
||||
}
|
||||
|
||||
async function waitForCurrentLoginValues(page, args) {
|
||||
const ready = await page.waitForFunction((expected) => {
|
||||
const username = document.querySelector('input[autocomplete="username"], .login-card input');
|
||||
const password = document.querySelector('input[autocomplete="current-password"], .login-card input[type="password"], input[type="password"]');
|
||||
const submit = document.querySelector('.login-card button[type="submit"], button[type="submit"]');
|
||||
return Boolean(username && password && username.value === expected.user && password.value.length === expected.passwordLength && !submit?.disabled);
|
||||
}, { user: args.user, passwordLength: args.pass.length }, { timeout: Math.min(args.timeoutMs, 5000) }).catch(() => null);
|
||||
return Boolean(ready);
|
||||
}
|
||||
|
||||
async function waitForLoginOutcome(page, args) {
|
||||
const handle = await page.waitForFunction(() => {
|
||||
if (document.querySelector("#command-input")) return { kind: "workspace" };
|
||||
const errorText = document.querySelector(".form-error, .login-error, [role='alert'], .error, .text-red-500, .text-destructive")?.textContent?.trim();
|
||||
if (errorText) return { kind: "error", errorText };
|
||||
return null;
|
||||
}, null, { timeout: Math.min(args.timeoutMs, 15000) }).catch(() => null);
|
||||
if (!handle) return null;
|
||||
return handle.jsonValue().catch(() => null);
|
||||
}
|
||||
|
||||
function assertNoCredentialLeak(value) {
|
||||
const finalUrl = new URL(value);
|
||||
if (finalUrl.searchParams.has("username") || finalUrl.searchParams.has("password")) {
|
||||
|
||||
Reference in New Issue
Block a user