test(e2e): cover the anonymous public-share page - #81
Merged
Conversation
Closes gate-26, and covers four dashboard-public-share scenarios that had no e2e proof (gate-19: 262 -> 258). The public share is the one page LaunchPad serves to unauthenticated visitors — a separate entry point (templates/public.php -> src/public.js -> DashboardPublicShareView.vue) that bypasses the app shell and the user session entirely. It had no e2e coverage at all. THE DISCRIMINATING ASSERTIONS ARE THE NEGATIVE ONES. "An anonymous request with a valid token returns the dashboard" would also pass if the endpoint ignored the token and served any dashboard to anyone — the failure mode that actually matters on a route with no authentication in front of it. So the positive case is bracketed by two controls against the same endpoint in the same run: - a well-formed but never-issued token must NOT return 200 (before) - the token that just worked must STOP working once revoked (after) A pass therefore means the token is what admits the request, rather than the absence of a check. The browser leg uses a fresh context with no credentials and asserts `.public-share-view` is visible — DashboardPublicShareView's root element, so the assertion is that the public bundle booted and mounted, not merely that some HTML came back. It also asserts the visitor was not bounced to /login: both API legs could pass while the rendered page still demanded a session, which is precisely the bug a public link must not have. It lands in tests/e2e/ci/ — the directory the Playwright job actually runs. A spec outside it would satisfy the gate while never executing, which is the shape of every green-but-dead suite in this fleet.
Contributor
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| composer | ✅ | ✅ 102/102 | |||
| npm | ✅ | ✅ 548/548 | |||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-09 15:22 UTC
Download the full PDF report from the workflow artifacts.
…it after CI measured: POST /api/dashboard answered 403 personal_dashboards_disabled. A fresh instance ships allow_user_dashboards OFF (REQ-ASET-003), so the test could never reach the surface it exists to cover. Enabling it is setup, not an assertion — the prior value is read from GET /api/admin/settings first and restored at the end, so the instance is left as it was found for whatever runs next in the same job.
Contributor
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| composer | ✅ | ✅ 102/102 | |||
| npm | ✅ | ✅ 548/548 | |||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-09 15:33 UTC
Download the full PDF report from the workflow artifacts.
CI measured: POST /api/dashboard answers
{dashboard: {...uuid...}, placements: [...]} — the new dashboard is
nested and the default widget bundle comes back alongside it, so reading
uuid off the root gave undefined. The assertion message printed the whole
body, which is how the real shape was identified from one run.
Contributor
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| composer | ✅ | ✅ 102/102 | |||
| npm | ✅ | ✅ 548/548 | |||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-09 15:44 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.
Closes gate-26, and covers four
dashboard-public-sharescenarios that had no e2e proof (gate-19: 262 → 258).Why this surface
The public share is the one page LaunchPad serves to unauthenticated visitors — a separate entry point (
templates/public.php→src/public.js→DashboardPublicShareView.vue) that bypasses the app shell and the user session entirely. It had no e2e coverage at all.The discriminating assertions are the negative ones
"An anonymous request with a valid token returns the dashboard" would also pass if the endpoint ignored the token and served any dashboard to anyone — the failure mode that actually matters on a route with no authentication in front of it.
So the positive case is bracketed by two controls, against the same endpoint in the same run:
A pass therefore means the token is what admits the request, rather than the absence of a check.
The browser leg
A fresh context with no credentials, asserting
.public-share-viewis visible —DashboardPublicShareView's root element, so the assertion is that the public bundle booted and mounted, not merely that some HTML came back. It also asserts the visitor was not bounced to/login: both API legs could pass while the rendered page still demanded a session, which is exactly the bug a public link must not have.Placement
It lands in
tests/e2e/ci/— the directory the Playwright job actually runs (playwright-test-path: tests/e2e/ci). A spec outside it would satisfy the gate while never executing, which is the shape of every green-but-dead suite in this fleet.Measured
gate-46 (spec-anchor-existence) still passes, so the
@spectarget and all four@e2eslugs resolve to real scenarios — the drop of exactly 4 is the evidence they matched.quality / E2E Tests (Playwright)is green here. The whole point is a test that runs; if CI shows it red, the finding stands and this PR should not land.