Jobs: render-parity fixture + goldens for the two-screen create flow #234

Open
opened 2026-08-25 01:52:12 +00:00 by nalum · 0 comments
Owner

Follow-up to #180. The two-screen job creation flow (handoff §8, web/src/components/NewJobSheet.tsx / Android's NewJobSheetContent in Jobs.kt) shipped with no render-parity fixture and no gallery/Roborazzi goldens. The commit that built it said why:

Not done: no new render-parity/screenshot-golden fixture for the two
screens ... that fixture format fits a presentational card, not a
stateful two-screen wizard with async submit, and building it well is
a separable follow-up.

#180's coverage check re-examined that judgment rather than assuming it. It holds up:

  • Every existing render-*.json family (render-job.json, render-job-sheet.json, render-job-pickers.json, render-field-row.json) poses a case by handing the component a server-shaped object (a job, a sheet, a picker's linked rewards) and rendering it once. render-job-sheet.json already reaches nested UI (⋯, the repeat sheet, the delete/tick dialogs) by clicking through from that posed state (OPEN_PATHS / openPath, conformance/README.md), but the object being posed is still a fully-formed one the server could have produced.
  • The create flow has no such object. Both NewJobSheet (web) and NewJobSheetContent (Android) hold the draft entirely in local state — useState/remember { mutableStateOf(...) } for title, ownerUid, date/time, description, repeat, pointsMode/pointsValue, rewardPick, subJobs, plus screen and picker — built up by typing and picker taps, with no prop or parameter that accepts a starting draft. Posing "screen two, worth filled in, two sub-jobs queued" means either simulating every keystroke that produces it, or adding an injection seam that does not exist for any other reason today.
  • The flow's terminal action is an async Create RPC (client-minted UUIDv7, best-effort sub-job creates and reward link after) that navigates to the new job's detail sheet on success. Existing fixtures never cross a commit boundary — render-job-sheet.json's cases mock mutate/mutateGroup as inert specifically so nothing async has to be waited on. A create-flow fixture would need the same discipline (pose pre-commit render states only) stated explicitly, since it is the flow's whole point in a way it isn't for the sheet.

None of that is a reason to leave the gap open indefinitely — it's a scope description for the fixture that's actually needed. Proposed shape:

  1. A new family, conformance/render-job-create.json. Each case carries a draft object (the fields above) and a screen: 1 | 2, not a server entity — a genuinely different shape from every existing render-* family, so it earns its own conventions section in conformance/README.md rather than reusing render-job-sheet.json's.
  2. A narrow, clearly-test-only way to seed that draft — an initialDraft prop/parameter on NewJobSheet / NewJobSheetContent (or a thin wrapper used only by the test harness and the gallery page, the way JobSheetCaseView/JobSheetCase wrap the real sheet today) — not a product affordance, and not reachable from the real create button.
  3. Cases pose render states only, never a commit: screen one empty, screen one with a day chip selected, screen one with a title typed and a validation/won't-commit state if one exists, screen two reached via More, screen two with repeat/worth/description/sub-jobs populated, and the Worth picker's "Make a new one" state (it reuses JobPickers.tsx/JobPickers.kt, already fixture-covered generically by render-job-pickers.json, so this case only needs to confirm it merges correctly inside the create flow's own chrome).
  4. Wire both suites per conformance/README.md's existing rule ("adding a fixture family means wiring both sides") — web vitest, Android RenderConformanceTest, gallery screens.spec.ts + Android ScreenshotTest (Roborazzi) — and add the family to web/tests/fixtures.test.ts's CONSUMED list, which currently fails the build on any unconsumed fixture file.

Labeling area/jobs, area/testing, enhancement.

Follow-up to #180. The two-screen job creation flow (handoff §8, `web/src/components/NewJobSheet.tsx` / Android's `NewJobSheetContent` in `Jobs.kt`) shipped with no render-parity fixture and no gallery/Roborazzi goldens. The commit that built it said why: > Not done: no new render-parity/screenshot-golden fixture for the two > screens ... that fixture format fits a presentational card, not a > stateful two-screen wizard with async submit, and building it well is > a separable follow-up. #180's coverage check re-examined that judgment rather than assuming it. It holds up: - Every existing `render-*.json` family (`render-job.json`, `render-job-sheet.json`, `render-job-pickers.json`, `render-field-row.json`) poses a case by handing the component a **server-shaped object** (a job, a sheet, a picker's linked rewards) and rendering it once. `render-job-sheet.json` already reaches nested UI (`⋯`, the repeat sheet, the delete/tick dialogs) by clicking through from that posed state (`OPEN_PATHS` / `openPath`, `conformance/README.md`), but the object being posed is still a fully-formed one the server could have produced. - The create flow has no such object. Both `NewJobSheet` (web) and `NewJobSheetContent` (Android) hold the draft entirely in local state — `useState`/`remember { mutableStateOf(...) }` for `title`, `ownerUid`, `date`/`time`, `description`, `repeat`, `pointsMode`/`pointsValue`, `rewardPick`, `subJobs`, plus `screen` and `picker` — built up by typing and picker taps, with no prop or parameter that accepts a starting draft. Posing "screen two, worth filled in, two sub-jobs queued" means either simulating every keystroke that produces it, or adding an injection seam that does not exist for any other reason today. - The flow's terminal action is an async `Create` RPC (client-minted UUIDv7, best-effort sub-job creates and reward link after) that navigates to the new job's detail sheet on success. Existing fixtures never cross a commit boundary — `render-job-sheet.json`'s cases mock `mutate`/`mutateGroup` as inert specifically so nothing async has to be waited on. A create-flow fixture would need the same discipline (pose pre-commit render states only) stated explicitly, since it is the flow's whole point in a way it isn't for the sheet. None of that is a reason to leave the gap open indefinitely — it's a scope description for the fixture that's actually needed. Proposed shape: 1. A new family, `conformance/render-job-create.json`. Each case carries a `draft` object (the fields above) and a `screen: 1 | 2`, not a server entity — a genuinely different shape from every existing `render-*` family, so it earns its own conventions section in `conformance/README.md` rather than reusing `render-job-sheet.json`'s. 2. A narrow, clearly-test-only way to seed that draft — an `initialDraft` prop/parameter on `NewJobSheet` / `NewJobSheetContent` (or a thin wrapper used only by the test harness and the gallery page, the way `JobSheetCaseView`/`JobSheetCase` wrap the real sheet today) — not a product affordance, and not reachable from the real create button. 3. Cases pose render states only, never a commit: screen one empty, screen one with a day chip selected, screen one with a title typed and a validation/won't-commit state if one exists, screen two reached via `More`, screen two with repeat/worth/description/sub-jobs populated, and the Worth picker's "Make a new one" state (it reuses `JobPickers.tsx`/`JobPickers.kt`, already fixture-covered generically by `render-job-pickers.json`, so this case only needs to confirm it merges correctly inside the create flow's own chrome). 4. Wire both suites per `conformance/README.md`'s existing rule ("adding a fixture family means wiring both sides") — web vitest, Android `RenderConformanceTest`, gallery `screens.spec.ts` + Android `ScreenshotTest` (Roborazzi) — and add the family to `web/tests/fixtures.test.ts`'s `CONSUMED` list, which currently fails the build on any unconsumed fixture file. Labeling `area/jobs`, `area/testing`, `enhancement`.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
eagraiclainne/app#234
No description provided.