MotirBuilding in public
MOTIR · moooon
onMotir
You’re viewing a public project. Anyone can view it — no account needed. Sign in to submit, upvote, or comment on requests.View-only — you can’t edit work items
MOTIR-137

2.6.3 Full Epic-2 lifecycle integration scenario (vitest)

Done
Description

Estimate: 35m · Depends on: 2.6.1

Add tests/integration/work-items/epic2-lifecycle.test.ts — a single cross-story scenario that threads the whole Epic-2 lifecycle end to end, the integration journey no individual 2.x test owns (each owns a slice). All through workItemsService against real Postgres.

The scenario:

  1. Build a full tree honoring the kind-parent matrix: create an epic, a story under it, a task under the story, a bug under the task, and a subtask under the bug (exercising the legal parent chain to the 4-level depth cap; assert each lands with the right parentId, a gap-free per-project key, and a derived PROD-<n> identifier).
  2. Assign items to a workspace member (and confirm a non-member assignee is rejected with AssigneeNotInWorkspaceError — the assignee gate in a lifecycle context).
  3. Walk a representative item through a multi-hop status lifecycle under restricted policy: todo → in_progress → in_review → done, then a block/unblock detour (in_progress ↔ blocked), then a reopen (done → in_progress). Assert each hop validates and records an updated revision, and that an illegal jump mid-walk (e.g. todo → done) raises IllegalTransitionError without mutating status.
  4. Archive a leaf and assert the soft-delete leaves children intact (Linear shape — no cascade) and that the archived item drops out of the default list/tree reads.
  5. Assert the read surfaces reflect the final state: getProjectTree returns the nested forest with correct depths and the archived item excluded; getProjectIssuesList (paginated/filtered) returns the live items with the right statuses + assignees; isReady is correct for an item with/without open blockers.

This is an INTEGRATION scenario, not unit re-coverage — it asserts the pieces compose. Reuse the shared fixtures (do not re-inline helpers).

Acceptance criteria

  • New file tests/integration/work-items/epic2-lifecycle.test.ts; passes under pnpm test on real Postgres.
  • The full epic→story→task→bug→subtask chain is created through the service and asserted (parentage, gap-free keys, derived identifiers, depth).
  • The multi-hop status walk covers forward + block/unblock + reopen, each writing a revision; a mid-walk illegal transition is rejected without mutation.
  • Assignee gate exercised (member assigns; non-member rejected with AssigneeNotInWorkspaceError).
  • Archive leaves children intact and the item is excluded from getProjectTree + getProjectIssuesList defaults.
  • Final getProjectTree, getProjectIssuesList, and isReady reads assert the end state.
  • Uses tests/fixtures/* (no re-inlined setup); each describe/it names the behavior.

Context refs

  • lib/services/workItemsService.tscreateWorkItem, assignWorkItem, updateStatus, archiveWorkItem, getProjectTree, getProjectIssuesList, isReady
  • lib/workItems/errors.tsAssigneeNotInWorkspaceError, IllegalTransitionError, IllegalParentTypeError
  • tests/integration/work-items/{service,project-tree,issue-list-view}.test.ts — the sliced coverage this composes (do not duplicate)
  • tests/fixtures/{workItemFixtures,projectFixtures,workspaceFixtures,userFixtures}.ts, tests/helpers/db.ts
  • prisma/sql/work_item_triggers.sql — kind-parent / depth rules the create chain rides