sokko-g/e2e/text-exchange.spec.js
Shinuwa 0acf5ecf21
All checks were successful
Deploy Sokko G / deploy (push) Successful in 18s
Add toolbox spaces and recover from stale asset bundles
2026-09-29 21:31:49 +02:00

106 lines
6.9 KiB
JavaScript

// Rôle : vérifie les modales d'échange texte, les erreurs et la persistance des imports réels.
import { expect, test } from "@playwright/test";
import { Buffer } from "node:buffer";
async function setup(page) {
await page.goto("/#/toolboxes");
await page.getByText("Importer une toolbox", { exact: true }).locator('input[type="file"]').setInputFiles({
name: "exchange.json", mimeType: "application/json",
buffer: Buffer.from(JSON.stringify({
toolbox: { id: "exchange", name: "Text exchange", modules: [
{ id: "table", type: "table", title: "Tableau" },
{ id: "calc", type: "calculator", title: "Calculateur" },
] },
modules: { table: { rows: 2, columns: 2, cells: {} }, calc: { entries: [{ id: "original", label: "Original", value: 7, formula: "7" }] } },
})),
});
await page.getByRole("link", { name: "Ouvrir Text exchange", exact: true }).first().click();
}
test("table text import/export preserves formulas and labels, copies read-only text and resets cancelled drafts", async ({ page, context }) => {
await context.grantPermissions(["clipboard-read", "clipboard-write"]);
await setup(page);
const table = page.locator('[data-module-type="table"]');
const importButton = table.getByRole("button", { name: "Importer TSV", exact: true });
await expect(importButton).toBeHidden();
await table.getByRole("button", { name: "Afficher l'import/export de Tableau", exact: true }).click();
await expect(table.getByRole("button", { name: "Exporter TSV", exact: true })).toBeDisabled();
const originalOverflow = await page.locator("body").evaluate((body) => body.style.overflow);
await importButton.click();
const dialog = page.getByRole("dialog", { name: "Importer un tableau TSV", exact: true });
await expect(dialog.getByRole("textbox")).toBeFocused();
await expect(page.locator("body")).toHaveCSS("overflow", "hidden");
await dialog.getByRole("textbox").fill("cancelled");
await dialog.getByRole("button", { name: "Annuler", exact: true }).click();
await expect.poll(() => page.locator("body").evaluate((body) => body.style.overflow)).toBe(originalOverflow);
await importButton.click();
await expect(dialog.getByRole("textbox")).toHaveValue("");
await dialog.getByRole("button", { name: "Importer le TSV", exact: true }).click();
await expect(dialog.getByRole("alert")).toContainText("Le texte à importer est vide.");
await expect(dialog.getByRole("textbox")).toHaveAttribute("aria-invalid", "true");
const text = "@size: 2x2\n@columns: Quantity\tTotal\n@rows: Ore\tBars\n@tsv\n3\t=A1*2\n5\t=A2*2";
await dialog.getByRole("textbox").fill(text);
await expect(dialog.getByRole("alert")).toHaveCount(0);
await expect(dialog.getByRole("textbox")).toHaveAttribute("aria-invalid", "false");
await dialog.getByRole("button", { name: "Importer le TSV", exact: true }).click();
await expect(dialog).toBeHidden();
await expect(table.getByRole("textbox", { name: "Cellule B2", exact: true })).toHaveValue("10");
await page.reload();
await expect(table.getByRole("textbox", { name: "Intitulé de colonne A", exact: true })).toHaveValue("Quantity");
await expect(table.getByRole("textbox", { name: "Intitulé de ligne 1", exact: true })).toHaveValue("Ore");
await expect(table.getByRole("textbox", { name: "Cellule B1", exact: true })).toHaveValue("6");
await table.getByRole("button", { name: "Afficher l'import/export de Tableau", exact: true }).click();
await table.getByRole("button", { name: "Exporter TSV", exact: true }).click();
const exported = page.getByRole("dialog", { name: "Exporter un tableau TSV", exact: true });
await expect(exported.getByRole("textbox")).toHaveAttribute("readonly", "");
await expect(exported.getByRole("textbox")).toHaveValue(text);
await exported.getByRole("button", { name: "Copier le TSV", exact: true }).click();
await expect.poll(() => page.evaluate(() => globalThis.navigator.clipboard.readText())).toBe(text);
await expect(exported).toBeVisible();
await exported.getByRole("textbox").press("Escape");
await expect(exported).toBeHidden();
await expect.poll(() => page.locator("body").evaluate((body) => body.style.overflow)).toBe(originalOverflow);
await table.getByRole("button", { name: "Masquer l'import/export de Tableau", exact: true }).click();
await expect(importButton).toBeHidden();
});
test("invalid calculator imports preserve existing results and a corrected import replaces them with a persistent hierarchy", async ({ page }) => {
await setup(page);
const calc = page.locator('[data-module-type="calculator"]');
await calc.getByRole("button", { name: "Afficher l'import/export de Calculateur", exact: true }).click();
const openImport = calc.getByRole("button", { name: "Importer du texte", exact: true });
await openImport.click();
const dialog = page.getByRole("dialog", { name: "Importer des résultats", exact: true });
await dialog.getByRole("textbox").fill("invalid");
await dialog.getByRole("button", { name: "Importer le texte", exact: true }).click();
await expect(dialog.getByRole("alert")).toContainText("ligne calculateur invalide");
await expect(calc.locator(".calculator-entry em")).toHaveText(["Original"]);
await dialog.getByRole("button", { name: "Fermer", exact: true }).click();
await page.reload();
await expect(calc.locator(".calculator-entry em")).toHaveText(["Original"]);
await calc.getByRole("button", { name: "Afficher l'import/export de Calculateur", exact: true }).click();
await openImport.click();
await expect(dialog.getByRole("textbox")).toHaveValue("");
await expect(dialog.getByRole("alert")).toHaveCount(0);
const text = "@scrollResults: true\nOre: 10 | formula=10\n Bars: 20 | formula=base*2";
await dialog.getByRole("textbox").fill(text);
await page.evaluate(() => {
globalThis.__sokkogModuleWriteComplete = false;
globalThis.addEventListener("sokkog:auto-backup-data-changed", () => {
globalThis.__sokkogModuleWriteComplete = true;
}, { once: true });
});
await dialog.getByRole("button", { name: "Importer le texte", exact: true }).click();
await expect(dialog).toBeHidden();
await expect(calc.locator(".calculator-entry em")).toHaveText(["Ore", "Bars"]);
await expect.poll(() => page.evaluate(() => globalThis.__sokkogModuleWriteComplete)).toBe(true);
await page.reload();
await expect(calc.locator(".calculator-entry em")).toHaveText(["Ore", "Bars"]);
await expect(calc.getByRole("button", { name: "Liste scrollable", exact: true })).toHaveAttribute("aria-pressed", "true");
await calc.getByRole("button", { name: "Afficher l'import/export de Calculateur", exact: true }).click();
await calc.getByRole("button", { name: "Exporter en format texte", exact: true }).click();
const exported = page.getByRole("dialog", { name: "Exporter des résultats", exact: true });
await expect(exported.getByRole("textbox")).toHaveValue(text);
await page.locator(".text-import-modal-root .confirm-backdrop").click({ position: { x: 10, y: 10 } });
await expect(exported).toBeHidden();
});