Files
RenewCMS/features/articles_pagination_screen.qa.md

5.1 KiB
Raw Permalink Blame History

QA: Articles list pagination (SPA)

Automated (Vitest + Vue Test Utils, task test:web)

Mock useApi for GET /v1/article/?format=html&... (the route key includes the query) per case. Mount ArticlesPage inside DashboardShell with a verified session and a test router at /article, as in features/articles_list.qa.md. The fixture is 312 articles at 25 per page, built by a helper, with counts {all, online, draft}. No system date freezing.

  1. First page: no page/size in the URL, "Showing 1–25 of 312", First/Previous disabled, page 1 aria-current.
  2. Middle page: ?page=7 -> "Showing 151–175 of 312", aria-current on 7, ellipsis present.
  3. Last page: ?page=13 -> "Showing 301–312 of 312", Next/Last disabled.
  4. Single page: total 6 -> no paginator nav, summary "Showing 1–6 of 6", select present, tabs "All 6" "Online 4" "Drafts 2".
  5. Loading next page: unresolved page-2 promise -> skeleton rows, aria-busy, controls disabled, "Loading page 2…"; resolve -> rows, URL ?page=2 (URL unchanged before the response).
  6. Error (500 and network rejection): rows and URL (?page=6) kept, notice "Couldn't load page 7. Showing page 6.", Retry resends page 7, success clears the notice and sets ?page=7.
  7. Out of range: ?page=99 returns {items:[], total:312} -> router.replace to ?page=13 (assert no extra history entry), second request page=13, notice text. 7b: total 0 -> empty state, no redirect.
  8. Search resets: from ?page=7 type "plaster" (fake timers past 120 ms) -> request q=plaster&page=1, URL /article?q=plaster after the response, tab counts unchanged. Same assertion for tab, sort (request sort=title:asc&page=1) and size. 8a. Sort headers: for Title, Status, Created, Updated, a first click sends sort=:asc&page=1, the URL becomes /article?sort=:asc only after the response, the arrow icon shows and counts are unchanged. 8b. A second click toggles to desc; returning to updated_at:desc drops sort from the URL. 8c. Sort kept across Next, size change and search. 8d. A sorted URL on load (?sort=created_at:desc&page=2) sends it and shows the Created arrow-down; an invalid ?sort=body:asc sends no sort and the URL is replaced by /article. 8e. No client-side re-sorting: with the mock returning rows in a fixed order, the table shows exactly that order whatever the sorting state. 8f. Caption: default "Articles, sorted by last updated, newest first"; sorted by Title ascending "Articles, sorted by title, ascending"; French strings present. 8g. Mobile card list renders no sort control.
  9. Empty after search: paginator and summary absent, copy and "Clear search", tab counts unchanged.
  10. Page-size menu: 5/25/50/100 -> request and URL; ArrowDown opens, Enter selects, Esc closes and restores focus. 10b: ?size=10&page=abc -> request page=1&size=25, URL replaced.
  11. Focus-visible: the focus-ring tokens on every control (the pixel outline is a visual check).
  12. Tabs on the server: Drafts -> status=draft&page=1, counts unchanged.
  13. Mobile: below md, Previous / "Page 2 of 13" / Next, no numbers.
  14. Delete last row of last page: reloads the previous page, counts refreshed.
  15. HomeView, ArticleView and useArticles: with the envelope mocked, they render from items; no code path reads a bare array (a mocked bare array makes the test fail).
  16. Existing specs amended: features/articles_list.qa.md items 1-18 (search and tab counts server-driven, GET /v1/article/ mocked as the envelope), web/src/i18n/spa.spec.ts (mock around line 417), the ArticleTable specs that rely on client-side TanStack sorting, and the Home, ArticleView and Integration specs. List them in the diff.

Visual (task visual:check -- articles)

Add a setup per state in web/visual/states.ts, reusing the board's own sample data from group "Articles: pagination" in docs/design/source/RenewCMS Screens Back-office.dc.html (total 312, size 25, titles from the frame script), at 1440x900 and 390x844, light and dark; every capture within 10 %. States: First page, Middle page, Last page, Single page, Loading next page, Error loading a page, Page out of range, Search resets to page 1, Empty after search, Page size menu, Focus-visible. A state whose frame shows relative dates ("2 hours ago") is skip: 'clock-sensitive'; confirm per frame when coding. Take layout (summary vs paginator vs select, select opening upward) from the frame markup, not from components.md prose. The Articles group's existing states are re-run, since the list now comes from the envelope.

Manual

  • Keyboard order and focus return (Tab path, Enter/Space, ArrowDown/Enter/Esc), hover and motion (the skeleton pulse stops under reduced motion).
  • Keyboard activation (Enter/Space) of the sort headers and the screen-reader announcement of the sort direction (aria-sort).
  • The sorted-header arrow is part of the existing Articles board states; if a frame lacks it, raise it with the user rather than inventing a state.
  • Real round trip with task dev: page, size, q, status, total and counts from a live SQLite file; a reload keeps the URL state; browser Back after a size change.
  • Out-of-range redirect against a real shrinking list (delete rows in another tab).
  • Home and Article views against the real API after the envelope change.