test(e2e): drive the onboarding chain in a real browser - #48
Merged
Conversation
The first end-to-end test, and the first test in this repository that exercises a screen at all. It walks the whole chain in one test -- register, create an organization, create a project, create an environment, then load /dashboard/environments cold and find it there. Deliberately not four independent tests: the chain working is the thing that broke, and four tests that each build their own state would stop testing it. Proven to fail, not just to pass. Reintroducing the original defect -- dropping refreshCapabilities() from the tenant refresh -- turns it red on the step that asserts a fresh admin is offered a project rather than told they lack access. Restored, it is green again. A test whose failure has never been observed is a claim, not a check. No data-testid anywhere; every selector is getByRole/getByLabel/getByText. That discipline paid immediately: the first run hit a strict-mode violation because an environment name appears both as a badge and as an option in the environment filter. A CSS-class selector would have silently picked one. CI gets a third job rather than changes to the two existing ones. main's ruleset requires 'Backend (lint + tests)' and 'Frontend (lint + build)' by exact name, and renaming either makes it unsatisfiable and blocks every merge in the repository. npm test still runs node --test, untouched. The suite drives the real stack, so global setup polls the API first and fails naming the compose command rather than timing out on a selector. Each run leaves an account, organization, project and environment in the development database. No teardown on purpose: tearing down means driving the delete-confirmation dialog, doubling the surface for no coverage, and a failed run's leftovers are exactly what you want to inspect. Everything a run creates shares one id so its debris greps as a unit.
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.
The first end-to-end test, and the first test in this repository that exercises a screen at all.
What it does
One test, the whole chain: register → create an organization → create a project → create an environment → load
/dashboard/environmentscold and find it there.Deliberately not four independent tests. The chain working is the thing that broke; four tests that each build their own state would stop testing it.
Proven to fail, not just to pass
Reintroducing the original defect — dropping
refreshCapabilities()from the tenantrefresh()— turns it red on exactly the step that asserts a fresh admin is offered a project rather than told they lack access:Restored, green again.
A test whose failure has never been observed is a claim, not a check.
Worth knowing for anyone doing this next: the frontend container has no source mount. A source change needs
docker compose -f compose.dev.yml up -d --build frontendbefore the test sees it. The first mutation attempt appeared to prove the test didn't catch the bug — it had simply never reached the running app.No
data-testidanywhereEvery selector is
getByRole/getByLabel/getByText. That discipline paid immediately: the first run hit a strict-mode violation because an environment name appears both as a badge and as an option in the environment filter. A CSS-class selector would have silently picked one.Two accessibility gaps surfaced the same way, by the test having nothing to grab: the copy-API-key button has no accessible name, and the registration error banner has no
role="alert". Both are fixed in the follow-up, not here.CI
A third job,
E2E (onboarding chain). The two existing jobs are untouched, and that is not stylistic:main's ruleset requiresBackend (lint + tests)andFrontend (lint + build)by exact name, so renaming either makes it unsatisfiable and blocks every merge in the repository.npm teststill runsnode --test.The new job is not in the ruleset, which is intentional — an end-to-end test should earn the right to block merges before it does.
Running the real stack
docker compose -f compose.dev.yml up -dfrom the repo root. Global setup polls the API first and fails naming that command, rather than timing out on a selector twenty seconds later.Leftover data — stated, not solved
Each run leaves an account, organization, project and environment in the development database. No teardown, on purpose: tearing down means driving the delete-confirmation dialog, doubling the test's surface for no coverage, and a failed run's leftovers are exactly what you want to inspect. Everything a run creates shares one id, so a run's debris greps as a unit. CI ends with
docker compose down -v.Verification
🤖 Generated with Claude Code