e3823ce470
Add an end-to-end and unit test suite for the SvelteKit frontend:
- Playwright e2e specs (tests/e2e/spa) with a throwaway container stack,
codegen scenarios, and an Istanbul-based coverage report pipeline.
- Vitest unit tests across API endpoints, components, stores and composables.
- `data-testid` hooks on interactive elements (AppShell, FileViewer,
ShareDialog, search, photos, files breadcrumbs, login/Nextcloud flows,
public share pages) so the e2e suite can target them deterministically.
- Serve the SPA app-shell CSP from a <meta> policy (svelte.config.js) plus a
middleware that skips the CSP header on HTML; move the Nextcloud Login Flow
v2 grant page to the SvelteKit /nextcloud/login route.
- `just front-codegen` recipe and start-server-spa.sh harness.
Make the test environment robust and consistent:
- Install a deterministic in-memory localStorage/sessionStorage in the Vitest
setup so storage behaves identically across Node versions (Node 26 ships a
native Web Storage global that otherwise shadows jsdom's).
- Pin devenv to Node 26 + PostgreSQL 18 and pin every CI job to Node 26.3.0
so the dev shell and CI run the same toolchain versions.
Repair the API/WebDAV (hurl) suite, which had drifted from the backend:
- Migrate the removed `/api/folders/{id}/listing` endpoint to `/resources`
(cursor-paginated `{items:[{resource_type,resource}]}` shape) across the
batch-copy, grants, nested-group, and WebDAV NC tests + the dav_helpers
wipe routine.
- Stop photos_etag from uploading the dedup-tracked fixture so the dedup
blob-lifecycle test can own its content-addressed blob exclusively.
- dedup_create now asserts the idempotent same-content re-upload (201 +
existing file id) instead of the stale 409 expectation.
Generated coverage reports, nyc output and the e2e server runtime data dir
are gitignored rather than committed.
71 lines
2.8 KiB
Markdown
71 lines
2.8 KiB
Markdown
# Codegen recorder templates
|
|
|
|
Each file here is a **starting point** for `just front-codegen`. It boots an
|
|
isolated container stack, runs your setup, then opens the Playwright Inspector
|
|
so you record from a known state. The file name is what shows up in the menu —
|
|
drop a new `*.spec.ts` here and it appears automatically.
|
|
|
|
## Anatomy
|
|
|
|
```ts
|
|
import { test, apiLogin } from '../helpers';
|
|
|
|
test('codegen: <name>', async ({ page }) => {
|
|
test.setTimeout(0); // no timeout — recorder stays open until you close it
|
|
await apiLogin(page); // setup: get to the state you want to record from
|
|
await page.goto('/files');
|
|
await page.pause(); // MUST be last — opens the Inspector
|
|
});
|
|
```
|
|
|
|
Rules:
|
|
|
|
- Import `test` (and any helpers) from `../helpers` — **not** `@playwright/test`.
|
|
That wires in the container-stack fixture and the JS-error guard.
|
|
- Set `test.setTimeout(0)` so the recorder doesn't time out while you work.
|
|
- End with `await page.pause()`. Everything **before** it runs first, so put as
|
|
much setup as you like there (log in, open a folder, start an upload, …) and
|
|
you'll record the continuation from that state.
|
|
- Use the helpers for setup: `apiLogin(page)` signs in via the API (no UI
|
|
clicks, selector-independent). Skip it for an anonymous/login flow.
|
|
|
|
## What carries into the saved spec
|
|
|
|
When you save a recording, the setup lines (everything before `page.pause()`,
|
|
minus `test.setTimeout`) are copied into the generated `scenarios/<name>.spec.ts`,
|
|
then your recorded steps are spliced in. So a recorder's setup == the saved
|
|
test's setup — keep it to the state you want every recording from this template
|
|
to start in.
|
|
|
|
## Seeding content before you record
|
|
|
|
To record flows that need existing files/folders (move, copy, delete,
|
|
multi-select, previews, sorting by type), seed them via the API in the setup —
|
|
no UI clicks, just like `apiLogin`. The `authed-files` template does this:
|
|
|
|
```ts
|
|
import { test, apiLogin, seedFilesAndFolders } from '../helpers';
|
|
|
|
test('codegen: authed-files', async ({ page }) => {
|
|
test.setTimeout(0);
|
|
await apiLogin(page);
|
|
await seedFilesAndFolders(page); // Documents/, Documents/Reports/, Images/ + files of each type
|
|
await page.goto('/');
|
|
await page.pause();
|
|
});
|
|
```
|
|
|
|
`helpers.ts` exposes the building blocks: `apiCreateFolder`, `apiUploadFile`,
|
|
`SAMPLE_FILES` (text / markdown / JSON / CSV / PNG / PDF), and the
|
|
`seedFilesAndFolders` convenience that lays down a small mixed-type tree.
|
|
**Remember:** the saved spec inherits this setup, so the recorded selectors only
|
|
have content to act on if `seedFilesAndFolders(page)` runs there too — it does,
|
|
because the template's setup is copied into the saved test.
|
|
|
|
## Add one
|
|
|
|
```sh
|
|
cp authed.spec.ts my-start.spec.ts # edit the setup, keep page.pause() last
|
|
just front-codegen # "my-start" is now in the menu
|
|
```
|