Skip to content

fix(e2e): install Docudesk in CI, repair 2 lying skips, turn traces back on - #142

Open
rubenvdlinde wants to merge 2 commits into
developmentfrom
fix/e2e-burndown-0806
Open

fix(e2e): install Docudesk in CI, repair 2 lying skips, turn traces back on#142
rubenvdlinde wants to merge 2 commits into
developmentfrom
fix/e2e-burndown-0806

Conversation

@rubenvdlinde

@rubenvdlinde rubenvdlinde commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Burning down the Playwright E2E suite. Measured baseline on development, run 31083894467: 168 passed / 5 failed / 76 skipped of 249 collected.

The instrument first

Traces have never been written by this job. tests/e2e/playwright.config.ts sets trace: 'on-first-retry' next to retries: 0. Playwright records under that mode only on a retry, and a retry can never happen here — so no trace file has ever existed, while the shared workflow's upload step ran, matched nothing, and reported it quietly under if-no-files-found: ignore. Every red run had a screenshot and a video and not the one artifact that carries the network log and the per-step DOM.

Switched to retain-on-failure, which does not depend on retries. The output path was already correct: the shared workflow globs both server/apps/<app>/test-results/ and server/apps/<app>/tests/e2e/test-results/, and this config's outputDir is the former.

The root playwright.config.ts gets the same change plus the globalTimeout the CI config already carries. CI does not use it, but it is the documented fallback, and the job it would run under is capped at timeout-minutes: 45 — a cancellation there prints no tally and uploads nothing.

The five failures

# Test Root cause
1 builder-host.spec.ts:44 detail page Not fixed — needs a decision, see below.
2-4 docudesk-document-templates.spec.ts:146/:176/:204 Docudesk was not installed on the CI instance
5 page-editor-coverage.spec.ts:398 wiki page Bound register/schema slugs that only exist on a dev box

Docudesk (3 failures). The three REQ-DDT-002 specs drive Docudesk's own REST surface. With the app absent every call is a Nextcloud router 404, and the log said so plainly — [globalSetup] docudesk not installed — template fixtures skipped, then Expected: 200 / Received: 404. No change in this repository could have fixed that. tests/e2e/global-setup.ts already knows how to configure Docudesk's template register and seed the fixtures once it is present, so adding it to additional-apps is the entire fix. ref: main because Docudesk publishes main and beta only. Only its API is exercised, so the un-built frontend does not matter.

Two mutually exclusive warnings rendered together. The strict-mode violation in failure 4 was a real defect underneath the missing dependency: .ob-document-attach__warn resolved to two elements — "Docudesk is not installed" and "the attached template no longer exists in Docudesk". The second is not knowable when the first is true; a 404 from an absent app is the router reporting a missing route, not Docudesk reporting a missing template. They were two independent v-ifs and both fired whenever docudeskAvailable arrived late, which is the normal case — PageDesignerHost initialises it true and resolves it asynchronously. Now v-else-if.

Wiki page (failure 5). It bound openbuild-hello-world-production / hello-world-production-hello-message. Those are names the creation wizard mints. The CI fixture is built by occ openbuild:seed-hello-world-fixture, which deliberately does not mint a per-version register and puts the manifest, the schema and the sample objects in the shared openbuild register — its own code comment says so, and ci-seed.sh prints the instance's register list, where those names do not appear. The test was pinned to a fixture shape that only existed on the machine it was written on. Bound to the pair the fixture actually provides.

Skips: two guards that lied

builder-undo-redo.spec.ts REQ-BUR-004 probed for an ApplicationVersion named staging, found none, and skipped with "seed one to exercise this scenario". Nothing in CI was ever going to. The suite's own ensureVersionChain() provisions development → staging → production on demand and is proven working in this same job by versionRouting.spec.ts. Given a dedicated slug: the neighbouring tests open /pages with no ?_version=, so growing a chain on the shared pw-undo-redo would silently change what they test on every run after the first.

automations-rbac.spec.ts — the guard reported a failed lookup as a defect. Both tests skipped with "the openbuild automation schema slug collides with a pre-existing schema of the same slug on this shared instance — automation CREATE/SAVE 400s regardless of app/version". Run 31083894467 disproves that within a single run: seven tests in automations.spec.ts sit behind a copy of the same helper, against the same instance, and passed — composing and saving real automations end to end (REQ-AUTD-002 x3, -003, -005, -006, -007). Only this file's two skipped.

The discriminator is not the instance, it is the auth context. This describe declares test.use({ storageState: { cookies: [], origins: [] } }) so each test can log in as a non-admin — which also makes the request fixture anonymous. The probe's read of api/schemas/automation was refused, and if (resp.ok() === false) return false turned "I could not look" into "the feature is broken", with a confident and wrong explanation attached. The probe now authenticates with the admin credentials the config already uses for httpCredentials, and a non-OK response throws rather than returning false — a probe that cannot probe must fail loudly, not become a verdict. These two may now fail for real reasons; that is the point.

Four stale openbuild#41 quarantines liftedbootstrap-openbuild's index-page test, page-designer-ui REQ-OBPDUI-001/002, application-detail-overview REQ-OBADO-006. All four carry the reason builder-host.spec.ts's own note already says "no longer holds", and the routes they claim are broken are driven successfully by specs that pass in the same run.

Two were strengthened while being lifted, because as written they could not have failed honestly:

  • REQ-OBPDUI-002 asserted "the page body does not contain the string 404 or 'not found'" — a page-wide text scan that would fail on the legitimate version-not-found copy the very next test requires, and pass on a completely blank designer. Replaced with a positive assertion that the host mounted for the slug.
  • REQ-OBADO-006 used page.locator('a, button').filter({ hasText: /openregister/i }).first() — page-wide, so it would keep passing with the Register widget deleted — and then read an href the widget does not have (it navigates via window.location.href), inside an if (href) that asserted nothing when absent. Now scoped to .ob-register-widget and asserted on the navigation request the click actually issues.

Mutation proof

The dialog fix ships with a unit test that fails against the old markup:

$ # v-else-if reverted to v-if
AssertionError: expected [ DOMWrapper{ …(3) }, …(1) ] to have a length of 1 but got 2
 Tests  1 failed | 4 passed (5)
$ # with the fix
 Tests  5 passed (5)

Not fixed here, needs a decision

builder-host.spec.ts:44 — the detail page renders no data widget. Read from the failure's error-context.md: the page does render, the object did load (the heading is the object's own title), and the Related widget is there — but the auto-rendered Data widget is absent, so the seeded body text has nowhere to appear.

Cause is in @conduction/nextcloud-vue, not here. CnDetailPage.fetchObjectIfNeeded() fires fetchObject and fetchSchema in parallel. shouldRenderAutoBody flips true on currentObject alone, and its watcher calls materializeAutoBody(), which drops the Data widget when !this.currentSchema. The only trigger that would re-materialize is a change of resolvedObjectType, which never changes on a detail route. So whenever the schema resolves after the object — the overwhelmingly likely order, one row by id versus a schema lookup — the Data widget is dropped permanently. Left honestly red; the fix belongs in nc-vue.

applicationDetailOverview.spec.ts:241 (REQ-OBADO-007/009/010) skips for two independent reasons, both structural. Its guard is linkCount === 0 on .ob-detail-dashboard__widgets a[href], and the widget shelf contains no anchors at all — ManifestWidget, RegisterWidget and GroupsWidget navigate by assigning window.location.href from NcButton clicks. Retargeting the selector would not help, because the requirement itself — structural widget deep-links preserve ?_version= — contradicts the shipped design: ensureVersionChain omits register so versions share one register (manifest-only versioning, REQ-OBV-107), and the deep link therefore cannot carry a version slug. This needs a spec decision, not a test edit.

automations.spec.ts / automations-rbac.spec.ts — 10 skips, guard is HONEST. automationSchemaIsUsable() is a read-only capability probe, not a malformed seed. The blocker is upstream: OpenRegister's SchemasController::show() resolves api/schemas/{slug} by global slug with no register scoping, and SchemaMapper::find() carries a dated BUG-DB-10 comment documenting exactly this collision class. Needs an OpenRegister fix or a namespaced slug for openbuild's automation schema.

Skips deliberately left alone

21 tests are test.skip('title', fn) with a STUB bodygoto('/applications') + expect(main).toBeVisible() regardless of what the title claims, each carrying an // @e2e <anchor> comment that satisfies gate-19's traceability check. nldesign-theme-selection (7), docudesk-document-templates REQ-DDT-003/004/005 (7), app-icon-management (3), application-detail-overview REQ-OBADO-001 (2), openbuild-rbac (2). One of them literally asserts expect(actionCount).toBeGreaterThanOrEqual(0). Un-skipping these would convert 21 silent skips into 21 vacuous passes, which is strictly worse — they are identified and left alone on purpose.

4 more are test.skip with an EMPTY bodyopenbuild-runtime REQ-OBR-008a x2 and REQ-OBR-009a x2 are comment-only blocks documenting a blocker. Worth flagging: the blocker three of them name ("the version-history panel renders no rows") was fixed in fcaa7a8, and version-rollback.spec.ts's "the version history tab lists the chain" passes today. So they are unblocked — but their assertions were deleted when they were quarantined, so un-skipping them yields vacuous green. Writing the bodies back is real follow-up work, not a mechanical flip.

Gate-19 accepts both shapes. A test.skip whose body is a stub, or empty, still counts as @e2e coverage for its scenario. That is a gate defect rather than an openbuild one, but it is why 25 scenarios here report as covered while asserting nothing.

Honest skips, verified: hydra-console (12 — probes for an externally-provisioned hydra-cache register and deliberately treats any non-404 as present, so a broken-but-present register fails loudly; a model probe), chat-companion-streaming (6) and agents (1) — no LLM provider on the runner, promoteDestructive (3 — PromoteVersionDialog has no call site at all; onPromoteClick looks for a window.openbuild.openPromoteDialog nothing registers), export-zip (2 — dead selector plus a route that changed from slug to object UUID), github-store (2 — no GitHub credential granted to openbuild), schema-access-scopes-rbac (3 — needs a staging-version schema copy; versionChain.ts creates versions, not their schemas, and the file's own comment says so precisely), virtual-app-crud/schema-crud test.fixme (3 — named product gaps).

Also worth knowing

.github/workflows/code-quality.yml's push trigger is [main, development, feature/**, bugfix/**, hotfix/**]. A branch named fix/** gets no CI on push at all — this PR is the only reason these changes were measured.

🤖 Generated with Claude Code

…ack on

The E2E job measured 168 passed / 5 failed / 76 skipped (run 31083894467).
This addresses the instrument first, then the failures whose cause was a
missing dependency or a guard that lied.

TRACES WERE NEVER WRITTEN. tests/e2e/playwright.config.ts pairs
`trace: 'on-first-retry'` with `retries: 0`. Playwright only records under
that mode ON a retry, and a retry can never happen, so no trace file has
ever been produced by this job — while the workflow's upload step ran,
found nothing, and said so quietly under `if-no-files-found: ignore`. Every
red run had a screenshot and a video but not the one artifact carrying the
network log. `retain-on-failure` has no dependence on retries. The output
directory is already globbed by the shared workflow (it uploads both
`server/apps/<app>/test-results/` and `.../tests/e2e/test-results/`), so
the traces now actually leave the runner. The root config gets the same
change plus the `globalTimeout` the CI config already carries — it is the
documented fallback if the CI config is ever absent, and a job cancelled at
`timeout-minutes: 45` produces no tally and uploads nothing.

DOCUDESK WAS NOT INSTALLED. Three REQ-DDT-002 specs drive Docudesk's REST
surface (`api/templates`, `api/templates/{id}`, `.../preview`). With the app
absent every call is a router 404 and the run said so: `[globalSetup]
docudesk not installed`, then `Expected: 200 / Received: 404`. No code
change here could have fixed that. global-setup.ts already configures
Docudesk's template register and seeds the fixtures once it IS present, so
adding it to `additional-apps` is the whole fix. `ref: main` — Docudesk
publishes `main` and `beta` only, no `development`.

TWO WARNINGS RENDERED AT ONCE. `.ob-document-attach__warn` resolved to two
elements — "Docudesk is not installed" and "the attached template no longer
exists in Docudesk" — which are mutually exclusive claims; the second is not
knowable when the first is true, because a 404 from an absent app is the
router reporting a missing ROUTE, not Docudesk reporting a missing TEMPLATE.
They were two independent `v-if`s and both fired whenever the capability
flag arrived late, which is the normal case (PageDesignerHost initialises it
`true` and resolves it asynchronously). Now `v-else-if`, with a unit test
that fails on the old markup: `expected [...] to have a length of 1 but
got 2`.

A SKIP THAT COULD HAVE SEEDED ITSELF. builder-undo-redo REQ-BUR-004 probed
for an ApplicationVersion named "staging", found none, and skipped with
"seed one to exercise this scenario". Nothing was ever going to. The suite's
own `ensureVersionChain()` provisions development -> staging -> production
on demand and is proven in this same job by versionRouting.spec.ts. Given a
DEDICATED slug, not the shared one: the neighbouring tests open `/pages`
with no `?_version=`, so growing a chain on `pw-undo-redo` would change what
they test on every run after the first.

A FIXTURE THAT ONLY EXISTED ON ONE MACHINE. page-editor REQ-PEC-006 bound
`openbuild-hello-world-production` / `hello-world-production-hello-message`.
Those are wizard-minted names; the CI fixture is built by `occ
openbuild:seed-hello-world-fixture`, which deliberately does not mint a
per-version register and puts everything in the shared `openbuild` register
— ci-seed.sh prints the register list and it is not there. Bound to the pair
the fixture actually provides, so CI and a dev box now agree.

FOUR STALE QUARANTINES LIFTED. bootstrap-openbuild's index-page test,
page-designer-ui REQ-OBPDUI-001/002 and application-detail-overview
REQ-OBADO-006 all carry the openbuild#41 reason that builder-host.spec.ts's
own note says "no longer holds" — and the routes they claim are broken are
driven successfully by passing specs in the same run. Two were strengthened
while being lifted: REQ-OBPDUI-002 asserted "the page body does not contain
the word 404", which would fail on the legitimate version-not-found copy the
next test requires and pass on a blank designer; REQ-OBADO-006 used a
page-wide `locator('a, button').filter(...).first()` that would keep passing
with the Register widget deleted, and read an `href` the widget does not
have (it navigates via `window.location.href`), guarded by an `if (href)`
that asserted nothing.
… a defect

Both tests in automations-rbac.spec.ts skipped with "the openbuild
`automation` schema slug collides with a pre-existing schema of the same slug
on this shared instance — automation CREATE/SAVE 400s regardless of
app/version".

Run 31083894467 disproves that within a single run. Seven tests in
automations.spec.ts sit behind a copy of the SAME helper, against the SAME
instance, and passed — composing and saving real automations end to end
(REQ-AUTD-002 x3, -003, -005, -006, -007). Only this file's two skipped.

The discriminator is not the instance, it is the auth context. This describe
declares `test.use({ storageState: { cookies: [], origins: [] } })` so each
test can log in as a non-admin. That also makes the `request` fixture
anonymous, so the probe's read of `api/schemas/automation` was refused —
and `if (resp.ok() === false) return false` turned "I could not look" into
"the feature is broken", with a confident and wrong explanation attached.

The probe now authenticates with the admin credentials the config already
uses for `httpCredentials`, independently of the test's storageState. And a
non-OK response THROWS instead of returning false: a probe that cannot probe
now fails the run loudly rather than silently becoming a verdict. The skip
reasons are rewritten to describe what the check actually establishes.

These two tests may now fail for real reasons. That is the point — a real
failure is information and a false skip is not.
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openbuild @ ad89c2e

Check PHP Vue Security License Tests
lint ⏭️
phpcs ⏭️
phpmd ⏭️
psalm ⏭️
phpstan ⏭️
phpmetrics ⏭️
eslint ⏭️
stylelint ⏭️
build ⏭️
composer ⏭️ ⏭️
npm ⏭️ ⏭️
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-06 11:18 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openbuild @ 0ba61da

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
test-l10n
composer ✅ 101/101
npm ✅ 654/654
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️
Hydra gates

Quality workflow — 2026-08-06 11:28 UTC

Download the full PDF report from the workflow artifacts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants