sokko-g/e2e/toolbox.spec.js
Shinuwa 0ac1a0974e
All checks were successful
Deploy Sokko G / deploy (push) Successful in 19s
Refocus responsive layouts on compact desktop use
2026-10-05 15:47:46 +02:00

496 lines
24 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Rôle : couvre les parcours navigateur principaux des toolboxes locales.
/* global window, document, navigator, CustomEvent, FileSystemDirectoryHandle */
import { expect, test } from "@playwright/test";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { resetSokkoStorage } from "./helpers/storage.js";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const fixturePath = path.join(__dirname, "fixtures", "toolbox-export.json");
async function collectBrowserErrors(page) {
const errors = [];
page.on("pageerror", (error) => errors.push(`pageerror: ${error.stack || error.message}`));
page.on("console", (message) => {
if (message.type() === "error") errors.push(`console: ${message.text()}`);
});
return errors;
}
async function createToolbox(page, name) {
await page.goto("/#/toolboxes");
await expect(page.getByRole("main")).toBeVisible();
await page.getByRole("button", { name: "Nouvelle toolbox" }).click();
const dialog = page.getByRole("dialog", { name: "Nouvelle toolbox" });
await expect(dialog).toBeVisible();
await dialog.getByLabel("Nom").fill(name);
await dialog.getByRole("button", { name: "Créer" }).click();
await expect(page.getByRole("heading", { name })).toBeVisible();
}
async function addTool(page, name) {
await page.getByRole("button", { name: "Ajouter un outil", exact: true }).click();
const addDialog = page.getByRole("dialog", { name: "Ajouter un outil" });
await expect(addDialog).toBeVisible();
await addDialog.getByRole("button", { name }).click();
}
function moduleByType(page, type) {
return page.locator(`[data-module-type='${type}']`);
}
function tableCell(table, address) {
return table.getByRole("textbox", { name: `Cellule ${address}`, exact: true });
}
test.beforeEach(async ({ page }) => {
await resetSokkoStorage(page);
page.browserErrors = await collectBrowserErrors(page);
});
test.afterEach(async ({ page }) => {
expect(page.browserErrors, page.browserErrors.join("\n")).toEqual([]);
});
test("creates a toolbox and lazy-loads an added tool", async ({ page }) => {
await createToolbox(page, "E2E Toolbox");
await expect(page.getByRole("heading", { name: "E2E Toolbox" })).toBeVisible();
await expect(page.locator("[data-module-type='memos']")).toBeVisible();
await expect(page.locator("[data-module-type='links']")).toBeVisible();
await addTool(page, "Arbre d'objectifs");
await expect(page.locator("[data-module-type='goalTree']")).toBeVisible();
});
test("keeps an uncommitted memo through unrelated app updates and saves multiline text", async ({ page }) => {
await createToolbox(page, "Memo draft toolbox");
const memos = moduleByType(page, "memos");
const editor = memos.getByRole("textbox", { name: "Modifier le mémo" }).first();
await editor.fill("Premiere ligne\nDeuxieme ligne");
await page.evaluate(() => window.dispatchEvent(new CustomEvent("sokkog:notify", {
detail: { message: "Memo draft notification" }
})));
await expect(page.getByText("Memo draft notification", { exact: true })).toBeVisible();
await expect(editor).toHaveValue("Premiere ligne\nDeuxieme ligne");
await editor.press("End");
await editor.press("Enter");
await editor.pressSequentially("Troisieme ligne");
await editor.blur();
await expect(editor).toHaveValue("Premiere ligne\nDeuxieme ligne\nTroisieme ligne");
await page.reload();
await expect(editor).toHaveValue("Premiere ligne\nDeuxieme ligne\nTroisieme ligne");
await editor.fill(" Premiere ligne\nDeuxieme ligne\nTroisieme ligne ");
await editor.blur();
await expect(editor).toHaveValue("Premiere ligne\nDeuxieme ligne\nTroisieme ligne");
await editor.fill(" ");
await editor.blur();
await expect(memos.locator(".memo-card")).toHaveCount(0);
});
test("creates, edits and deletes a weekly calendar event", async ({ page }) => {
await createToolbox(page, "Calendar E2E Toolbox");
await addTool(page, "Calendrier");
const calendar = page.locator("[data-module-type='calendar']");
await expect(calendar).toBeVisible();
await calendar.getByRole("button", { name: "Hebdomadaire" }).click();
await expect(calendar.locator(".calendar-week-grid")).toBeVisible();
await calendar.getByRole("button", { name: /Afficher l'ajout de Calendrier/ }).click();
await calendar.getByLabel("Titre").fill("Raid E2E");
await calendar.getByRole("textbox", { name: "Début" }).fill("18:00");
await calendar.getByRole("textbox", { name: "Fin" }).fill("20:00");
await calendar.getByRole("button", { name: "Ajouter" }).click();
await expect(calendar.getByRole("button", { name: /Raid E2E/ })).toBeVisible();
await calendar.getByRole("button", { name: /Raid E2E/ }).click();
await calendar.getByLabel("Titre").fill("Raid E2E modifié");
await calendar.getByRole("button", { name: "Enregistrer" }).click();
await expect(calendar.getByRole("button", { name: /Raid E2E modifié/ })).toBeVisible();
await expect(calendar.getByRole("button", { name: /Raid E2E$/ })).toHaveCount(0);
await calendar.getByRole("button", { name: /Raid E2E modifié/ }).click();
await calendar.getByRole("button", { name: "Supprimer" }).click();
await expect(calendar.getByRole("button", { name: /Raid E2E modifié/ })).toHaveCount(0);
});
test("updates weekly and monthly calendar drafts when extending a selection", async ({ page }) => {
await createToolbox(page, "Calendar selection E2E");
await addTool(page, "Calendrier");
const weekly = moduleByType(page, "calendar").first();
await weekly.getByRole("button", { name: "Hebdomadaire" }).click();
await weekly.getByRole("button", { name: /Afficher l'ajout de Calendrier/ }).click();
const slots = weekly.locator(".calendar-day-column").first().locator(".calendar-slot");
await slots.nth(21).dispatchEvent("pointerdown", { buttons: 1 });
await slots.nth(18).dispatchEvent("pointerover", { buttons: 1 });
await slots.nth(18).dispatchEvent("pointerup", { buttons: 0 });
await expect(weekly.getByRole("textbox", { name: "Début" })).toHaveValue("09:00");
await expect(weekly.getByRole("textbox", { name: "Fin" })).toHaveValue("11:00");
await addTool(page, "Calendrier");
const monthly = moduleByType(page, "calendar").last();
await monthly.getByRole("button", { name: "Mensuel" }).click();
await monthly.getByRole("button", { name: /Afficher l'ajout de Calendrier/ }).click();
const days = monthly.locator(".calendar-month-cell:not(.is-outside)");
await days.nth(4).dispatchEvent("pointerdown", { buttons: 1 });
await days.nth(2).dispatchEvent("pointerover", { buttons: 1 });
await expect(monthly.locator(".calendar-month-cell.is-selected")).toHaveCount(3);
await days.nth(2).dispatchEvent("pointerup", { buttons: 0 });
await expect(monthly.locator(".calendar-event-form")).toBeVisible();
await expect(monthly.locator(".calendar-month-cell.is-form-selected")).toHaveCount(3);
});
test("creates a goal tree checklist with more than three visible lines", async ({ page }) => {
await createToolbox(page, "Goal Tree E2E Toolbox");
await addTool(page, "Arbre d'objectifs");
const goalTree = page.locator("[data-module-type='goalTree']");
await expect(goalTree).toBeVisible();
await goalTree.getByRole("button", { name: /Afficher l'ajout de Arbre d'objectifs/ }).click();
await goalTree.getByRole("button", { name: "Ajouter un objectif a la racine" }).click();
const editor = goalTree.getByRole("region", { name: "Édition de l'arbre d'objectifs" });
await expect(editor).toBeVisible();
await editor.getByLabel("Titre de l'objectif").fill("Farm E2E");
await editor.getByLabel("Type de l'objectif").selectOption("checklist");
await editor.getByRole("tab", { name: "Contenu" }).click();
for (const index of [1, 2, 3, 4, 5]) {
await editor.getByRole("button", { name: "Ajouter une ligne" }).click();
await editor.getByLabel("Libellé").nth(index - 1).fill(`Objectif ligne ${index}`);
}
const previewRows = goalTree.locator(".goal-tree-node-content-row");
await expect(previewRows).toHaveCount(5);
await expect(previewRows.filter({ hasText: "Objectif ligne 1" })).toBeVisible();
await expect(previewRows.filter({ hasText: "Objectif ligne 5" })).toBeVisible();
});
test("loads randomizer tabs after module split", async ({ page }) => {
await createToolbox(page, "Randomizer E2E Toolbox");
await addTool(page, "Randomizer");
const randomizer = moduleByType(page, "randomizer");
await expect(randomizer).toBeVisible();
await expect(randomizer.getByRole("tab", { name: "Dé" })).toBeVisible();
await expect(randomizer.getByRole("button", { name: "Lancer" })).toBeVisible();
await randomizer.getByRole("tab", { name: "Roue" }).click();
await expect(randomizer.getByLabel("Liste de valeurs")).toBeVisible();
await randomizer.getByLabel("Liste de valeurs").fill("Rouge\nBleu");
await randomizer.getByRole("button", { name: "Ajouter" }).click();
await expect(randomizer.locator(".randomizer-wheel-value-row .nds-input").first()).toHaveValue("Rouge");
await randomizer.getByRole("tab", { name: "Équipes" }).click();
await expect(randomizer.getByLabel("Liste de noms")).toBeVisible();
await expect(randomizer.getByRole("button", { name: "Créer les équipes" })).toBeVisible();
await randomizer.getByRole("combobox", { name: "Répartition", exact: true }).selectOption("count");
const count = randomizer.getByRole("spinbutton", { name: "Nombre", exact: true });
await count.fill("5");
await count.blur();
await expect(count).toHaveValue("5");
await randomizer.getByRole("spinbutton", { name: "Équipes", exact: true }).fill("6");
await expect(count).toHaveValue("6");
await count.fill("");
await count.blur();
await expect(count).toHaveValue("6");
await randomizer.getByRole("tab", { name: "Dé", exact: true }).click();
await randomizer.getByRole("tab", { name: "Équipes", exact: true }).click();
await expect(count).toHaveValue("6");
});
test("creates a game-linked toolbox from the drawer", async ({ page }) => {
await page.goto("/#/games/mhwilds");
await expect(page.getByRole("heading", { name: /Monster Hunter.*Wilds/ })).toBeVisible();
await page.getByRole("tab", { name: "Toolbox", exact: true }).click();
const drawer = page.locator("#toolbox-drawer .drawer-panel");
await expect(drawer).toBeVisible();
await drawer.getByRole("button", { name: "Créer et associer" }).click();
const dialog = page.getByRole("dialog", { name: "Créer et associer une toolbox" });
await expect(dialog.getByLabel("Nom")).toHaveValue(/Monster Hunter.*Wilds/);
await dialog.getByRole("button", { name: "Créer" }).click();
await expect(drawer.getByRole("heading", { name: /Monster Hunter.*Wilds/ })).toBeVisible();
await expect(drawer.locator("[data-module-type='memos']")).toBeVisible();
await expect(drawer.locator("[data-module-type='links']")).toBeVisible();
await expect(page.getByRole("tab", { name: "Toolbox", exact: true })).toHaveAttribute("aria-selected", "true");
});
test("links an available toolbox directly from the empty game drawer", async ({ page }) => {
await createToolbox(page, "Toolbox déjà liée");
await page.goto("/#/games/mhwilds");
await page.getByRole("tab", { name: "Toolbox", exact: true }).click();
const drawer = page.locator("#toolbox-drawer .drawer-panel");
await expect(drawer.getByRole("heading", { name: "Ou associer une toolbox déjà existante" })).toBeVisible();
await drawer.getByLabel("Toolbox disponible").selectOption({ label: "Toolbox déjà liée" });
await drawer.getByRole("button", { name: "Associer", exact: true }).click();
await expect(drawer.getByRole("heading", { name: "Toolbox déjà liée", exact: true })).toBeVisible();
await createToolbox(page, "Toolbox libre");
await page.goto("/#/games/diablo4");
await page.getByRole("tab", { name: "Toolbox", exact: true }).click();
await expect(drawer.getByLabel("Toolbox disponible").getByRole("option", { name: "Toolbox déjà liée" })).toHaveCount(0);
await drawer.getByLabel("Toolbox disponible").selectOption({ label: "Toolbox libre" });
await drawer.getByRole("button", { name: "Associer", exact: true }).click();
await expect(drawer.getByRole("heading", { name: "Toolbox libre", exact: true })).toBeVisible();
await expect(drawer.getByRole("heading", { name: "Ou associer une toolbox déjà existante" })).toHaveCount(0);
});
test("imports and exports a toolbox payload", async ({ page }) => {
await page.goto("/#/toolboxes");
await expect(page.getByRole("main")).toBeVisible();
await page.getByText("Importer une toolbox").locator("input[type='file']").setInputFiles(fixturePath);
const importedToolboxLink = page.getByRole("link", { name: "Ouvrir Fixture Toolbox" }).first();
await expect(importedToolboxLink).toBeVisible();
await importedToolboxLink.click();
await expect(page.getByRole("heading", { name: "Fixture Toolbox" })).toBeVisible();
const importedNotepad = page.locator("[data-module-type='notepad']");
await expect(importedNotepad).toBeVisible();
await expect(importedNotepad.getByRole("heading", { name: "Fixture Notes" })).toBeVisible();
await expect(importedNotepad.getByText("Imported fixture note")).toBeVisible();
await page.goto("/#/toolboxes");
const downloadPromise = page.waitForEvent("download");
await page.getByRole("button", { name: "Exporter Fixture Toolbox" }).click();
const download = await downloadPromise;
expect(download.suggestedFilename()).toBe("fixture-toolbox.sokkog.json");
});
test("opens the local automatic backup settings modal", async ({ page }) => {
await page.goto("/#/toolboxes");
await expect(page.getByRole("button", { name: "Sauvegarde automatique", exact: true })).toBeVisible();
await page.getByRole("button", { name: "Sauvegarde automatique", exact: true }).click();
const dialog = page.getByRole("dialog", { name: "Sauvegarde automatique" });
await expect(dialog).toBeVisible();
expect((await dialog.boundingBox()).width).toBeGreaterThan(700);
expect(await dialog.evaluate((element) => window.getComputedStyle(element).scrollbarColor)).toContain("88, 55, 174");
await expect(dialog.getByText("Cette fonctionnalité n’est pas disponible dans tous les navigateurs.")).toBeVisible();
await expect(dialog.getByText("Opera GX", { exact: true })).toBeVisible();
await expect(dialog.getByText("Comment fonctionne la sauvegarde", { exact: true })).toBeVisible();
await expect(dialog.getByText("la popup système ne peut apparaître qu’après un clic de votre part.")).toBeVisible();
await expect(dialog.getByText("10 versions sont conservées.", { exact: true })).toBeVisible();
await expect(dialog.getByText("Dossier configuré :", { exact: true })).toBeVisible();
await expect(dialog.getByText("Aucun dossier", { exact: true })).toBeVisible();
await expect(dialog.getByRole("checkbox")).toBeVisible();
await dialog.getByRole("button", { name: "Fermer", exact: true }).last().click();
await expect(dialog).toHaveCount(0);
});
test("offers an actionable backup alert without requesting permission at startup", async ({ page }) => {
await page.evaluate(async () => {
const db = await import("/src/utils/indexedDbStorage.js");
const directoryHandle = await navigator.storage.getDirectory();
await db.setSetting("autoBackup", {
enabled: true,
directoryHandle,
lastBackup: "",
lastBackupSignature: "",
hasUnsavedChanges: false
});
});
await page.addInitScript(() => {
window.backupPermissionRequests = 0;
window.backupPermissionGranted = false;
window.backupReminderVisibleAtPermissionRequest = true;
Object.defineProperty(FileSystemDirectoryHandle.prototype, "queryPermission", {
configurable: true,
value: async () => window.backupPermissionGranted ? "granted" : "prompt"
});
Object.defineProperty(FileSystemDirectoryHandle.prototype, "requestPermission", {
configurable: true,
value: async () => {
window.backupPermissionRequests += 1;
window.backupReminderVisibleAtPermissionRequest = document.body.textContent.includes("Des modifications ont été détectées dans vos toolboxes.");
window.backupPermissionGranted = true;
return "granted";
}
});
});
await page.reload();
await page.goto("/#/toolboxes");
await expect(page.getByText("Des modifications ont été détectées dans vos toolboxes.")).toHaveCount(0);
await createToolbox(page, "Toolbox à sauvegarder");
const reminder = page.getByRole("status").filter({ hasText: "Des modifications ont été détectées dans vos toolboxes." });
await expect(reminder).toBeVisible();
await expect(page.getByRole("dialog", { name: "Sauvegarde automatique" })).toHaveCount(0);
expect(await page.evaluate(() => window.backupPermissionRequests)).toBe(0);
await reminder.getByRole("button", { name: "Sauvegarder", exact: true }).click();
await expect(reminder).toHaveCount(0);
expect(await page.evaluate(() => window.backupPermissionRequests)).toBe(1);
expect(await page.evaluate(() => window.backupReminderVisibleAtPermissionRequest)).toBe(false);
await expect.poll(async () => page.evaluate(async () => {
const db = await import("/src/utils/indexedDbStorage.js");
return (await db.getSetting("autoBackup", {})).hasUnsavedChanges;
})).toBe(false);
});
test("backs up silently when folder access is still granted", async ({ page }) => {
await page.evaluate(async () => {
const db = await import("/src/utils/indexedDbStorage.js");
const directoryHandle = await navigator.storage.getDirectory();
for await (const [name, handle] of directoryHandle.entries()) {
if (handle.kind === "file" && /^sokkog-global-\d{4}-\d{2}-\d{2}\.json$/.test(name)) await directoryHandle.removeEntry(name);
}
await db.setSetting("autoBackup", {
enabled: true,
directoryHandle,
lastBackup: "",
lastBackupSignature: "",
hasUnsavedChanges: false
});
});
await page.addInitScript(() => {
window.backupPermissionRequests = 0;
Object.defineProperty(FileSystemDirectoryHandle.prototype, "queryPermission", {
configurable: true,
value: async () => "granted"
});
Object.defineProperty(FileSystemDirectoryHandle.prototype, "requestPermission", {
configurable: true,
value: async () => {
window.backupPermissionRequests += 1;
return "granted";
}
});
});
await page.reload();
await expect.poll(async () => page.evaluate(async () => {
const directoryHandle = await navigator.storage.getDirectory();
for await (const [name, handle] of directoryHandle.entries()) {
if (handle.kind === "file" && /^sokkog-global-\d{4}-\d{2}-\d{2}\.json$/.test(name)) return true;
}
return false;
})).toBe(true);
await expect(page.getByText("Des modifications ont été détectées dans vos toolboxes.")).toHaveCount(0);
expect(await page.evaluate(() => window.backupPermissionRequests)).toBe(0);
});
test("edits a table with formulas and persists values", async ({ page }) => {
await createToolbox(page, "Table E2E Toolbox");
await addTool(page, "Tableau");
const table = moduleByType(page, "table");
await expect(table).toBeVisible();
await table.getByRole("button", { name: "Ajouter une ligne" }).click();
await table.getByRole("button", { name: "Ajouter une colonne" }).click();
await tableCell(table, "A1").dblclick();
await tableCell(table, "A1").fill("12");
await tableCell(table, "B1").dblclick();
await tableCell(table, "B1").fill("3");
await tableCell(table, "C1").dblclick();
await tableCell(table, "C1").fill("=A1*B1");
await tableCell(table, "C1").press("Enter");
await expect(tableCell(table, "C1")).toHaveValue("36");
await page.reload();
await expect(tableCell(moduleByType(page, "table"), "A1")).toHaveValue("12");
await expect(tableCell(moduleByType(page, "table"), "C1")).toHaveValue("36");
});
test("creates edits and deletes a combo", async ({ page }) => {
await createToolbox(page, "Combos E2E Toolbox");
await addTool(page, "Combos");
const combos = moduleByType(page, "combos");
await expect(combos).toBeVisible();
await combos.getByRole("button", { name: /Afficher l'ajout de Combos/ }).click();
await combos.getByPlaceholder("Nom du combo").fill("Combo E2E");
await combos.getByRole("button", { name: "←" }).click();
await combos.getByRole("button", { name: "□" }).click();
await combos.getByRole("button", { name: "Ajouter le combo" }).click();
await expect(combos.locator(".combo-card .combo-input-token")).toHaveCount(2);
await combos.getByRole("button", { name: "Modifier le combo Combo E2E" }).click();
await combos.getByPlaceholder("Nom du combo").fill("Combo E2E modifié");
await combos.getByRole("button", { name: "Enregistrer" }).click();
await expect(combos.getByRole("button", { name: "Modifier le combo Combo E2E modifié" })).toBeVisible();
await combos.getByRole("button", { name: "Supprimer le combo Combo E2E modifié" }).click();
await expect(combos.getByRole("button", { name: "Modifier le combo Combo E2E modifié" })).toHaveCount(0);
});
test("creates edits summarizes and deletes equipment", async ({ page }) => {
await createToolbox(page, "Equipment E2E Toolbox");
await addTool(page, "Planificateur d'équipements");
const equipmentPlanner = moduleByType(page, "equipmentPlanner");
await expect(equipmentPlanner).toBeVisible();
await equipmentPlanner.getByRole("button", { name: /Afficher l'ajout de Planificateur d'équipements/ }).click();
await equipmentPlanner.getByPlaceholder("Nouvel équipement").fill("Épée E2E");
await equipmentPlanner.getByRole("button", { name: "Ajouter" }).click();
await expect(equipmentPlanner.getByText("Épée E2E")).toBeVisible();
await expect(equipmentPlanner.getByText("1 équipement actif")).toBeVisible();
await equipmentPlanner.locator(".equipment-planner-row-edit-button").click();
await equipmentPlanner.getByPlaceholder("Catégorie").fill("Stats");
await equipmentPlanner.getByPlaceholder("Nom").fill("Attaque");
await equipmentPlanner.getByPlaceholder("Valeur").fill("12");
await equipmentPlanner.locator(".equipment-planner-trait-form").getByRole("button", { name: "Ajouter" }).click();
await expect(equipmentPlanner.getByText("Attaque").first()).toBeVisible();
await expect(equipmentPlanner.getByText("12").first()).toBeVisible();
await page.reload();
const persistedPlanner = moduleByType(page, "equipmentPlanner");
await expect(persistedPlanner.getByText("Épée E2E")).toBeVisible();
await expect(persistedPlanner.getByText("Attaque").first()).toBeVisible();
await persistedPlanner.getByRole("button", { name: "Supprimer Épée E2E" }).click();
await expect(persistedPlanner.getByText("Épée E2E")).toHaveCount(0);
});
test("edits rich notepad content and persists it", async ({ page }) => {
await createToolbox(page, "Notepad E2E Toolbox");
await addTool(page, "Bloc Note");
const notepad = moduleByType(page, "notepad");
await expect(notepad).toBeVisible();
const editor = notepad.getByRole("textbox");
await editor.click();
await page.keyboard.press("Control+A");
await page.keyboard.press("Backspace");
await notepad.locator(".notepad-toolbar-button[title='Titre']").click();
await page.keyboard.type("Note E2E importante");
await expect(editor).toContainText("Note E2E importante");
await expect(notepad.getByRole("heading", { name: "Note E2E importante" })).toBeVisible();
await page.waitForTimeout(500);
await page.reload();
const persistedEditor = moduleByType(page, "notepad").getByRole("textbox");
await expect(persistedEditor).toContainText("Note E2E importante");
await expect(moduleByType(page, "notepad").getByRole("heading", { name: "Note E2E importante" })).toBeVisible();
});
test("creates resets and deletes a countdown timer", async ({ page }) => {
await createToolbox(page, "Timer E2E Toolbox");
await addTool(page, "Timer");
const timer = moduleByType(page, "timer");
await expect(timer).toBeVisible();
await timer.getByRole("tab", { name: "Compte à rebours" }).click();
await timer.getByLabel("Libellé").fill("Boss E2E");
const durationParts = timer.getByRole("group", { name: "Format heure minute seconde" }).first().locator("input");
await durationParts.nth(1).fill("01");
await timer.getByRole("button", { name: "Ajouter" }).click();
const countdown = timer.locator(".timer-list-item").filter({ hasText: "Boss E2E" });
await expect(countdown).toBeVisible();
await countdown.locator(".timer-inline-reset").click();
await expect(countdown).toBeVisible();
await countdown.getByRole("button", { name: "Supprimer" }).click();
await expect(countdown).toHaveCount(0);
});