Skip to content

Fleet Playwright e2e coverage (Gate-19): status, way-of-working & how to continue #105

Description

@rubenvdlinde

Fleet Playwright e2e coverage (Gate-19): status, way-of-working & how to continue

This issue captures a large fleet-wide effort (2026-05-26/27) to consolidate pending work and stand up Playwright UI-test coverage across all Conduction Nextcloud apps, plus exactly where we stopped and how to continue.


1. What was done

Consolidation (goals 1, 2, 4, 5):

  • Committed + pushed all uncommitted WIP across ~18 app repos; opened and merged ~25 PRs to development/beta (incl. all production apps).
  • Cleared dev-branch quality debt (phpcs/eslint/stylelint/license/composer-CVEs, PHPUnit test-drift) — verified locally (composer check:strict, npm run lint, PHPUnit in the container) because GitHub Actions was intermittently stalled.
  • Smoke-tested the enabled apps in the browser.
  • Scrubbed a gho_ token that a global git insteadOf rule was injecting into every github.com URL (now via the gh credential helper).

Playwright e2e coverage system (goal 3):

  • Built Gate-19 (hydra/scripts/lib/check_e2e_coverage.py, skill hydra-gate-e2e-coverage, PRs hydra#347 + #349) — a mechanical gate that measures spec→Playwright coverage.

2. The way of working (follow this going forward)

Gate-19 model — every #### Scenario: and alt-format **Scenarios:** numbered item in openspec/specs/*/spec.md is a coverage unit, and must be either:

  • Covered: a tests/e2e/** Playwright test carries @e2e openspec/specs/<spec>/spec.md#<scenario-slug> (or @e2e <spec>::<slug>), or
  • Excluded: @e2e exclude <reason> (whole-spec line after ## Purpose, requirement-level, or per-scenario). A bare @e2e exclude (no reason) fails the gate.

Run: python3 scripts/lib/check_e2e_coverage.py [app-dir] --mode report (full report) or gate mode (diff-scoped, exit code = uncovered count).

Hard rules (non-negotiable):

  • Playwright tests the UI only — log in, click, fill, submit, assert rendered DOM. API contracts → Newman. Backend units → PHPUnit. Do not write API-assertion tests in Playwright.
  • Never change production code to make a test pass. In particular, never add @NoCSRFRequired to controllers for test convenience (a prior attempt did this on docudesk and was reverted, #279) — the browser sends the CSRF token automatically.
  • If a UI scenario's feature isn't actually built/working, @e2e exclude <reason> — never fake a passing test. Real functionality only.
  • Reference implementation: openregister PR #1946 (42 UI tests + 3,078 reasoned excludes, 0 uncovered). Copy its structure.

Tooling/process learned:

  • Run tests locally against the dev container at http://localhost:8080 (admin/admin) — npx playwright test (Playwright is installed; no MCP needed). Set base URL to :8080.
  • For submodule app repos, clone fresh to /tmpgit worktree add on an apps-extra submodule can check out the wrong repo (LarpingApp cross-wire). Worktrees are fine for plain repos.
  • Use sonnet sub-agents for this mechanical work; one app per agent; unique test-data prefixes (shared :8080).
  • Many apps' SPA routers use history-mode base /apps/<app> — if /index.php/apps/<app>/... renders empty, use /apps/<app>/....

3. Current status (per app)

Done — Gate-19 0 uncovered, with real UI tests:

App UI tests PR
openregister 42 #1946
pipelinq 78 #588
mydash 64 #317
openbuilt 59 #154
opencatalogi 39 #727
docudesk 31 #281
procest 9 #633
scholiq 5 #173

Done — 0 uncovered but currently all-excluded (see caveats):

App Note
openconnector #998/#999 — wrongly classified as headless; see §4
shillinq #355 — v0.1.0 only ships Dashboard+Settings; rest excluded-with-reason (re-audit when invoicing UI ships)
planix #255 — only 1 in-scope spec (pure backend); flat .md specs + changes/ specs are outside the gate's scan path

Done in the gate, but green is a BROKEN-SPA artifact (0 real coverage):

App Problem Bug
larpingapp Vue SPA silently fails to mount (blank #content) #202
softwarecatalog SPA white-screen — webpack runtime chunk not loaded in templates #322

Not done:

  • nldesign (admin theming UI at /settings/admin/theming), decidesk, zaakafhandelapp (deprecated — confirm before investing), doriath. hrmq is not installed in the dev container.

Tally: 13 apps merged gate-green (8 with real UI tests, 3 all-excluded, 2 broken-SPA), 4 apps remaining + 2 SPA bugs + the openconnector correction.


4. ⚠️ Correction: OpenConnector is NOT headless

openconnector was whole-spec-excluded (#998/#999) as a "headless connector — covered by Newman." That is wrong. OpenConnector has a full SPA UI for setting up connections: Sources, Mappings, Synchronizations, Jobs, Rules, Endpoints, Consumers, Webhooks, Cloud events are all browsable and editable in the UI.

Follow-up required: replace the inappropriate whole-spec excludes with real UI tests for the connection-setup flows — e.g. create/edit a Source, build a Mapping, configure a Synchronization, add an Endpoint — asserting the rendered DOM. Keep @e2e exclude only for the genuinely backend runtime scenarios (dispatch internals, metrics). Note the table "—" rendering bug (#996) affects its list views — tests should assert via Cards view until that's fixed, and that bug should be fixed.


5. How to unblock the broken-SPA apps

larpingapp (#202) — JS bundle loads (200), #content exists, but new Vue().$mount('#content') renders nothing, no console error. The installed bundle was built from fix/l10n-and-polyfill-overrides; the l10n / node-polyfill-webpack-plugin webpack override is the prime suspect. Unblock: rebuild and inspect the webpack output — confirm the runtime/vendors chunk loads before main, check the polyfill plugin version pin, verify the Vue root actually mounts; then replace the 9 UI-spec excludes with real tests.

softwarecatalog (#322) — both softwarecatalog-settings.js and softwarecatalog-main.js start with (self.webpackChunksoftwarecatalog=...).push(...) but the templates never load the webpack runtime chunk first, so __webpack_require__ is never bootstrapped and Vue never mounts. Unblock: fix templates/*.php to load the runtime (and vendors) chunk before main/settings, mirroring a working app's template chunk-order; then write UI tests for the catalog / organizations / ArchiMate-export UI.

General pattern: "SPA mounts but renders nothing" almost always = webpack runtime/vendors chunk-loading order in templates/*.php. Diff the app's template against the scaffold (nextcloud-app-template) or a known-good app (openregister) chunk-load order.


6. How it should continue (next steps, in priority order)

  1. Fix the 2 broken SPAs (larpingapp #202, softwarecatalog #322) → then replace their excludes with real UI tests.
  2. Correct openconnector (§4) with real connection-setup UI tests.
  3. Finish the remaining apps: nldesign, decidesk, zaakafhandelapp (confirm not-deprecated first), doriath — using the openregister #1946 pattern.
  4. Normalize spec locations so the gate sees everything: planix has flat .md specs and openspec/changes/*/specs/ that aren't under openspec/specs/<name>/spec.md; shillinq's specs were only in changes/ (promoted during #355). Standardize on openspec/specs/<name>/spec.md.
  5. Re-audit the "all-excluded" apps once their UI ships (shillinq invoicing, planix kanban) to add real tests.
  6. Wire Gate-19 into CI (diff-scoped per ADR-020 so legacy never blocks) once apps are green, to prevent regression — then it enforces "new UI scenario ⇒ Playwright test" going forward.

7. Org-level flags (need a human / org admin)

  • PROJECT_TOKEN rotation — the reusable "OpenSpec Sync" workflow fails org-wide with Bad credentials; the org secret is expired.
  • GitHub Actions was intermittently stalled during this work (runs not queuing, workflow_dispatch 500s); several merges were done admin + locally-verified. Confirm CI has since caught up and re-run on the merged development tips.
  • Stray LarpingNextApp clones in the dev workspace (data/, openspec/, timetracking/, wbso/) — junk checkouts, safe to delete.
  • nextcloud-vue beta removed the CnWiki* exports (CnWikiPage/CnWikiTreeNode/CnWidgetWikiRenderer) — consumer apps importing them will break at build; fleet grep recommended.

Bugs/issues filed during this effort

openregister #1947 (ViewService organisation), #1948 (EntitiesSidebar slot); openconnector #996 (table "—"); larpingapp #202 (SPA mount); softwarecatalog #322 (SPA chunk-load).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions