fix(e2e): install Docudesk in CI, repair 2 lying skips, turn traces back on - #142
Open
rubenvdlinde wants to merge 2 commits into
Open
fix(e2e): install Docudesk in CI, repair 2 lying skips, turn traces back on#142rubenvdlinde wants to merge 2 commits into
rubenvdlinde wants to merge 2 commits into
Conversation
…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.
Contributor
Quality Report — ConductionNL/openbuild @
|
| 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.
Contributor
Quality Report — ConductionNL/openbuild @
|
| 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.tssetstrace: 'on-first-retry'next toretries: 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 underif-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 bothserver/apps/<app>/test-results/andserver/apps/<app>/tests/e2e/test-results/, and this config'soutputDiris the former.The root
playwright.config.tsgets the same change plus theglobalTimeoutthe CI config already carries. CI does not use it, but it is the documented fallback, and the job it would run under is capped attimeout-minutes: 45— a cancellation there prints no tally and uploads nothing.The five failures
builder-host.spec.ts:44detail pagedocudesk-document-templates.spec.ts:146/:176/:204page-editor-coverage.spec.ts:398wiki pageDocudesk (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, thenExpected: 200 / Received: 404. No change in this repository could have fixed that.tests/e2e/global-setup.tsalready knows how to configure Docudesk's template register and seed the fixtures once it is present, so adding it toadditional-appsis the entire fix.ref: mainbecause Docudesk publishesmainandbetaonly. 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__warnresolved 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 independentv-ifs and both fired wheneverdocudeskAvailablearrived late, which is the normal case —PageDesignerHostinitialises ittrueand resolves it asynchronously. Nowv-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 byocc 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 sharedopenbuildregister — its own code comment says so, andci-seed.shprints 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.tsREQ-BUR-004 probed for an ApplicationVersion namedstaging, found none, and skipped with "seed one to exercise this scenario". Nothing in CI was ever going to. The suite's ownensureVersionChain()provisionsdevelopment → staging → productionon demand and is proven working in this same job byversionRouting.spec.ts. Given a dedicated slug: the neighbouring tests open/pageswith no?_version=, so growing a chain on the sharedpw-undo-redowould 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 openbuildautomationschema 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 inautomations.spec.tssit 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 therequestfixture anonymous. The probe's read ofapi/schemas/automationwas refused, andif (resp.ok() === false) return falseturned "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 forhttpCredentials, and a non-OK response throws rather than returningfalse— 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#41quarantines lifted —bootstrap-openbuild's index-page test,page-designer-uiREQ-OBPDUI-001/002,application-detail-overviewREQ-OBADO-006. All four carry the reasonbuilder-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:
page.locator('a, button').filter({ hasText: /openregister/i }).first()— page-wide, so it would keep passing with the Register widget deleted — and then read anhrefthe widget does not have (it navigates viawindow.location.href), inside anif (href)that asserted nothing when absent. Now scoped to.ob-register-widgetand 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:
Not fixed here, needs a decision
builder-host.spec.ts:44— the detail page renders no data widget. Read from the failure'serror-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()firesfetchObjectandfetchSchemain parallel.shouldRenderAutoBodyflips true oncurrentObjectalone, and its watcher callsmaterializeAutoBody(), which drops the Data widget when!this.currentSchema. The only trigger that would re-materialize is a change ofresolvedObjectType, 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 islinkCount === 0on.ob-detail-dashboard__widgets a[href], and the widget shelf contains no anchors at all —ManifestWidget,RegisterWidgetandGroupsWidgetnavigate by assigningwindow.location.hreffromNcButtonclicks. Retargeting the selector would not help, because the requirement itself — structural widget deep-links preserve?_version=— contradicts the shipped design:ensureVersionChainomitsregisterso 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'sSchemasController::show()resolvesapi/schemas/{slug}by global slug with no register scoping, andSchemaMapper::find()carries a datedBUG-DB-10comment documenting exactly this collision class. Needs an OpenRegister fix or a namespaced slug for openbuild'sautomationschema.Skips deliberately left alone
21 tests are
test.skip('title', fn)with a STUB body —goto('/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-templatesREQ-DDT-003/004/005 (7),app-icon-management(3),application-detail-overviewREQ-OBADO-001 (2),openbuild-rbac(2). One of them literally assertsexpect(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.skipwith an EMPTY body —openbuild-runtimeREQ-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, andversion-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.skipwhose body is a stub, or empty, still counts as@e2ecoverage 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-provisionedhydra-cacheregister and deliberately treats any non-404 as present, so a broken-but-present register fails loudly; a model probe),chat-companion-streaming(6) andagents(1) — no LLM provider on the runner,promoteDestructive(3 —PromoteVersionDialoghas no call site at all;onPromoteClicklooks for awindow.openbuild.openPromoteDialognothing 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.tscreates versions, not their schemas, and the file's own comment says so precisely),virtual-app-crud/schema-crudtest.fixme(3 — named product gaps).Also worth knowing
.github/workflows/code-quality.yml's push trigger is[main, development, feature/**, bugfix/**, hotfix/**]. A branch namedfix/**gets no CI on push at all — this PR is the only reason these changes were measured.🤖 Generated with Claude Code