case 4690 - E2E: reliable login and notification wait on remote servers

Over the internet the login page reloads once on a first visit (service
worker taking control) and can move the focus back to the username field
while it settles; both made logins fail at random (8.2.4 and 8.3.0). ayLogin
now lets the service worker take control first, waits for notify/hello and the
trial users list, checks both fields and types again if needed, and clicks the
login button. 0900 reloads Notifications until the notification arrives (the
server delivers about once a minute). 27/27 on the 8.3.0 release candidate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 17:12:31 -07:00
parent e0b3641f00
commit ad8fbdec54
2 changed files with 63 additions and 6 deletions

View File

@@ -56,19 +56,61 @@ Cypress.Commands.add("ayLogin", (user, urlAfterLogin) => {
if (!urlAfterLogin) {
urlAfterLogin = "/ay-evaluate";
}
// On a first visit to a built server the app's service worker installs, takes control and
// App.vue then reloads the page (controllerchange); a reload while typing fails the test.
// Let that happen first: wait until the service worker controls the page (at most 15 seconds,
// never failing; the local dev server has none), then open the login page again.
cy.visit("/login");
cy.get("input[name=username]").clear();
cy.get("input[name=password]").clear();
cy.window().then(
{ timeout: 20000 },
(win) =>
new Cypress.Promise((resolve) => {
const sw = win.navigator.serviceWorker;
if (!sw || sw.controller) {
return resolve();
}
const giveUp = setTimeout(resolve, 15000);
sw.addEventListener("controllerchange", () => {
clearTimeout(giveUp);
resolve();
});
})
);
cy.get("input[name=username]").clear().type(Cypress.env(user).login);
// the login page fills in sample credentials and adds the trial users list above the
// username field when notify/hello answers (trial servers); wait for that first.
// The suite always runs on a seeded trial.
cy.intercept("GET", "**/notify/hello").as("hello");
cy.visit("/login");
cy.wait("@hello");
cy.get("[data-cy=selecttrialuser]");
// {enter} causes the form to submit
cy.get("input[name=password]").clear()
.type(`${Cypress.env(user).password}{enter}`);
ayFillLogin(Cypress.env(user).login, Cypress.env(user).password, 5);
// the button logs in with whatever is in the fields, wherever the keyboard focus is
cy.get("[data-cy=loginbutton]").click();
cy.url().should("include", urlAfterLogin);
});
// Over the internet the login page can still redraw while it settles, and on a first visit the
// service worker reloads it once (App.vue, controllerchange). A redraw moves the keyboard focus
// back to the username field (v-focus) mid-typing, a reload wipes both fields (both seen on 8.2.4
// and 8.3.0). So type, give any redraw under way a moment, check both fields, and type again if
// either is wrong.
function ayFillLogin(login, password, triesLeft) {
cy.get("input[name=username]").clear().type(login);
cy.get("input[name=password]").clear().type(password);
cy.wait(500);
cy.get("input[name=username]").then(($u) => {
cy.get("input[name=password]").then(($p) => {
if (($u.val() !== login || $p.val() !== password) && triesLeft > 0) {
ayFillLogin(login, password, triesLeft - 1);
}
});
});
}
Cypress.Commands.add("ayChooseExistingTags", (dataCyTag, tagList) => {
for (let i = 0; i < tagList.length; i++) {
cy.get(`[data-cy='${dataCyTag}']`).click().type(tagList[i]);

View File

@@ -6,9 +6,24 @@ describe("Tax code", () => {
cy.get("[data-cy=notification]").click();
cy.url().should("include", "/home-notifications");
// the server delivers notifications about once a minute (release build) and this page does not
// refresh itself, so reload until the contract notification from 0500 has arrived
waitForNotification(15);
cy.contains("Object created");
//Going to assume this is a virgin run so test contract text should be there but not going to assume it's due to current run so not checking for cyid
//cy.contains(`${Cypress.config("cyid")}-test-contract`);
cy.contains('-test-contract');
});
});
// check 5 seconds after each (re)load, up to the given number of times, until "Object created" shows
function waitForNotification(triesLeft) {
cy.wait(5000);
cy.get("body").then(($body) => {
if ($body.text().includes("Object created") || triesLeft <= 0) {
return;
}
cy.reload();
waitForNotification(triesLeft - 1);
});
}