Files
TX/artifacts/tx-os/tests/executive-meetings-edit-toggle.spec.mjs
T

149 lines
5.5 KiB
JavaScript
Raw Normal View History

import { test, expect } from "@playwright/test";
async function loginViaUi(page, username, password) {
await page.goto("/login");
await page.locator("#username").fill(username);
await page.locator("#password").fill(password);
await Promise.all([
page.waitForURL((url) => !url.pathname.endsWith("/login"), {
timeout: 15_000,
}),
page.locator('form button[type="submit"]').click(),
]);
}
test("Schedule: Edit toggle hides editing affordances by default and reveals them when on", async ({
page,
}) => {
await page.addInitScript(() => {
try {
window.localStorage.setItem("tx-lang", "en");
} catch {
/* localStorage may not be ready before navigation */
}
});
await loginViaUi(page, "admin", "admin123");
// Make sure we always start the test in view mode regardless of any
// previously-persisted toggle state from another run. We clear AFTER
// login so the cleanup isn't undone by the initScript on every nav.
await page.goto("/executive-meetings");
// The toggle's storage key is namespaced per-user
// (`em-schedule-edit-mode-v1:<userId>`), so we wipe every entry that
// starts with the base key to make sure we begin in view mode no
// matter who admin's userId resolves to in this run.
await page.evaluate(() => {
try {
const keys = Object.keys(window.localStorage);
for (const k of keys) {
if (k.startsWith("em-schedule-edit-mode-v1")) {
window.localStorage.removeItem(k);
}
}
} catch {
/* ignore */
}
});
await page.reload();
// Toggle is rendered (admin has edit permission), and starts in
// pressed=false / view mode.
const toggle = page.getByTestId("em-edit-mode-toggle");
await expect(toggle).toBeVisible();
await expect(toggle).toHaveAttribute("aria-pressed", "false");
// In view mode the row-level "Add meeting" button must be hidden.
await expect(page.getByTestId("em-add-row-button")).toHaveCount(0);
// And no row-level overlays (delete, color picker, merge trigger,
// grip handle) should exist anywhere in the table.
await expect(page.locator('[data-testid^="em-delete-row-"]')).toHaveCount(0);
await expect(page.getByTestId("em-row-color-trigger")).toHaveCount(0);
await expect(page.locator('[data-testid^="em-merge-trigger-"]')).toHaveCount(0);
await expect(page.locator('[data-testid^="em-row-grip-"]')).toHaveCount(0);
// Flip toggle on. aria-pressed becomes true and the affordances appear.
await toggle.click();
await expect(toggle).toHaveAttribute("aria-pressed", "true");
// The "+ Add meeting" row button is back.
await expect(page.getByTestId("em-add-row-button")).toBeVisible();
// Persist + survive a reload: the toggle should still be on.
await page.reload();
const toggleAfterReload = page.getByTestId("em-edit-mode-toggle");
await expect(toggleAfterReload).toHaveAttribute("aria-pressed", "true");
await expect(page.getByTestId("em-add-row-button")).toBeVisible();
// Toggle back off — affordances disappear again.
await toggleAfterReload.click();
await expect(toggleAfterReload).toHaveAttribute("aria-pressed", "false");
await expect(page.getByTestId("em-add-row-button")).toHaveCount(0);
});
test("Schedule: turning edit mode OFF cancels any open inline editor and discards the draft", async ({
page,
}) => {
await page.addInitScript(() => {
try {
window.localStorage.setItem("tx-lang", "en");
} catch {
/* ignore */
}
});
await loginViaUi(page, "admin", "admin123");
await page.goto("/executive-meetings");
// Start clean (view mode), then flip edit mode on.
await page.evaluate(() => {
try {
const keys = Object.keys(window.localStorage);
for (const k of keys) {
if (k.startsWith("em-schedule-edit-mode-v1")) {
window.localStorage.removeItem(k);
}
}
} catch {
/* ignore */
}
});
await page.reload();
const toggle = page.getByTestId("em-edit-mode-toggle");
await expect(toggle).toBeVisible();
await toggle.click();
await expect(toggle).toHaveAttribute("aria-pressed", "true");
// Make sure there's at least one row to edit. If the schedule is
// empty for today, add a row via the now-visible "+ Add meeting"
// button so the test has a stable target.
const addRow = page.getByTestId("em-add-row-button");
await expect(addRow).toBeVisible();
let titleCells = page.locator('[data-testid^="em-edit-title-"]');
if ((await titleCells.count()) === 0) {
await addRow.click();
await expect(titleCells.first()).toBeVisible({ timeout: 5_000 });
}
// Open the first inline title editor and type a draft we expect
// to be discarded.
const firstTitle = titleCells.first();
const originalText = (await firstTitle.innerText()).trim();
await firstTitle.click();
// The editor renders a contenteditable inside the cell. Type a
// unique draft so we can later assert it never landed.
const draft = "DRAFT-DO-NOT-PERSIST-" + Date.now();
await page.keyboard.type(draft);
// Now flip edit mode OFF while the editor is still open. The
// EditableCell `disabled` effect should exit edit mode and reset
// the displayed content back to its saved value.
await toggle.click();
await expect(toggle).toHaveAttribute("aria-pressed", "false");
// The displayed cell should NOT contain our draft text — i.e. the
// open editor was cancelled and the unsaved draft was discarded.
const afterText = (await firstTitle.innerText()).trim();
expect(afterText).not.toContain(draft);
expect(afterText).toBe(originalText);
});