Files
RenewCMS/features/relation_field_spa.qa.md
T

6.6 KiB
Raw Blame History

QA procedure: relation field in the SPA

Two parts. Part 1 is automated (Vitest component tests, task test:web). Part 2 is the visual gate (task visual:check). Part 3 is manual. The Go side is in relation_field_type.qa.md. Until task test:web exists, SPA tests are reported NOT RUN, never passing.

Part 1: automated (Vitest + Vue Test Utils)

Mock /v1 per test with the shapes below; no live server. A field is {"key","label","type":"relation","required","unique":false,"default":null,"min":null,"max":null,"options":[],"relation":{"content_type","kind"}} and every other field carries "relation": null.

Registry

  1. lib/fieldTypes: the relation entry has the properties of the registry outline (label, icon lucide:link, control RelationField, no unique/limits/default/choices, empty value per kind, sample null or []). An unknown type still falls back to text; a relation never does.
  2. Client validation table (single and many, required/optional, 0, "3", [3], duplicates, 51 ids) and the message map including the "not produced" rules.

Builder (one test per state) 3. Type gallery: Relation is the last tile; locked on a saved field with the other tiles dimmed. 4. New relation: the related-type select lists the other types (mock GET /v1/content-type), the help text, the three cards with the exact sentences, default "One to many" (proposed); choosing a type updates the sentences. 5. Preview outline: the kind change updates both sentences and the line · shown on Venue as the field "Events"; the example cards "Event" and "Venue" show the board's chips (Rue Verte hall, Open day, Lime plaster workshop, +1). Nothing about the inverse is in any request. 6. Save body: relation sent as {"content_type","kind"}, others "relation": null; a loaded field round-trips unchanged; no related type chosen blocks Save with the proposed message. 7. Saved relation: key, tiles, related type and cards are disabled; Label and Required editable; the proposed lock note shows. 8. Review: required relation + entries > 0 shows the flagged row and disabled "Apply changes" with no PUT; optional shows the clean row; required with 0 entries sends at once; making an optional relation required shows "Entries may not fit" with Apply enabled. 9. Server answers: 409 schema_incompatible and 422 invalid_field map to the existing flows. 10. Delete refused: 409 content_type_referenced shows the proposed copy and the type stays listed. 11. A non-owner/admin sees no builder.

Entry form (one test per state) 12. Single control: type "rue" -> only GET /v1/content-type/venues/entry?q=rue&page=1&size=... is sent (debounced, trimmed, stale answers ignored); rows show title and second line; pick sets the value to 3, one chip, "Unsaved changes", live message. 13. Many control: chips for [11, 12], "Search to add", the help line; add keeps order; x and Backspace remove; picked ids are not offered again; the 51st is blocked with the proposed message. 14. States: loading (skeleton after 150 ms), no match with "Clear search", empty type, 500, network error, 429 countdown, 401 redirect, 404 (all with the proposed copy where tagged), "Try again" re-sends only the search. 15. Missing target (optional and required), saving, keyboard (arrows, Enter, Esc, Tab, Backspace), required-empty error and focus order (first invalid field only). 16. Outline "What the control shows and sends" (all 7 rows) and the create payload with venue: null, speakers: [] and with a picked number. 17. Dirty tracking: back to the original value gives "Saved"; reordered many ids count as changed. 18. Server answers table: required, type, unique, unknown_field (reload alert), each with the right copy, chip and focus. 19. Layout: a relation after boolean/number/date never pairs.

List 20. Cell outline (one chip, two chips, two chips + "+2", dash for null, dash for [], missing chip) from each item's relations with no extra request; relation columns are not sortable (no sort icon, no aria-sort). 21. Desktop grid for items 42/41/40 matches the board texts; the mobile card shows the labelled lines; the Columns menu lists Venue and Speakers with the link icon and the cap of 6. 22. Plain text of a relation cell never shows the numeric id; a first-field relation keeps the link and the "Entry N" title.

Accessibility 23. Combobox/listbox roles and attributes, chip group label, "Remove X from Y" button names, required/invalid/describedby wiring, the live region texts.

Part 2: visual (task visual:check -- <screen>)

Hard gate: each capture within 10 % at 1440x900 and 390x844, light and dark. Add setups in web/visual/states.ts with the board's own sample data; no clock-sensitive state exists in this group.

Screen State Board sample data the mock must reuse
schema Relation in the builder Events with Venue (label), key venue, related type Venue, "One to many" selected, preview sentences, example cards with chips "Rue Verte hall", "Open day", "Lime plaster workshop", "+1"
entry (content/events/42) Relation in the entry form Title "Lime plaster workshop" (21 / 80); Venue search "rue" with rows "Rue Verte hall / Lyon · 120 seats", "Rue Verte yard / Lyon · outdoor", "Rue du Port studio / Nantes · 24 seats"; Speakers chips "Ines Duarte", "Jonas Pereira"; help "An event can have many speakers."
content (events) Relation in the list Items 42 "Lime plaster workshop" 21 Nov 2026 (Rue Verte hall; Ines Duarte, Jonas Pereira, +2), 41 "Heat pumps: what the numbers say" 3 Nov 2026 (–; Jonas Pereira), 40 "Open day at the Rue Verte site" 12 Nov 2026 (Rue Verte yard; –)

Notes:

  • The board's states are drawn with a "Later" badge; the SPA does not render it. Expect a pixel difference at the badge. If the 10 % gate fails because of it, the user decides on a documented exception (approvedBy); the QA never adds one.
  • The board's builder shows a four-tile gallery plus Relation; the SPA shows the full gallery. The mismatch is reported to the user, not worked around.
  • States tagged "(proposed copy)" (loading, no match, error, missing chip, locked inspector, review refusal, delete refusal) are not on the board and get Vitest tests only, no visual capture.

Part 3: manual (screenshots can't cover)

  • Keyboard and focus order across the combobox, chips and list; screen reader announcements of the live region.
  • Hover and motion of the popover and of the chips' x; the mobile bottom-sheet versus under-input choice.
  • Real SQLite end to end with the built binary: build the type pair, pick, save, reload, delete a target and see the missing chip.
  • bunx playwright install chromium the first time on a machine.