6.1 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. No /v1 mocks are needed. A spec fails if any /v1 call
is made.
Catalogue spec (pure data, no mount, imports web/src/data/apiCatalogue.ts):
- 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.
- Every catalogue route has a non-empty
description. An empty or missing one fails the spec and names the route. - 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.
- 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, next_cursor, counts (all, unused, duplicates);
- 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.
- 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:
formaton every article route, and q, hash, cursor, filter, sort, limit on GET /v1/media/. - 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.
- 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:
- 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".
- 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, the "JavaScript" CodeBlock, and the Errors list with 400 and 401.
- Copied: base URL: fake timers; click Copy. Clipboard gets the origin; check icon and "Copied"; announced; reverts after 2 s.
- Copied: CodeBlock: expand a card; click "Copy JavaScript example". Clipboard gets that code, only that button reads "Copied", and it reverts after 2 s.
- Authentication: both cards, curl/fetch tabs for GET /v1/auth/me, the "Manage API keys" link href /integration/api-keys, Note 1, Note 2.
- 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.
- Errors: table rows 400, 401, 403, 404, 409, 429, 500 with the real strings and the 403 sample block.
- Navigation: clicking an index item sets aria-current and scrolls to its anchor; the mobile "Jump to" lists the same sections.
- 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.
- Notes: format note, image-prefix note, CORS note.
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: CodeBlock (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), CodeBlock 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).