Test navigateur : attendre l'enregistrement de la nouvelle partie

Sous Firefox, sur disque lent, l'enregistrement de la nouvelle partie
attend dans la file derrière l'analyse de la partie finie ; le test lisait
IndexedDB trop tôt. Il attend désormais que la partie en cours change.
Test unitaire : rien n'est perdu avec un stockage lent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Pierre MARTIN
2026-11-12 02:47:38 +01:00
co-authored by Claude Opus 5.5
parent 99294900a0
commit cb42052c80
2 changed files with 100 additions and 1 deletions
+49 -1
View File
@@ -164,6 +164,45 @@ async function readJournal() {
);
}
/** L'identifiant de la partie en cours enregistrée dans IndexedDB
* (magasin settings, clé « current »), ou null. */
async function savedGameId() {
return page.evaluate(
() =>
new Promise((resolve, reject) => {
const open = indexedDB.open("ustagammon");
open.onerror = () => reject(open.error);
open.onsuccess = () => {
const db = open.result;
const current = db.transaction("settings").objectStore("settings").get("current");
current.onsuccess = () => {
db.close();
resolve(current.result?.value ?? null);
};
};
}),
);
}
/**
* Attend que la partie en cours enregistrée ne soit plus oldId, et renvoie
* le temps d'attente en ms (null au bout de 30 s). L'application enregistre
* sans attendre l'écriture, dans une file (app/src/storage/game-library.ts) :
* sous Firefox, sur un disque lent et chargé, l'enregistrement de la
* nouvelle partie peut attendre derrière ceux de l'analyse de la partie
* finie, et une lecture directe d'IndexedDB trouver encore l'ancienne.
*/
async function waitForSavedGameOtherThan(oldId) {
const start = Date.now();
while (Date.now() - start < 30_000) {
if ((await savedGameId()) !== oldId) {
return Date.now() - start;
}
await sleep(100);
}
return null;
}
/** Le nombre de parties enregistrées dans IndexedDB. */
async function savedGameCount() {
await savedJournal(); // les enregistrements en cours terminés
@@ -1026,6 +1065,7 @@ async function rematch() {
* immédiat, bandeau 10 s. Renvoie le journal de la partie quittée. */
async function newGameFromMenu() {
const before = await savedJournal();
const beforeId = await savedGameId();
const started = () =>
page.evaluate(() => JSON.parse(localStorage.getItem("ustagammon.settings") ?? "{}").gamesStarted);
const startedBefore = await started();
@@ -1038,6 +1078,8 @@ async function newGameFromMenu() {
`bandeau : « ${await page.textContent("#banner")} »`);
check(!(await page.isVisible("#menu")), "le menu reste ouvert après « Nouvelle partie »");
await waitForPlayer();
check((await waitForSavedGameOtherThan(beforeId)) !== null,
"« Nouvelle partie » : la partie n'a pas été enregistrée (30 s)");
const after = await savedJournal();
// (Les identifiants d'événements se suivent : une partie neuve peut avoir
// la même tête que la précédente ; on compte les parties commencées.)
@@ -1617,11 +1659,17 @@ step("mes parties");
// recharger la page.
{
const finished = await savedJournal();
const finishedId = await savedGameId();
await rematch();
await waitForPlayer();
// L'état observable, et non un délai : la nouvelle partie devient la
// partie en cours enregistrée.
const waited = await waitForSavedGameOtherThan(finishedId);
check(waited !== null, "la nouvelle partie n'a pas été enregistrée (30 s)");
log(`nouvelle partie enregistrée ${waited} ms après la main au joueur`);
const second = await savedJournal();
check(second.head !== finished.head || second.events.length !== finished.events.length,
"la nouvelle partie n'a pas été enregistrée");
"la nouvelle partie enregistrée a le journal de la partie finie");
await openMenu();
await page.click("#menu-games");
await page.waitForSelector("#games-veil:not([hidden]) .games-item");