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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions