5.6 KiB
QA: Entry list of a custom content type (SPA slice 6)
Runner: Vitest + Vue Test Utils (task test:web). No Go test: both endpoints and /v1/user/lookup already exist and the backend does not change. Kit: reuse views/__tests__/schemaTestKit.ts (add GET /v1/content-type/{key}, GET .../entry with page/size/sort, and /v1/user/lookup handlers; Events with the 7 fields and 7/37 entries of SchemaFrame.dc.html). Pin the time zone; never freeze the system date.
Automated
- Composable (useContentTypes.spec):
getContentType(key);listEntries(key, {page,size,sort})builds the query, returns {items,total,page,size,sort}, passes status and plain text through (403, 404, 500), NetworkError passes through.lookupUsers(ids)sends the distinct ids once and returns display names. - URL parsing (it.each): invalid/missing page, size, sort fall back to 1, 25, updated_at:desc and are replaced in the URL; defaults omitted; size and sort change reset page; the URL changes on success only.
- State 1 Populated: title, subtitle "events · 7 fields", toolbar, headers, first row values, "7 entries", no pager; singular "1 entry".
- State 2 Paginated (size=5, total 37): "Showing 1–5 of 37", "5 per page", pager; mobile "Page 1 of 8"; Next sends page=2 and updates the URL on success.
- Reuse of Articles pager behaviours (it.each): last page, loading page (aria-busy, disabled controls, "Loading page 2…"), error keeps rows with Retry, out-of-range redirect with notice, total 0 on out-of-range shows empty.
- Cells (it.each per field type): truncation, rich text first line, number alignment, Yes/No icon, date without shift, Choice tag, empty "–"; Created and Updated formats.
- Updated by: one lookup with distinct ids after the entries; "–" before it resolves, on failure and for an unknown id.
- State 3 Columns: popover on desktop (Reset only), sheet on mobile (Reset and Done); "4 of 6", sentence, rows with icon, label and key; the Created/updated row disabled; live column change with no request; cap at 6 with message and disabled rows; Esc/outside/Done close and return focus.
- Column persistence (it.each from the feature table): writes, Reset removes, unknown keys dropped, more than 6 truncated, invalid JSON, per-type keys, throwing/undefined localStorage, load never writes.
- Sort: the three options and the direction button (it.each), accessible names, URL and request, header arrow, sort kept across paging, invalid URL values replaced.
- State 4: with 14 types the sidebar shows 5 + selected + "Show all 14"; mobile drawer collapsed row "All content types 14" (sidebar logic itself stays in ContentNav.spec).
- State 5 Loading: skeleton rows (8 / 6), aria-busy, "New entry" disabled.
- State 6 Empty: copy, "New entry" navigates to /content/events/new, no pager.
- State 7 Error (500 and network): copy, "Try again" sends the failed request again; type-load failure variant.
- State 8 Forbidden (entries 403, type 403): copy, name fallback to the key, "Go to Home" goes to /home.
- State 9 Not found (type 404, entries 404): copy, breadcrumb "Content", no current sidebar row; deleted-type scenario.
- Navigation: New entry, first-cell links, mobile card link, "Edit content type" to /schema/events; hidden for a non-owner/admin and on mobile; mobile floating button hidden in loading and error.
- 401 redirect; stale answer dropped after a sort change; switching type resets page/size/sort and columns.
- Accessibility: caption text per sort, accessible names, keyboard on the picker and the select.
- French: every new string has an entry (i18n completeness spec passes).
Visual (task visual:check -- content)
Register the group "5 Content and entry list" in extraSources if not registered. Every capture within 10 %, desktop and mobile, light and dark. Nothing is clock-sensitive. Mock every /v1 call including the sidebar's GET /v1/content-type and /v1/user/lookup.
| Board state | Setup in web/visual/states.ts | Board sample data |
|---|---|---|
| 1 Populated | /content/events, 7 entries (ROWS of SchemaFrame.dc.html), owner session | "Lime plaster workshop", "Marta Alves", "events · 7 fields", "7 entries" |
| 2 Paginated, 5 per page | /content/events?size=5, total 37, 5 items | "Showing 1–5 of 37", "Page 1 of 8" (mobile) |
| 3 Columns menu | /content/events, step: click "Columns" | "4 of 6", Title, Starts on, Ends on, Online checked |
| 4 Many types | /content/events with 14 types (CT list of the board); mobile: open the drawer and expand the group | "Frequently asked questions and answers", "Show all 14" |
| 5 Loading | entries hang: true |
skeleton rows |
| 6 Empty | entries total 0 | "No entries yet" |
| 7 Error | entries 500 | "Couldn't load entries" |
| 8 Forbidden | entries 403 | "You don't have access to Events" |
| 9 Type not found | /content/unknown, type 404 content_type_not_found | "Content type not found" |
Board caveats to report, never hide: the mobile card shows a Category tag that the default 4 columns do not include; the desktop picker is drawn without Done; the mobile frames hide "Edit content type", so mobile has no path to the builder (design follow-up).
Manual
- Real backend, owner and a non-owner/admin if one exists: list a type with 37 entries; sort, page, change size; reload keeps the URL state.
- Columns: choose 6, reload, switch type and back; clear localStorage and see the default.
- Click "New entry" and a row: the 404 page is expected until the editor slice; Back returns to the list with its URL.
- Keyboard: tab order toolbar (select, direction, Columns, Edit), table links, pager; the picker and the sheet focus order; hover tooltip on truncated text.
- Delete a type in another tab, then reload /content/: not found page.