102 lines
11 KiB
Markdown
102 lines
11 KiB
Markdown
# QA: Media field usage in the Media library (slice C)
|
|
|
|
Runner: Vitest + Vue Test Utils (`task test:web`). No Go test and no Go change: the usage API is covered by features/media_field_type.qa.md. Kit: extend the Media view test kit with
|
|
- the library list (`GET /v1/media/?page=&size=&q=&filter=` with `items`, `total`, `counts`);
|
|
- `GET /v1/media/{id}/usage` fixtures:
|
|
- image 10 `bathroom-tiles.png`: 3 entries (Events), `used_in` 3;
|
|
- image 11 `lime-plaster.jpg`: 2 articles ("Open day at the workshop" online, "Restoring lime plaster" draft) plus 5 Events entries (first three: first_field text "Lime plaster workshop", "Heritage stone walk", "Winter open day"), `used_in` 7;
|
|
- image 1 `north-wall.jpg`: 2 articles, `used_in` 2;
|
|
- image 8 `window-frame.jpg`: `used_in` 0;
|
|
- an author-and-site-only image, `used_in` 2;
|
|
- entry items of every `first_field.type`, plus items with no `first_field`;
|
|
- failures: 500, network, 429, 404, 401.
|
|
|
|
Pin the time zone; never freeze the system date. No state of this slice depends on the clock.
|
|
|
|
Decisions accepted by the user (all as the feature draft assumes):
|
|
- D1 split source for the tooltip: lazy `/usage` fetch, SPA-only.
|
|
- D2 wording of the card name and the table column: "used in N places", underlined "Used in N" button.
|
|
- D3 title derivation: reuse `describeCell` and `plainCellText`.
|
|
- D4 truncation: one line, ellipsis, native title.
|
|
- D5 usage failure: inline message with "Try again" in the panel, silent tooltip.
|
|
- D6 usage loading: skeleton after 150 ms, delete dialog opens at once with a generic description.
|
|
- D7 authors and sites in the usage: filtered out, heading counts articles only.
|
|
- D8 bulk delete: "N places".
|
|
- D9 merge: "N places".
|
|
- D10 entry rows in the delete dialog are not links.
|
|
- D11 mobile panel as drawn.
|
|
- D12 visual gate setup.
|
|
|
|
## Automated
|
|
|
|
Pure logic (lib/__tests__, it.each over the feature's Examples):
|
|
1. `splitUsage(items)`: articles are those with `type === 'article'`, entries those with `type === 'entry'`, authors and sites are counted by neither. Entry rows keep API order, the first 3 are kept, `more` is the rest (0, 1, 2, 117). An absent array gives zeros.
|
|
2. `usageEntryTitle(item)`: the table "Entry title from first_field" for text, richtext (empty and Markdown), number (0 and 1500), boolean, date, select, media and null, empty string, absent first_field and an unknown type (falls to the default case of `describeCell`). It reuses `describeCell` and `plainCellText`; no second title rule exists. `entryTitle` itself is unchanged and its existing specs pass untouched.
|
|
3. Wording helpers: pluralEntries ("1 entry", "5 entries"), usage description by case (articles+entries, singular forms, articles only unchanged, entries only, usage unavailable fallback), `usedInLabel` for the card name ("used in 1 place", "used in 7 places", "unused").
|
|
4. Tooltip lines: entries only gives one line, both gives articles first, articles only gives one line, authors or sites only gives none.
|
|
|
|
MediaCardBadges, MediaTable, MediaGrid, MediaCardList (components/__tests__):
|
|
5. Badge label for used_in 0, 1, 3, 7. Outline kind, no icon. Same label in the grid card, the list row (underlined button in the table, badge in the mobile card) and the mobile card.
|
|
6. Tooltip: hover on the badge (`pointerenter`) fetches `/usage` once and opens with the right lines for the three splits; focus on the grid card opens it; Escape and blur close it without closing the panel; no fetch for `used_in` 0; no tooltip on mobile (viewport helper 390); nothing opens while the request is pending, and it opens on answer if the pointer is still there; failures (500, network, 404, authors-only) leave no tooltip; the usage is cached per image and cleared on reload of the list.
|
|
7. Card `aria-label`: the three names of the feature, replacing the "used in 2 articles" assertions in the existing specs; update those specs and change nothing else in them.
|
|
8. Table: the "Used in" cell is the underlined button "Used in N" (`data-testid="media-used-in"` kept) that opens the panel; "Unused" badge at 0.
|
|
|
|
MediaDetailPanel (components/__tests__/MediaDetailPanel.spec.ts, views/__tests__/MediaView*.spec.ts):
|
|
9. Articles and entries: heading "Used in 2 articles" built from the articles of the usage, not from `used_in`; article rows unchanged; "Used in entries" heading and 3 rows with type name, title link to `/content/<key>/<id>` and the arrow icon; "and 2 more" as plain text; the counts table (1, 3, 4, 5, 120 entries); row heights 36 px (desktop) and 48 px (mobile) as classes.
|
|
10. Entries only: heading "Not used in any article" with "No article shows it."; articles only: no entries section and the panel as before; unused: "safe to delete" line and no `/usage` request; authors and sites only: "No article shows it." and no list.
|
|
11. Preview aspect: 16:10 desktop and 4:3 mobile without entries, 16:6 desktop and 16:3.6 mobile with entries (classes, after the usage answers).
|
|
12. Loading: nothing before 150 ms, the three-row skeleton after, the real sections after the answer; fake timers only for the 150 ms delay, never the date. Failure: 500, network and 429 show "Couldn't load where this image is used." with "Try again" that repeats only `/usage`; 404 runs the existing gone flow; 401 is left to the global redirect; Delete stays enabled; switching images ignores the late answer.
|
|
13. Long title and long type name: one line, ellipsis classes, native title attribute on the link, row height unchanged.
|
|
14. Focus and tab order: article links, then entry links; the ring classes on a link; "and 2 more" not focusable.
|
|
|
|
DeleteMediaDialog (components/__tests__/DeleteMediaDialog.spec.ts):
|
|
15. The description table (2/5, 1/1, 2/0, 0/3, 0/0), the title for in use vs unused, the body order (entries list with heading and "and 2 more", then the articles list), the buttons, the variants note kept, no link in the entry rows.
|
|
16. Usage not ready (pending, failed): the generic description, no lists, "Delete image" enabled; when the usage answers while open the copy and lists switch and the focus stays.
|
|
17. Delete flow (confirm, in progress, failed, done, 404) runs unchanged; Cancel and Esc return focus to the Delete button of the panel.
|
|
|
|
BulkDeleteMediaDialog and MergeMediaDialog:
|
|
18. Bulk description counts "places" and uses "which will show a broken image or a missing-image notice."; rows and badges unchanged; no `/usage` request.
|
|
19. Merge dialog says "N places will be updated" and "Kept · used in N places now"; the toast stays "N copies merged. M articles updated.".
|
|
|
|
Cross-cutting:
|
|
20. French: every new string has an entry (the i18n completeness spec passes).
|
|
21. Regression: the existing Media view specs pass unchanged except the assertions named in 7, 18 and 19; if any other spec needs an edit, stop and report.
|
|
|
|
## Visual (task visual:check -- media)
|
|
|
|
In scope: the 4 states of the board group "11 Media library: usage" of RenewCMS Screens Schema.dc.html (they draw MediaFrame, and the copy list gives them the sample data). Every capture must be within 10 %, desktop and mobile, light and dark. Out of scope: states whose setups exist already and whose data does not change (they must keep passing untouched), and the picker states of slice B.
|
|
|
|
Prerequisites in web/visual, no change under docs/design (decision D12):
|
|
- `check.ts`: add the source `{ board: 'RenewCMS Screens Schema.dc.html', group: '11 Media library: usage', states: [the four below] }` to `extraSources.media`. The group differs from the screen's primary group ("Media"), so no merge change is needed.
|
|
- `states.ts`: the four setups, with the media API mock extended by `GET /v1/media/10/usage` and `GET /v1/media/11/usage` (shapes above). Existing media states keep their data, so `used_in` stays articles-only there.
|
|
- Board data:
|
|
- image 10 bathroom-tiles.png, 3 entries, `used_in` 3;
|
|
- image 11 lime-plaster.jpg, 2 articles and 5 entries, `used_in` 7;
|
|
- the grid also holds an unused image, so "Unused" shows in the captures.
|
|
|
|
| Board state | Setup in web/visual/states.ts | Board sample data |
|
|
|---|---|---|
|
|
| Grid: usage badge tooltip | /media with ent counts; step: hover the badge of image 10 (desktop), wait for the tooltip; mobile shows the grid with no tooltip | "Used in 3", tooltip "Used in entries: 3", "Unused" |
|
|
| List view: usage badge | /media?view=list; desktop table, mobile cards | "Used in 3", "Used in 7", "Unused" |
|
|
| Detail panel: used in entries | step: open image 11; wait for the entries list | "Used in 2 articles", "Used in entries", Events + "Lime plaster workshop", "Heritage stone walk", "Winter open day", "and 2 more" |
|
|
| Delete: image used by entries | step: open image 11, activate Delete; wait for the lists | the title, the description of 5 entries and 2 articles, both lists, "Cancel", "Delete image" |
|
|
|
|
Board caveats to report, never hide:
|
|
- The desktop table of the board draws `usedLink` with `pl(im.used)` (articles only). It shows "N articles" for lime-plaster.jpg and "Unused" for bathroom-tiles.png, while the written spec 3.8 says the list row carries the same badge. The spec follows the written text (D2); if the desktop capture of "List view: usage badge" exceeds 10 % the exception needs the user's explicit approval (`approvedBy`).
|
|
- The board draws the entry rows in the delete dialog as underlined links with the arrow icon; the spec renders plain rows (D10). If a capture exceeds 10 %, report it before changing the choice.
|
|
- The tooltip is drawn at a fixed place (left aligned, 26 px below the badge); a Nuxt UI tooltip may centre it. Use the `align` and offset that match the frame.
|
|
- The board titles ("Lime plaster workshop") come from the setup's `first_field` values, not from a title field.
|
|
- Clock-sensitive: none of the four states shows a relative date.
|
|
|
|
## Manual
|
|
|
|
- Real backend, owner and a second verified user: upload an image, use it in an article and in two entries through a Media field, and read "Used in 3" in the grid, list and mobile card. Hover and focus the badge for the tooltip, and check that a card with no entries shows "Used in articles: N" only.
|
|
- Open the panel: the entries link opens /content/<key>/<id> and shows the right entry. Add a fourth entry and read "and 1 more". Delete the entry and reload: counts fall.
|
|
- Delete the image from the panel with the dialog open: read the real counts, confirm, then open one of the entries and see "This image is no longer in the library" with the id kept.
|
|
- Throttle or kill the network while opening the panel and the dialog: the error line, "Try again" and the generic delete description.
|
|
- An image used only by an author or a site: no "safe to delete" claim anywhere.
|
|
- Keyboard: tab order across card, badge tooltip (focus), panel links and dialog buttons; Escape closes the tooltip first, then the panel; the focus return after Cancel; screen reader reads the card name, the tooltip and the lists.
|
|
- Motion and hover: the tooltip opening and closing, the skeleton fade at 150 ms, no layout jump larger than the preview change when the usage answers.
|
|
- Mobile: the full-screen panel, 48 px rows, the bottom-sheet dialog, 44 px targets, no tooltip.
|
|
- Contrast of the tooltip pair and of the muted type name in light and dark.
|