test(e2e): stop 18 backend-only scenarios laundering gate-19 coverage through an always-skipped test - #765
Conversation
… through an always-skipped test tests/e2e/spec-coverage/document-zaakdossier.spec.ts carried a test tagged with 18 @e2e anchors whose body ended in an unconditional `test.skip(true, 'Backend-enforced — asserted in PHPUnit/Newman, not UI')`. It reported *skipped* on every run in every environment, while still giving gate-19 the traceability link for all 18 scenarios — REQ-ZAK-001a..c, 002a..d, 003a..d, 007a..b, 008b, 009a..b, 010a..b were recorded as e2e-covered by a test that never executed. Those scenarios are genuinely backend-only (service guards, HTTP status contracts, Range framing, a repair step), so their traceability moves to the mechanism gate-19 provides for exactly this: a reason-bearing `@e2e exclude` on each scenario in the spec, naming the PHPUnit/Newman suite that does assert it. The placeholder test is removed. Three further tests ended in an unconditional `test.skip(true, 'Requires a seeded case fixture …')`. The blocker is real but permanent — nothing in this repo seeds a dossier fixture for Playwright — so they become `test.fixme` referencing #764 rather than skips that read as transient. Net: no scenario loses its traceability (18 excluded with a written reason, 10 still tagged by this file), and the suite no longer reports coverage from a test that cannot run. Refs #764
… report red Removed in the next commit.
Quality Report — ConductionNL/procest @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue3-compile | ✅ | ||||
| test-l10n | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ✅ 552/552 | |||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-08 10:46 UTC
Download the full PDF report from the workflow artifacts.
Positive control done: with the sentinel present the E2E job reported 1 failed / 87 passed / 38 skipped and concluded 'failure', so the 87 passed / 0 failed / 38 skipped result on this branch is a real verdict rather than a job that cannot go red.
Quality Report — ConductionNL/procest @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue3-compile | ✅ | ||||
| test-l10n | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ✅ 552/552 | |||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-08 11:10 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/procest @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue3-compile | ✅ | ||||
| test-l10n | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ✅ 552/552 | |||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-08 11:33 UTC
Download the full PDF report from the workflow artifacts.
VerificationE2E Tests (Playwright) —
Total −1 (the deleted placeholder test), skipped −1, passed unchanged. Note the dependabot PR run has no E2E job at all, so it is not a usable baseline. Positive controlA sentinel spec was pushed that boots the real app through the same navigation and asserts an impossible string. With it present the E2E job reported 1 failed / 87 passed / 38 skipped and concluded Hydra Gates is red — pre-existing, and gate-19's remaining 10 are explained
1. gate-19 was already red on procest PRs before this change. The two most recent baseline PR runs ( 2. On this spec's own scope, this change takes gate-19 from 28 findings to 10. Measured by running Every one of the spec's 28 scenarios was previously flagged. The gate had already worked out that this spec's e2e coverage was fictitious; nothing surfaced it because gate-19 is diff-scoped and no PR had touched the spec. The remaining 10, split honestly
Reproduced minimally (two tests, one file, identical but for a guarded skip — the guarded one fails, the clean one passes) and filed as ConductionNL/.github#239, with the fleet blast radius: 111 guarded occurrences of this idiom across openregister/procest/hermiq/docudesk/nldesign versus 4 genuinely unconditional ones. I have deliberately not added |
The finding
tests/e2e/spec-coverage/document-zaakdossier.spec.tscontained a test tagged with 18@e2escenario anchors whose body ended in:Unconditional. It reported skipped on every run, in every environment, while still supplying gate-19 with the traceability link for all 18 scenarios. REQ-ZAK-001a–c, 002a–d, 003a–d, 007a–b, 008b, 009a–b and 010a–b were recorded as e2e-covered by a test that never executed.
The stated reason was honest about why the test could not assert anything — but the mechanism laundered coverage: the gate cannot tell a tag on a running test from a tag on a permanently skipped one.
The fix
Those 18 scenarios really are backend-only (service guards, HTTP status contracts,
Content-Rangeframing, aninfo.xmlrepair step). So their traceability moves to the mechanism gate-19 provides for exactly this case — a reason-bearing@e2e excludeon each scenario inopenspec/specs/document-zaakdossier/spec.md, each naming the PHPUnit or Newman suite that does assert it. The placeholder test is deleted.Three further tests ended in an unconditional
test.skip(true, 'Requires a seeded case fixture …'). The blocker is real, but permanent — nothing in this repo seeds a dossier fixture for Playwright, so the condition can never become true. They becometest.fixmereferencing #764, so the quarantine is visible in the declaration rather than hidden behind a skip that reads as transient.Coverage accounting
fixme, all → #764)@e2e excludereasonVerified by partition: the 18 excluded and the 10 still tagged by the spec file are disjoint and together cover every
#### Scenarioin the spec — no scenario is left uncovered and none is double-counted.Note on the wider inventory
This came out of a fleet-wide triage of disabled e2e declarations. Worth recording: the great majority of
test.skip(true, …)calls across the fleet are insideif/else/catchguards — the literaltrueis Playwright's "skip from this point" API shape, not evidence that the skip is unconditional. Across 11 repos only 4 unconditionaltest.skip(true)calls existed, and all 4 were in this one file.Closes nothing on its own; #764 tracks the seeding work that would let the three
fixmetests run.