diff --git a/end2end/tests/persistence.spec.ts b/end2end/tests/persistence.spec.ts new file mode 100644 index 0000000..d8814c5 --- /dev/null +++ b/end2end/tests/persistence.spec.ts @@ -0,0 +1,74 @@ +import { test, expect, type Page } from "@playwright/test"; +import * as fs from "node:fs"; + + +// Override with BASE_URL (e.g. when the dev server runs on another port). +const BASE = process.env.BASE_URL ?? "http://localhost:3000"; + +// Collects browser console errors and page errors for the duration of a test. +function trackErrors(page: Page): string[] { + const errors: string[] = []; + page.on("console", (msg) => { + if (msg.type() === "error") { + errors.push(msg.text()); + } + }); + page.on("pageerror", (err) => { + errors.push(String(err)); + }); + return errors; +} + +// Autosave is debounced at 500 ms; give it time before reloading. +const DEBOUNCE_MS = 700; + +test("campaign name survives a reload", async ({ page }) => { + const errors = trackErrors(page); + await page.goto(`${BASE}/`); + + const name = "Кампания с сохранением"; + const input = page.locator("#campaign-name"); + await input.fill(name); + await page.waitForTimeout(DEBOUNCE_MS); + + await page.reload(); + await expect(input).toHaveValue(name); + + expect(errors).toEqual([]); +}); + +test("export/import round trip through the file", async ({ page }) => { + const errors = trackErrors(page); + await page.goto(`${BASE}/`); + + // Save: the header button downloads dashboard.json with the current state. + const name = "Кампания экспорта"; + await page.locator("#campaign-name").fill(name); + const [download] = await Promise.all([ + page.waitForEvent("download"), + page.getByRole("button", { name: "Сохранить" }).click(), + ]); + expect(download.suggestedFilename()).toBe("dashboard.json"); + + const filePath = await download.path(); + expect(filePath).not.toBeNull(); + const saved = JSON.parse(fs.readFileSync(filePath!, "utf8")); + expect(saved.campaign).toBe(name); + + // Clear: confirm the dialog, the dashboard goes blank. + await page.getByRole("button", { name: "Очистить" }).click(); + await page.locator(".modal").waitFor(); + await page.locator(".modal").getByRole("button", { name: "Очистить" }).click(); + await expect(page.locator(".modal")).toBeHidden(); + await expect(page.locator("#campaign-name")).toHaveValue(""); + + // Load: pick the file we just saved, the state comes back. + const [chooser] = await Promise.all([ + page.waitForEvent("filechooser"), + page.getByRole("button", { name: "Загрузить" }).click(), + ]); + await chooser.setFiles(filePath!); + await expect(page.locator("#campaign-name")).toHaveValue(name); + + expect(errors).toEqual([]); +}); diff --git a/end2end/tests/smoke.spec.ts b/end2end/tests/smoke.spec.ts index fe9bc20..29d2313 100644 --- a/end2end/tests/smoke.spec.ts +++ b/end2end/tests/smoke.spec.ts @@ -1,6 +1,7 @@ import { test, expect, type Page } from "@playwright/test"; -const BASE = "http://localhost:3000"; +// Override with BASE_URL (e.g. when the dev server runs on another port). +const BASE = process.env.BASE_URL ?? "http://localhost:3000"; // Collects browser console errors and page errors for the duration of a test. function trackErrors(page: Page): string[] {