dorfteich/apps/web/e2e
Claude Fable 5 58c19abfdd #169: Nicht-Text-Inhalte — Task-Checkboxen, Wissensgraph
Task-Checkboxen tragen in beiden Renderpfaden einen Namen: docToHtml
setzt aria-label aus dem Aufgabentext, die Editor-NodeView ebenso. Die
NodeView rendert ihr Host-Element jetzt selbst als li (ReactNodeView-
Renderer as/attrs) — TipTaps zusätzliches div-Host-Element zwischen ul
und li brach die Listensemantik; der Wrapper flacht per display:contents
ab, die #137-Pixel-Abstimmung bleibt erhalten (Selektor auf die neue
Tiefe nachgeführt, Ausrichtung nachgemessen: 1px-Versatz unverändert).
Der Wissensgraph-SVG bekommt ein beschreibendes aria-label inklusive
Verweis auf die Backlinks als gleichwertige Listenform. Der
Bild-Alt-Editor existierte bereits (Bild-Controls bei Auswahl) — kein
Änderungsbedarf. Hinweis: gecachte Seiten übernehmen das
Checkbox-Label wie bei jeder docToHtml-Änderung erst mit dem nächsten
Persist ihrer Inhalte.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AGM8jo3hwoV9wsCVGfy8iq
2026-07-21 14:35:16 +02:00
..
access-rules.spec.ts Add effective-permissions inspector (#57) 2026-07-10 00:00:27 +02:00
admin-quotas.spec.ts Add Site-Admin quota override management UI (#58) 2026-07-10 00:14:28 +02:00
admin-users.spec.ts Add Site-Admin user management (#59) 2026-07-10 00:31:41 +02:00
attachments.spec.ts Add non-image attachments with allowlist, SVG policy, and file managers (#61) 2026-07-10 02:52:40 +02:00
auth.spec.ts Bind the CI dev server to all interfaces and surface login errors 2026-07-05 06:07:49 +02:00
backlinks.spec.ts Add backlinks panel and phantom-pages view (#48) 2026-07-09 13:05:32 +02:00
collab-permissions.spec.ts Wire real permissions into collab tokens and revocation (#53) 2026-07-09 18:48:42 +02:00
collab.spec.ts Public REST API v1: personal access tokens, instance switch + per-pond opt-in (#104) 2026-07-12 11:17:03 +02:00
comments.spec.ts #133 Kommentare fest inline im Lesemodus (Slide-in-Panel ablösen) 2026-07-19 01:22:22 +02:00
content.spec.ts #169: Nicht-Text-Inhalte — Task-Checkboxen, Wissensgraph 2026-07-21 14:35:16 +02:00
create-missing-page.spec.ts Offer creating the page on the not-found screen (#115) 2026-07-14 16:45:27 +02:00
editor.spec.ts Modernize stale editor e2e pack to live-collab semantics 2026-07-09 17:01:41 +02:00
export.spec.ts Move page actions into the TopBar as self-hosted icon buttons (#101) 2026-07-12 04:39:42 +02:00
favorites.spec.ts Favorites: personal page stars, golden icons, sidebar filter (#132) 2026-07-16 12:03:55 +02:00
fonts.spec.ts Add per-pond fonts: catalog, build, application, and admin UI (#66) 2026-07-10 11:16:29 +02:00
graph.spec.ts Pond graph: size the canvas to the viewport, not the width ratio (#131) 2026-07-16 12:02:56 +02:00
helpers.ts Add auth e2e regression pack with fixtures and CI stack 2026-07-05 05:43:05 +02:00
image.spec.ts Add image paste and insert in the editor (#28) 2026-07-08 11:30:25 +02:00
import-vault.spec.ts Vault import: always show the label section, create labels inline 2026-07-15 10:58:50 +02:00
import.spec.ts Add document import UI in the sidebar (#64) 2026-07-10 09:38:31 +02:00
labels.spec.ts Add label UI: tree management, page assignment, and sidebar filter (#44) 2026-07-09 11:41:42 +02:00
legal.spec.ts Add instance legal pages with public rendering and footer links (#82) 2026-07-11 16:40:04 +02:00
link.spec.ts Add link UX: edit URL and open in new tab (#29) 2026-07-08 11:50:34 +02:00
markdown.spec.ts Move pond settings to a TopBar gear, pin the trash link to the sidebar bottom (M10 follow-up) 2026-07-12 06:07:15 +02:00
members.spec.ts Pond lifecycle in the UI: create shared ponds, delete from settings 2026-07-12 19:15:34 +02:00
mermaid.spec.ts Add the Mermaid reference plugin (#78) 2026-07-11 13:51:15 +02:00
offline.spec.ts Harden the offline e2e for slower CI timing (#38) 2026-07-08 22:24:29 +02:00
page-tools.spec.ts Add pageTool plugins with toc and page-index references (#77) 2026-07-11 13:27:30 +02:00
page-tree.spec.ts QA: page-tree and graph e2e packs in CI, manuals updated (#114) 2026-07-14 11:10:14 +02:00
permission-matrix.spec.ts Pin the comments/notifications semantics as a regression pack (#96) 2026-07-12 00:00:34 +02:00
plugin-admin.spec.ts Add plugin administration UI: instance modes and pond activation (#72) 2026-07-11 09:32:16 +02:00
plugin-blocks.spec.ts #160: Plugin-Block — Bearbeiten-Knopf nach Moduswechsel wieder da 2026-07-20 21:54:50 +02:00
plugin-fixtures.ts Add block plugins: plugin_block node with sandboxed rendering and editing (#76) 2026-07-11 12:45:14 +02:00
plugins.spec.ts Add the sandbox host runtime for plugin iframes (#73) 2026-07-11 09:16:30 +02:00
public.spec.ts Move live presence into the TopBar, signed-in only (#102) 2026-07-12 04:42:59 +02:00
README.md Add the sandbox host runtime for plugin iframes (#73) 2026-07-11 09:16:30 +02:00
reorder.spec.ts Add manual page ordering with drag-and-drop (#45) 2026-07-09 12:18:44 +02:00
search.spec.ts search.spec: Fehl-Klick entfernt — Reload IST der Weg zurück in den Lesemodus 2026-07-19 21:31:53 +02:00
section-styles.spec.ts e2e-Fixes nach CI: section-styles-Selektor eindeutig, settings-nav-Timing 2026-07-20 01:54:29 +02:00
settings-nav.spec.ts settings-nav robust: Sofort-Sprung statt Smooth-Scroll, Spec wartet auf networkidle 2026-07-20 02:11:35 +02:00
setup.spec.ts Add the first-run setup wizard UI (#81) 2026-07-11 16:05:01 +02:00
sidebar.spec.ts #169: Nicht-Text-Inhalte — Task-Checkboxen, Wissensgraph 2026-07-21 14:35:16 +02:00
smoke.spec.ts Add collaboration server skeleton (Hocuspocus) with health, container, and CI/CD (#33) 2026-07-08 14:53:44 +02:00
social.spec.ts Format the social pack (#96) 2026-07-12 00:02:12 +02:00
system.spec.ts Expect the notification-digest job in the system panel pack (#95) 2026-07-11 23:44:44 +02:00
tasks.spec.ts #154: Aufgabenübersicht als Kern-Block (Seite + Unterseiten) 2026-07-20 01:20:30 +02:00
trash.spec.ts Trash: checkbox multi-select with bulk restore and purge (#128) 2026-07-16 12:03:35 +02:00
wikilink.spec.ts Add wikilink node with autocomplete (#46) 2026-07-09 12:42:01 +02:00

End-to-end tests

Playwright suites, most local-only — three run in CI/CD:

Suite Target Where it runs
smoke.spec.ts any deployed stage CD pipeline against https://test.dorfteich.cloud after every deploy
auth.spec.ts full local stack with Mailpit CI job auth-e2e on every PR/push; locally against the dev stack
content.spec.ts full local stack same CI job auth-e2e (a second step), right after the auth pack
everything else full local stack locally only — editor/sidebar/image/link/markdown/trash.spec.ts

content.spec.ts is the M2 content regression pack (issue #32): page lifecycle, editor basics, image paste, Markdown round-trip, and trash — enough to catch a regression across the whole content model without re-running every edge case the feature-specific packs above already cover. Its Markdown round-trip test is a real regression pin, not just a smoke check: it compares the seeded "Every Element" fixture page's exported Markdown byte-for-byte against the checked-in content-page.md (see "Content fixtures" below) — any schema/serializer change that alters how a node round-trips fails it, once the seed has re-run against the changed code (build → migrate → seed → test, exactly CI's order).

Running locally

# 1. Stack: database + Mailpit, api (3001), web dev server (5173)
docker compose -f deploy/compose/docker-compose.yml -f deploy/compose/compose.dev.yml up -d db mailpit
DATABASE_URL=postgresql://dorfteich:dorfteich@localhost:5434/dorfteich pnpm --filter @dorfteich/api db:seed
DATABASE_URL=postgresql://dorfteich:dorfteich@localhost:5434/dorfteich PORT=3001 pnpm --filter @dorfteich/api start:dev &
pnpm --filter @dorfteich/web dev &

# 2. Tests
E2E_BASE_URL=http://localhost:5173 E2E_MAILPIT_URL=http://localhost:8025 pnpm --filter @dorfteich/web e2e

auth.spec.ts skips itself when E2E_MAILPIT_URL is unset, so the CD smoke run never trips over it.

Fixture matrix

Seeded by pnpm --filter @dorfteich/api db:seed (idempotent — re-running never duplicates). Shared password: fixture passwort 123. Fixtures exist only on dev machines and disposable CI/Test databases.

Username State Purpose
fixture-admin active, Site Admin admin UI/permissions cases
fixture-user active regular journeys, settings, sessions
fixture-editor active second regular account for the collab-permissions pack (reader/editor of another's pond)
fixture-viewer active signed-in non-member for authenticated/public access-rule cases (issue #55)
fixture-outsider active the "foreign user" of the permission matrix — member of nothing (issue #60)
fixture-pending e-mail not verified unverified-login cases

Permission matrix (permission-matrix.spec.ts, issue #60)

The cross-feature permission hardening pack pins the security-relevant subject × surface combinations against regressions. It is API-level (the UI adds nothing over the resolved status code) and enforces the 404-vs-403 policy: an unauthorized read is 404 (existence hidden), an unauthorized write on something readable is 403.

  • Subjects: site admin (fixture-admin), pond admin / owner (fixture-user), editor (fixture-editor), the same editor label-restricted by a secret-label deny, reader (fixture-viewer), public (anonymous), and the foreign user (fixture-outsider, a member of nothing).
  • Surfaces: page read, edit (collab-token rw/ro), sidebar list, search, versions (history = write), media, and the public HTML endpoint.
  • Extending it: a new permission-touching feature adds a surface here (one expect row per subject) rather than a bespoke test, so the matrix stays the one place the policy is pinned. A weakened guard is caught here — verified by temporarily loosening a route decorator and watching the pack go red.

Plugin sandbox (plugins.spec.ts, issue #73)

The sandbox security pack drives the Site-Admin plugin preview page (/admin/plugins/:id/preview) — the exact sandbox runtime pages embed — with three fixture plugins built in plugin-fixtures.ts and installed through the admin API:

  • well-behaved: answers render and resizes its own frame via the declared ui capability;
  • malicious (the permanent security regression asset, ADR 0008): probes the parent DOM, cookies, localStorage, same-origin and external fetch, and an undeclared capability — every probe must report blocked. A LEAKED verdict is a sandbox escape and fails the build;
  • hung: never answers, so the host's 5 s deadline must collapse it to the failure placeholder while the surrounding page stays responsive.

Runs in the auth-e2e CI job (needs the api's writable PLUGINS_DIR, satisfied by the default ./data/plugins).

Attachments (attachments.spec.ts, issue #61)

Non-image attachments: a page's attachments section uploads an allowlisted file, lists it, and inserts it into the document as a download link (verified to serve with Content-Disposition: attachment + nosniff, never inline); a disallowed extension is rejected with the localized allowlist error; the Pond Admin file manager reports storage usage and flags an orphan (a pond-level upload with no embedding page). The SVG sanitize/reject policy is covered at the api level in files.e2e.db.test.ts.

Import (import.spec.ts, issue #64)

The sidebar "import document" action: pick a file, upload, watch progress, open the new page. .md imports directly (the response is already succeeded); .docx/.odt poll a conversion job. Cases: a .docx corpus fixture (#63) opens the converted page, a .md opens directly, an unsupported .txt shows the localized error and creates no page, and two concurrent .md imports both complete. The .docx case self-skips unless E2E_PANDOC is set — CI's e2e stack has no reachable pandoc sidecar (jobs are container-networked; same reason the api's real-pandoc fixtures test skips in CI, #63), so it runs locally / on a stage. Run it locally with a sidecar reachable at the api's PANDOC_URL:

docker run -d -p 3030:3030 pandoc/core:3.6 server   # api PANDOC_URL → this
E2E_PANDOC=1 E2E_BASE_URL=http://localhost:5990 \
  pnpm --filter @dorfteich/web exec playwright test e2e/import.spec.ts

Export (export.spec.ts, issue #65)

The pond-settings "Download pond as ZIP" link (a Markdown ZIP of the readable pages) and the page-menu office export. The ZIP download needs no sidecar; the .docx export runs a conversion job and, like the import .docx case, self-skips unless E2E_PANDOC is set. The permission-filtered ZIP contents, the docx pandoc output, and the 500-page streaming path are covered at the api level in export.service.db.test.ts (+ export-markdown.test.ts).

Content fixtures

db:seed also creates a shared pond content-fixtures (owned by fixture-user) with two pages, for the content regression pack and manual QA:

  • Every Element (every-element) — every editor schema node and mark (issue #24: headings 14, all list types, table, blockquote, code block, horizontal rule, hard break, and all five marks). Loaded from the checked-in apps/api/prisma/fixtures/content-page.yjs, a Yjs snapshot generated from the human-readable content-page.md next to it — content-page.md is the thing to read or edit; the .yjs file is a build artifact of it, not source.
  • Fixture Image (fixture-image) — one real, servable uploaded image (the placeholder fileId inside the Markdown fixture above is not a real attachment; this page's image is).

Regenerating after editing content-page.md:

pnpm --filter @dorfteich/api fixtures:regenerate

This is deterministic — re-running without editing the Markdown produces a byte-identical .yjs file (the script pins the Yjs document's clientID, which is otherwise randomized per Y.Doc instance) — and it refuses to write a snapshot that isn't a fixed point of the Markdown round-trip (docToMarkdown(markdownToDoc(x)) === x), so a stale fixture can't get checked in silently.

Conventions

  • New feature packs get their own <feature>.spec.ts next to these and extend the fixture matrix here (permission matrix arrives with M5, issue #60).
  • Use contextForUser() from helpers.ts for signed-in tests — it logs in through the api and hands you a browser context with the session cookie, no UI login repetition.
  • Flaky tests are defects (ADR 0014): fix or quarantine immediately.