e2e: harden akLogin against the Lit stage re-render race
fill-verify-Enter with a single inputValue read per stage (identification and password); the toHaveValue assertion hard-failed every attempt when the re-render wipe landed inside its 5s window (00-auth.setup failure 2026-09-24)
This commit is contained in:
1 parent
b48de913b8
commit
b1372d428f
1 file changed
+20
-10
+20
-10
@@ -13,20 +13,30 @@ export async function akLogin(page: Page, baseUrl: string, user: string, pass: s
|
|||||||
await page.goto(baseUrl + "/");
|
await page.goto(baseUrl + "/");
|
||||||
const uid = page.locator('input[name="uidField"]');
|
const uid = page.locator('input[name="uidField"]');
|
||||||
await uid.waitFor({ state: "visible", timeout: 90_000 });
|
await uid.waitFor({ state: "visible", timeout: 90_000 });
|
||||||
await uid.fill(user);
|
|
||||||
await page.locator('button[type="submit"]').first().click();
|
// The flow executor (Lit) re-renders a stage right after mount and can wipe
|
||||||
|
// a programmatic fill; a submit then POSTs an empty form ("This field is
|
||||||
|
// required") and the stage never advances. Both stages share the race:
|
||||||
|
// fill, VERIFY the value survived with a single read (a toHaveValue
|
||||||
|
// assertion hard-fails the attempt when the wipe lands inside its window),
|
||||||
|
// submit via Enter (native form path; the button can be re-created between
|
||||||
|
// snapshot and click), and retry if the stage reset under us.
|
||||||
|
for (let attempt = 0; attempt < 3; attempt++) {
|
||||||
|
await uid.fill(user);
|
||||||
|
if ((await uid.inputValue()) !== user) continue;
|
||||||
|
await uid.press("Enter");
|
||||||
|
try {
|
||||||
|
await page.locator('input[name="password"]').waitFor({ state: "visible", timeout: 15_000 });
|
||||||
|
break;
|
||||||
|
} catch {
|
||||||
|
if (attempt === 2) throw new Error("identification stage never advanced after 3 attempts");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const pwd = page.locator('input[name="password"]');
|
const pwd = page.locator('input[name="password"]');
|
||||||
await pwd.waitFor({ state: "visible", timeout: 30_000 });
|
|
||||||
|
|
||||||
// authentik's flow executor (Lit) can re-render the stage right after it
|
|
||||||
// mounts, wiping a programmatic fill; clicking the submit button then
|
|
||||||
// POSTs an empty form ("This field is required"). Fill, VERIFY the value
|
|
||||||
// survived, and submit via Enter (native form path), retrying if the
|
|
||||||
// stage reset under us.
|
|
||||||
for (let attempt = 0; attempt < 3; attempt++) {
|
for (let attempt = 0; attempt < 3; attempt++) {
|
||||||
await pwd.fill(pass);
|
await pwd.fill(pass);
|
||||||
await expect(pwd).toHaveValue(pass, { timeout: 5_000 });
|
if ((await pwd.inputValue()) !== pass) continue;
|
||||||
await pwd.press("Enter");
|
await pwd.press("Enter");
|
||||||
try {
|
try {
|
||||||
await page.waitForURL(/:\/\/www\.franksdank\.cloud\//, { timeout: 20_000 });
|
await page.waitForURL(/:\/\/www\.franksdank\.cloud\//, { timeout: 20_000 });
|
||||||
|
|||||||
Reference in new issue
Block a user