MOTIR-81Done
2.2.7 Story E2E — workflow lifecycle + transition enforcement
Estimate: 17m · Depends on: 2.2.2, 2.2.4, 2.2.5, 2.2.6
The Story's closing journey-driven E2E (Playwright, real Postgres, real Next dev, following the Story-1.5.6 / Story-1.6.6 pattern). Drives the full workflow lifecycle from the user's seat to surface bugs the unit/integration tests miss, plus the tenant-isolation guarantees.
Scenarios covered:
- Auto-seed: a new workspace + new project lands at
/settings/project/[projectKey]/workflowshowing the six default statuses (todo,blocked,in_progress,in_review,done,cancelled) + fifteen transitions + restricted policy. Assert both categories (todo,in_progress,done) are represented and thatblocked+cancelledare rendered with the right pills. - Status edit: rename "In Review" → "QA" via the inline editor; reload; the change persists; existing issues with
status: 'in_review'still resolve (thekeyis stable across renames — only thelabelchanges; covered by a separate assertion). - Blocked round-trip (default-seeded): create an issue, transition
todo→blocked(legal per the seed); confirm the issue surfaces under the Blocked column / pill; transitionblocked→in_progressback; both transitions succeed under restricted mode without flipping policy. - Cancellation round-trip (default-seeded): cancel an in-progress issue (
in_progress→cancelled, legal per the seed); confirm finding-#21 readiness effect (a work item blocked by this cancelled blocker becomes ready); reopen viacancelled→todoand confirm the work item is blocked again. - Status add + delete: add a new "Won't Fix" status with
category: done;getTerminalStatusKeysnow returns{done, cancelled, wont_fix}; try to delete the initial status → 422 toast; try to delete BOTHdoneANDcancelledin sequence — the second deletion is blocked byCANNOT_DELETE_LAST_TERMINAL_STATUSbecausewont_fixalone keeps the invariant; removewont_fixtoo → blocked again until at least one terminal remains. - Transition enforcement: from the issue-detail page (existence point: assumed by 2.4; if 2.4 hasn't shipped at this Story's E2E time, the test drives the transition via the Server Action directly via Playwright route — same gate). Drag/click "Done" from "To Do" in a restricted project: rejected with the typed error. Flip policy to
open: same move succeeds. - Cross-workspace isolation: workspace A's workflow edits don't bleed into workspace B's project of the same key (mirroring Story 1.6.5's isolation test).
- Owner-only management: a non-owner member loading
/settings/project/.../workflowsees the read-only fallback; their Server Action POST returns 403. - Atomic-flip race: from two simultaneous sessions, both call
updateStatus({ isInitial: true })on different rows; only one succeeds — the partial unique index from 2.2.1 plus the same-tx unset path from 2.2.5 keeps the invariant.
Helpers: a new tests/e2e/_helpers/workflow.ts lifted from the inline setup, mirroring shell-session.ts + email-fault.ts patterns. Reused by any later Story (boards, list view) needing a workflow-seeded test fixture.
Acceptance criteria
tests/e2e/workflow-flow.spec.tsships the seven scenarios above; all green locally + in CI.tests/e2e/_helpers/workflow.tsreusable fixture lifted out.- The shell-a11y sweep (from 1.5.5) is extended to include
/settings/project/[projectKey]/workflowin EMPTY state; zero rule exclusions. - Quality gates green (tsc + eslint + vitest); full E2E suite green in CI (local OOM exception applies per 1.6.4/1.6.5).
- Any bug discovered during this E2E that's in-scope for the Story gets fixed in this Subtask's PR; anything out-of-scope is logged to
PRODECT_FINDINGS.mdper mistake #27.
Context refs
tests/e2e/shell-flows.spec.ts(1.5.6) +tests/e2e/jobs-flow.spec.ts(1.6.6) — the journey-driven Story E2E shapetests/e2e/_helpers/shell-session.ts— the lift-helpers patterntests/e2e/shell-a11y.spec.ts(1.5.5) — extension surface for the new routeplaywright.config.ts— current webServer + env-gate setupPRODECT_FINDINGS.md— finding-protocol per mistake #27