Ng eventually #1

Open
Sylvain wants to merge 110 commits from ng-eventually into main
2 changed files with 26 additions and 7 deletions
Showing only changes of commit c07150cb27 - Show all commits
@@ -1,5 +1,5 @@
# language: fr
@EVENT @priority-1 @data @wip
@EVENT @priority-1 @data
Fonctionnalité: Reconnexion d'une même identité sur le wallet persistant
En tant qu'utilisateur qui, sur le MÊME wallet physique, ouvre une PAGE FRAÎCHE
(nouveau login broker, session fraîche) sous le MÊME identifiant qu'avant,
@@ -52,21 +52,34 @@ When('une page fraîche pour la MÊME identité A recharge sur le même wallet',
(this as any).recoFreshFrame = freshFrame;
});
Then('l\'événement {string} est sur l\'accueil de la page fraîche A', async function (this: FestipodWorld, title: string) {
// The cold-start read is a BOUNDED SYNC-LAG (measured: the just-created public
// doc lists on the first cold attempt, home titles converge at ~1s), and the real
// UI is reactive — so these assertions POLL for convergence (up to ~15s) instead
// of reading once. A single-shot read races the first-open/sync window and would
// flake. This mirrors how the app's own steps already poll participation.
Then('l\'événement {string} est sur l\'accueil de la page fraîche A', { timeout: 60000 }, async function (this: FestipodWorld, title: string) {
const freshFrame = (this as any).recoFreshFrame;
const onHome = await freshFrame.evaluate((title: string) => {
const onHome = await freshFrame.evaluate(async (title: string) => {
const td = (window as any).__testData;
for (let i = 0; i < 30; i++) {
if (td.homeEventTitles().includes(title)) return true;
await new Promise(r => setTimeout(r, 500));
}
return td.homeEventTitles().includes(title);
}, title);
expect(onHome, `"${title}" MUST appear on the fresh A page's home (getUserEvents(A) after reconnect)`).to.be.true;
});
Then('la page fraîche A est participante de l\'événement {string}', async function (this: FestipodWorld, title: string) {
Then('la page fraîche A est participante de l\'événement {string}', { timeout: 60000 }, async function (this: FestipodWorld, title: string) {
const freshFrame = (this as any).recoFreshFrame;
const eventId = (this as any).isoEventId;
const isPart = await freshFrame.evaluate(async ({ eventId }: { eventId: string }) => {
const td = (window as any).__testData;
const aId = await td.ensureCurrentUser();
for (let i = 0; i < 30; i++) {
if (td.isParticipating(eventId, aId)) return true;
await new Promise(r => setTimeout(r, 500));
}
return td.isParticipating(eventId, aId);
}, { eventId });
expect(isPart, `The fresh A page MUST read its own participation in "${title}" after reconnect`).to.be.true;
@@ -75,10 +88,16 @@ Then('la page fraîche A est participante de l\'événement {string}', async fun
Then('le compte autoritatif de participation de A à l\'événement {string} est {int}', { timeout: 60000 }, async function (this: FestipodWorld, _title: string, expected: number) {
const freshFrame = (this as any).recoFreshFrame;
const eventId = (this as any).isoEventId;
const count = await freshFrame.evaluate(async ({ eventId }: { eventId: string }) => {
const count = await freshFrame.evaluate(async ({ eventId, expected }: { eventId: string; expected: number }) => {
const td = (window as any).__testData;
const aId = await td.ensureCurrentUser();
return td.authParticipationCount(eventId, aId);
}, { eventId });
let last = -1;
for (let i = 0; i < 30; i++) {
last = await td.authParticipationCount(eventId, aId);
if (last === expected) return last;
await new Promise(r => setTimeout(r, 500));
}
return last;
}, { eventId, expected });
expect(count, `Authoritative broker count of A's participation must be ${expected} after reconnect`).to.equal(expected);
});