Files

6.3 KiB

QA: Integration screen (API reference)

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

Mount IntegrationPage inside DashboardShell with a resolved verified session and a test router at /integration. Stub window.location.origin to https://cms.renew.example (the board's sample) and navigator.clipboard.writeText per case. Mock only GET /v1/image-variants (see integration_images.qa.md). A spec fails if any other /v1 call is made.

Catalogue spec (pure data, no mount, imports web/src/data/apiCatalogue.ts):

  1. The catalogue holds exactly the 20 expected key-callable routes from an explicit hand-maintained list in the spec (Articles 7, Media 6, Users and invites 6, Settings 1), each once, with no other expandable route. Session only has the 13 rows and Public auth flow the 6 rows listed in the feature, from the same kind of explicit list.
  2. Every catalogue route has a non-empty description. An empty or missing one fails the spec and names the route.
  3. Every route has method, path, access chip, key chip, a query-parameter list and a body-field list (possibly empty), and fetch, curl and Response examples.
  4. The Response sample of each route parses as JSON and uses only keys from a fixture of the real fields:
    • article: id, title, body, body_format, is_online, created_at, updated_at;
    • media item: id, filename, url, size, content_type, width, height, sha256, uploaded_by, created_at, used_in, duplicate;
    • media list: items, total, page, size, counts (all, unused, duplicates), no next_cursor;
    • merge: articles_updated, merged;
    • usage: id, title, published;
    • user list item: id, kind, username, display_name, email, role, status, created_at;
    • invite: id, kind, email, status, created_at, expires_at;
    • settings: version. Any other key fails the spec. "images" and "status" are explicitly rejected on articles.
  5. Request-body tables equal the validate tags (title 3-200, body optional with no length limit, filename, keep_id, merge_ids, display_name, email). The multipart field is "file". Query tables: format on every article route, and q, hash, cursor, filter, sort, limit on GET /v1/media/.
  6. The three invite routes carry "Owner only", a 403 "Only the owner can do this." caption and the rate-limit sentence. No /v1/system route is in an expandable group. Login, Log out, Register and Reset password rows carry no 403 claim. Verify, DELETE /auth/register, /api-key/* and /system/* are the only rows that claim 403.
  7. Error captions equal fixtures copied from api/pkg/apperr/messages.go and the image domain errors (413, 415, 400 on upload).

Component specs, one per design state:

  1. Default: breadcrumb, title "API reference", description, intro, Base URL equals the stubbed origin, all cards collapsed (aria-expanded "false"), section index entries present, the three invite rows show "Owner only".
  2. Group scrolled, one card expanded: click the POST /v1/article/ row. Assert the Query parameters table above the Request body table, the body rows, tabs fetch/curl/Response with fetch active in one CodeSnippet, and the Errors list with 400 and 401.
  3. Copied: base URL: fake timers; click Copy. Clipboard gets the origin; check icon and "Copied"; announced; reverts after 2 s.
  4. Copied: CodeSnippet: expand a card; click "Copy code". Clipboard gets the active tab's code, only that button reads "Copied", and it reverts after 2 s.
  5. Authentication: both cards, a CodeSnippet with curl/fetch tabs for GET /v1/auth/me, the "Manage API keys" link href /integration/api-keys, Note 1, Note 2.
  6. Session only: the corrected banner; lock icon and "Session only" chip only on rows that answer 403; the caption on the login family; no expand control; the "Public auth flow" rows with the "Public" chip.
  7. Errors: table rows 400, 401, 403, 404, 409, 429, 500 with the real strings and the 403 sample block.
  8. Navigation: clicking an index item sets aria-current and scrolls to its anchor; the mobile "Jump to" lists the same sections.
  9. Tabs: curl and Response render for a card. curl contains the stubbed origin and the Authorization header only on non-public routes. Not visually checked.
  10. Notes: format note, image-prefix note, CORS note.
  11. Base URL and error sample: both are CodeSnippets (single tabs "Base URL" and "Error response · text/plain").

Visual (task visual:check -- integration, desktop and mobile, light and dark)

Reference: docs/design/screens/integration.md; board "Integration" drawn by docs/design/source/IntegrationPage.dc.html. Serve the SPA under https://cms.renew.example. Mocks reuse the board's script data: BASE, KEY, group and endpoint descriptions, the request bodies (for example the "Choosing tiles for a small bathroom" article). Response samples are not compared; the Response tab is never active in a board frame.

Pre-approved exceptions: the user pre-approved visual exceptions for Session only, Group scrolled one card expanded, Errors and Default. For each of these four states the coder measures the real diff, sets the smallest maxPercent that is sufficient, writes the reason, and records approvedBy "Florian Sylvain". The other states must still pass 10 %.

  • Default (exception: owner-only chips and rate-limit line)
  • Group scrolled, one card expanded (exception: Query parameters table)
  • Copied: base URL (must pass 10 %)
  • Copied: CodeSnippet (must pass 10 %)
  • Authentication (must pass 10 %; Note 1 text changed)
  • Session only (exception: banner, 13th row, captions, Public auth flow block)
  • Errors (exception: 409 row)
  • Navigation (must pass 10 %)

None of these states is clock-sensitive, so none is skipped.

Manual

  • Keyboard and focus order: index, Base URL Copy, each row (Enter/Space), tab strip (arrow keys), CodeSnippet Copy, the pre (tabindex 0), Jump to on mobile.
  • Hover and motion on ghost Copy buttons and rows.
  • Find-in-page and a deep link to an #ep-... anchor.
  • Real origin in a production build and under task dev.
  • Run each documented example against a running server with a real rcms_ key, including the 403 on a session-only route and the owner-only 403 for an admin key on the invite routes. This needs a real server and is not automated.
  • docs/api.md matches the catalogue (hand check).