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-65

1.6.6 Story-level E2E: real-failure → DLQ → operator replay → success path (closes the Story)

Done
Description

Estimate: 18m · Depends on: 1.6.5

The Story-closing E2E proves the runtime + the patterns + the dashboard hold together end-to-end against a forced failure. Same shape as Story 1.5.6 — a Playwright spec that drives the user-visible flow, plus a Vitest integration spec for the cross-job invariants.

Spec at tests/e2e/jobs-flow.spec.ts covers:

  • Happy-path workspace invite: sign in as workspace owner → invite a new email → assert the invite-acceptance email is enqueued (visible in the dashboard's "Recent runs" tab as a succeeded row); the dev-console email provider logs the email body.
  • Forced-failure path: a Playwright fixture flag makes lib/email.ts's dev-console provider throw deterministically for a specific recipient email pattern; invite that email → confirm the run appears as failed with attempts climbing to 3 → confirm a row lands in the DLQ tab → confirm the DLQ tab badge increments.
  • Replay path: clear the failure flag → click "Replay" on the DLQ row → confirm a new job_run row appears as succeeded → confirm the DLQ row shows a non-null replayed_at → confirm the email body now logs to the dev console.
  • Cross-workspace isolation: as a member of workspace A, navigate to /settings/workspace/jobs while workspace B is active → confirm zero runs visible even though workspace A has many. This catches RLS misses the Vitest tests can't (they run with a single connection).
  • Role gating: as a non-owner member of a workspace, the Replay button is disabled with a tooltip explaining the gate.
  • Empty-state path: a fresh workspace with no job runs shows the documented empty state for both tabs.

Vitest integration spec at tests/jobs/integration.test.ts covers the cross-cutting invariants that don't surface via the browser:

  • The system.daily-health-check scheduled job, manually fired via the in-process harness, writes the expected synthetic-event job_run row.
  • Idempotency: firing the same email.send event twice with the same idempotency key results in exactly one job_run row and exactly one sendEmail invocation.
  • The DLQ replay does NOT bypass the idempotency window (a replay within 24h is a no-op against the original idempotency key — this is the "replay-after-fixing-the-underlying-bug-but-the-key-is-still-deduped" trap that real ops surfaces hit; document the workaround inline with the test).

Story-level verification recipe (manual, ≤12 minutes): pull main; pnpm install && pnpm dev + npx inngest-cli dev; walk the spec's scenarios interactively in the browser, spot-checking that the Inngest dev UI shows the same runs the dashboard does (the two surfaces should agree on every visible run).

If any scenario fails: fix in this Subtask if it's a Story-level regression; log a finding if it points at a deeper service-layer issue (per mistake #27).

Acceptance criteria

  • tests/e2e/jobs-flow.spec.ts covers every bullet in the scenario list; each scenario is its own test() block.
  • Forced-failure scenario uses a Playwright fixture flag to make lib/email.ts's dev-console provider throw deterministically; the flag scope is per-spec, not global.
  • Replay scenario asserts the DLQ row's replayed_at changes from null to a timestamp, AND a fresh succeeded job_run appears.
  • Cross-workspace isolation scenario uses the existing two-workspace fixture from Story 1.2; asserts zero runs visible when active workspace doesn't match the run's workspace.
  • Role-gating scenario reuses the existing owner/member fixture pair; verifies the disabled state + tooltip.
  • Vitest integration spec at tests/jobs/integration.test.ts covers: scheduled job firing; idempotency dedup across duplicate sends; DLQ replay vs idempotency-window interaction (with the documented workaround).
  • Story-level verification recipe reproduces locally in ≤12 minutes (includes the Inngest dev-server startup time).
  • All quality gates green; existing E2E suite (auth + workspace-flows + projects-flow + work-items-isolation + shell-a11y + shell-keyboard + shell-flows + jobs-dashboard) stays green; the new spec runs alongside without flake.
  • Any cross-Subtask issue surfaced during verification logged in PRODECT_FINDINGS.md.

Context refs

  • tests/e2e/workspace-flows.spec.ts + jobs-dashboard.spec.ts — existing patterns to mirror
  • tests/e2e/_helpers/db-reset.ts + email-capture.ts — the reset + email-inspection helpers
  • The full jobs stack (lib/jobs/*, the serve route, the dashboard page, the email job)
  • The Story 1.2 two-workspace fixture pattern; the Story 1.5 a11y + keyboard specs (to extend, not duplicate)