// Rôle : vérifie les dimensions, sélections et échanges de cellules du tableau réel. 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: "table.json", mimeType: "application/json", buffer: Buffer.from(JSON.stringify({ toolbox: { id: "table-fixture", name: "Table workflows", modules: [{ id: "grid", type: "table", title: "Tableau" }] }, modules: { grid: { rows: 3, columns: 3, cells: { A1: "2", B1: "3", C1: "=A1+B1", A2: "4", B2: "6", C3: "removed" } } }, })), }); await page.getByRole("link", { name: "Ouvrir Table workflows", exact: true }).first().click(); const table = page.locator('[data-module-type="table"]'); await expect(table.getByRole("grid", { name: "Tableau", exact: true })).toBeVisible(); return table; } function cell(table, address) { return table.getByRole("textbox", { name: `Cellule ${address}`, exact: true }); } async function drag(page, from, to) { await from.hover(); await page.mouse.down(); await to.hover(); await page.mouse.up(); } test("headers retain cell references and resizing removes only out-of-bounds data", async ({ page }) => { const table = await setup(page); const column = table.getByRole("textbox", { name: "Intitulé de colonne A", exact: true }); const row = table.getByRole("textbox", { name: "Intitulé de ligne 1", exact: true }); await column.click(); await expect.poll(() => column.evaluate((input) => [input.selectionStart, input.selectionEnd])).toEqual([0, 1]); await column.fill("Quantity"); await column.press("Enter"); await row.fill("Materials"); await row.press("Enter"); await column.fill("Cancelled"); await column.press("Escape"); await expect(column).toHaveValue("Quantity"); await expect(cell(table, "C1")).toHaveValue("5"); await page.reload(); await expect(column).toHaveValue("Quantity"); await expect(row).toHaveValue("Materials"); await table.getByRole("button", { name: "Supprimer la dernière ligne", exact: true }).click(); await table.getByRole("button", { name: "Supprimer la dernière colonne", exact: true }).click(); await expect(table.getByRole("textbox", { name: /^Cellule / })).toHaveCount(4); await table.getByRole("button", { name: "Ajouter une ligne", exact: true }).click(); await table.getByRole("button", { name: "Ajouter une colonne", exact: true }).click(); await expect(cell(table, "C1")).toHaveValue(""); await expect(cell(table, "C3")).toHaveValue(""); await expect(cell(table, "A1")).toHaveValue("2"); for (let index = 0; index < 2; index += 1) { await table.getByRole("button", { name: "Supprimer la dernière ligne", exact: true }).click(); await table.getByRole("button", { name: "Supprimer la dernière colonne", exact: true }).click(); } await expect(table.getByRole("button", { name: "Supprimer la dernière ligne", exact: true })).toBeDisabled(); await expect(table.getByRole("button", { name: "Supprimer la dernière colonne", exact: true })).toBeDisabled(); await page.reload(); await expect(table.getByRole("textbox", { name: /^Cellule / })).toHaveCount(1); await expect(cell(table, "A1")).toHaveValue("2"); await expect(column).toHaveValue("Quantity"); }); test("keyboard selection copies evaluated TSV, pastes blocks and clears only selected cells", async ({ page, context }) => { await context.grantPermissions(["clipboard-read", "clipboard-write"]); const table = await setup(page); await cell(table, "A1").click(); await cell(table, "A1").press("ArrowRight"); await expect(cell(table, "B1")).toBeFocused(); await cell(table, "B1").press("ArrowDown"); await expect(cell(table, "B2")).toBeFocused(); await cell(table, "B2").press("ArrowLeft"); await expect(cell(table, "A2")).toBeFocused(); await cell(table, "A2").press("ArrowUp"); await expect(cell(table, "A1")).toBeFocused(); await cell(table, "A1").press("Shift+ArrowRight"); await cell(table, "B1").press("Shift+ArrowRight"); await cell(table, "C1").press("ControlOrMeta+c"); await expect.poll(() => page.evaluate(() => globalThis.navigator.clipboard.readText())).toBe("2\t3\t5"); await cell(table, "A3").click(); await cell(table, "A3").press("ControlOrMeta+v"); await expect(cell(table, "A3")).toHaveValue("2"); await expect(cell(table, "B3")).toHaveValue("3"); await expect(cell(table, "C3")).toHaveValue("5"); await cell(table, "A3").press("Delete"); await expect(cell(table, "A3")).toHaveValue(""); await expect(cell(table, "B3")).toHaveValue(""); await expect(cell(table, "C3")).toHaveValue(""); await cell(table, "A1").click(); await table.getByRole("button", { name: "Copier les valeurs", exact: true }).click(); await expect.poll(() => page.evaluate(() => globalThis.navigator.clipboard.readText())).toBe("2\t3\t5\n4\t6\t\n\t\t"); await page.reload(); await expect(cell(table, "C1")).toHaveValue("5"); await expect(cell(table, "C3")).toHaveValue(""); }); test("pointer selections move blocks and insert ranges into formulas without changing source values", async ({ page }) => { const table = await setup(page); await drag(page, cell(table, "A2"), cell(table, "B2")); await expect(table.locator(".table-cell-input.is-selected")).toHaveCount(2); await drag(page, cell(table, "A2"), cell(table, "A3")); await expect(cell(table, "A2")).toHaveValue(""); await expect(cell(table, "B2")).toHaveValue(""); await expect(cell(table, "A3")).toHaveValue("4"); await expect(cell(table, "B3")).toHaveValue("6"); await cell(table, "C2").dblclick(); await cell(table, "C2").fill("="); await drag(page, cell(table, "A1"), cell(table, "B1")); await expect(cell(table, "C2")).toHaveValue("=(A1+B1)"); await cell(table, "C2").press("Enter"); await expect(cell(table, "C2")).toHaveValue("5"); await expect(cell(table, "A1")).toHaveValue("2"); await expect(cell(table, "B1")).toHaveValue("3"); await page.reload(); await expect(cell(table, "C2")).toHaveValue("5"); await expect(cell(table, "A2")).toHaveValue(""); await expect(cell(table, "A3")).toHaveValue("4"); await expect(cell(table, "B3")).toHaveValue("6"); });