Move the e2e suites into the repo (tests/), out of /tmp
The browser harness lived in /tmp/opencode and an overnight reboot wiped it. It now lives in tests/ and survives reboots, is versioned and runs with one command. - tests/lib.mjs: shared helpers (Chromium auto-detect, seeding, IndexedDB fixtures, stub/extra instance spawn with process-group cleanup, check/finish). - tests/run-all.mjs + npm run test:e2e [filter]: runs the ten suites in order with a summary; suites that need a stub Ollama or VAPID keys start their own next start instance on 3208/3209, verify the port is free and kill the group on exit. Test scratch in tests/.tmp/ (gitignored). - Suites rebuilt and green against the current build: regression 38, mobile 94 (tab matrix, ... sheet, settings sheet, axe), wizard 83, native 31 (PWA/offline/share/back/undo/haptics/draft), i18n 13, freeze-loading 6, review 15, phase1 36 (backup/sync/usage limits), phase2 42 (learning engine/reminders), phase3 21 (homework check). 379 checks, 10/10 suites in one full run. - playwright-core + axe-core added as devDependencies; CHROME env or the newest ~/.cache/ms-playwright chromium is used. - README: new decision 45 documenting the harness; decision 44's verification note updated. The older suites' exact sources were lost with the wipe, so the rebuilt versions reconstruct the same feature areas rather than being byte-identical.
This commit is contained in:
parent
2103f9fc69
commit
dbd5dfbc58
17 changed files with 2280 additions and 8 deletions
45
tests/freeze-loading-test.mjs
Normal file
45
tests/freeze-loading-test.mjs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* Freeze loading screen: it must appear the moment generation starts, keep
|
||||
* the wizard's action bar out of the way, and Cancel must return to the
|
||||
* wizard with the cancelled notice (not a stuck spinner).
|
||||
*/
|
||||
import { BASE, launchBrowser, makeChecker, makePage, seed } from "./lib.mjs";
|
||||
|
||||
const { check, finish } = makeChecker();
|
||||
const browser = await launchBrowser();
|
||||
const { context, page } = await makePage(browser);
|
||||
await seed(page, { decks: [] });
|
||||
|
||||
// Hold the generation so the loading screen stays up.
|
||||
await page.route("**/api/generate", () => new Promise(() => {}));
|
||||
await page.goto(`${BASE}/create`, { waitUntil: "networkidle" });
|
||||
await page.waitForTimeout(800);
|
||||
await page.getByRole("button", { name: "Paste text instead" }).click();
|
||||
await page.locator("textarea").first().fill("Photosynthesis needs light and water.");
|
||||
await page.getByRole("button", { name: "Next" }).click();
|
||||
await page.waitForTimeout(300);
|
||||
await page.getByRole("button", { name: "Next" }).click();
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
const tClick = Date.now();
|
||||
await page.getByRole("button", { name: "Freeze my deck" }).click();
|
||||
let appeared = true;
|
||||
await page
|
||||
.locator('img[src="/icons/icon-512.png"]')
|
||||
.waitFor({ state: "visible", timeout: 2000 })
|
||||
.catch(() => {
|
||||
appeared = false;
|
||||
});
|
||||
check("loading screen appears immediately after Freeze", appeared, `${Date.now() - tClick} ms`);
|
||||
check("stage message visible", await page.getByText(/Reading your notes|Finding the key ideas/).first().isVisible().catch(() => false));
|
||||
check("cancel available", await page.getByRole("button", { name: "Cancel" }).isVisible().catch(() => false));
|
||||
check("wizard bar is gone", (await page.locator("[data-wizard-bar]").count()) === 0);
|
||||
|
||||
await page.getByRole("button", { name: "Cancel" }).click();
|
||||
await page.waitForTimeout(700);
|
||||
check("cancel returns to the wizard", (await page.locator("[data-wizard-bar]").count()) === 1);
|
||||
check("cancel shows the notice + retry", await page.getByRole("button", { name: "Retry" }).isVisible());
|
||||
|
||||
await context.close();
|
||||
await browser.close();
|
||||
finish();
|
||||
Loading…
Add table
Add a link
Reference in a new issue