Locks the five flows the refactor must not break (feed, channel, player, settings, nav) so later sprints can prove they changed nothing. Adds a thin data-testid layer and a dedicated seeded non-demo account; the suite runs on the baked :8080 stack (authoritative) or :5173. No product-behaviour change.
63 lines
2.6 KiB
TypeScript
63 lines
2.6 KiB
TypeScript
import { test, expect } from "@playwright/test";
|
|
import { openApp, gotoPage } from "./helpers";
|
|
|
|
// Locks the Settings draft/dirty-save machine: an edit raises the save bar, Save persists via
|
|
// PUT /me/preferences, and leaving with unsaved changes is guarded. The dirty-guard is one of
|
|
// the behaviors the god-component refactor must preserve exactly.
|
|
test.describe("settings dirty-save", () => {
|
|
const TOGGLE = "Performance mode"; // an Appearance switch (locale pinned to en)
|
|
|
|
async function putPrefs(page: import("@playwright/test").Page) {
|
|
return page.waitForResponse(
|
|
(r) => r.url().includes("/me/preferences") && r.request().method() === "PUT",
|
|
);
|
|
}
|
|
|
|
test("edit raises the bar and Save persists via PUT /me/preferences", async ({ page }) => {
|
|
await openApp(page);
|
|
await gotoPage(page, "settings");
|
|
|
|
const bar = page.getByTestId("draft-save-bar");
|
|
const status = page.getByTestId("draft-save-status");
|
|
const toggle = page.getByRole("switch", { name: TOGGLE });
|
|
|
|
// Clean: the bar renders nothing.
|
|
await expect(bar).toHaveCount(0);
|
|
|
|
// Edit → the bar appears.
|
|
await toggle.click();
|
|
await expect(bar).toBeVisible();
|
|
|
|
// Save → the PUT fires and the status flips to "saved".
|
|
const [saved] = await Promise.all([putPrefs(page), page.getByTestId("draft-save").click()]);
|
|
expect(saved.ok()).toBeTruthy();
|
|
await expect(status).toHaveAttribute("data-state", "saved");
|
|
|
|
// Restore the baseline (toggle back and save) so the shared account stays clean. Assert the
|
|
// restore's own PUT (not the lingering "saved" from the first save, which shows for 2.5s).
|
|
await toggle.click();
|
|
const [restored] = await Promise.all([putPrefs(page), page.getByTestId("draft-save").click()]);
|
|
expect(restored.ok()).toBeTruthy();
|
|
});
|
|
|
|
test("leaving with unsaved changes is guarded", async ({ page }) => {
|
|
await openApp(page);
|
|
await gotoPage(page, "settings");
|
|
|
|
await page.getByRole("switch", { name: TOGGLE }).click();
|
|
await expect(page.getByTestId("draft-save-bar")).toBeVisible();
|
|
|
|
// Navigating away raises the confirm guard instead of leaving.
|
|
await page.getByTestId("nav-feed").click();
|
|
await expect(page.getByText("You have unsaved settings")).toBeVisible();
|
|
|
|
// Cancel → stay on Settings, still dirty.
|
|
await page.getByRole("button", { name: "Cancel" }).click();
|
|
await expect(page.getByTestId("draft-save-bar")).toBeVisible();
|
|
|
|
// Discard → clean, so the account is left at baseline.
|
|
await page.getByTestId("draft-discard").click();
|
|
await expect(page.getByTestId("draft-save-bar")).toHaveCount(0);
|
|
});
|
|
});
|