4.1 KiB
4.1 KiB
QA: First-time language setup
Accepted together with features/language_setup.feature.
Automated, no server (task test)
- Use case over in-memory fakes: "Apply for every pending site", "The owner may change a suggestion", "Retrying is safe", "A site with no articles still needs confirming", refused rows. Assert sentinels with errors.Is. Assert that the whole apply is one Transactor call and that site-row locks are taken in ascending site id order.
- HTTP: NewHandler over the use case, a fresh chi.NewRouter mirroring api/router.go under /v1/language, behind require(role.KeySettingsManageSites), validator.InitValidator(), httptest. Cover 200, 400, 401, 403, 404, 409 and 422 with exact plain-text bodies and the JSON key set. setup_in_progress is simulated by a fake whose apply returns the sentinel.
- Regression: slice 1 tests ("Create racing a confirmation", "Assigning a language is idempotent") untouched.
Automated, SQLite file (task test)
- Fixture: the four sites above with 8, 3, 5 and 0 articles, one soft-deleted. POST applies; assert ids, titles, bodies, slugs, is_online, story ids and timestamps unchanged; soft-deleted articles are assigned too; no pending site remains; a second POST changes nothing (hash of all rows). A site created after migration with no row is listed and can be confirmed.
- Atomicity: inject a failing write on the second site; assert no row is confirmed and no article is assigned; the next POST completes.
- Concurrency: goroutines creating articles during setup; every final lang equals the confirmed tag; bound the SQLITE_BUSY retries. Two concurrent POSTs: one 200, the other 200 or 409 setup_in_progress, never a deadlock.
Automated, real databases (task test:mysql, task test:postgres)
- One targeted run of steps 4 to 6 on MySQL 8.4, MariaDB 11 and PostgreSQL, sharing the run planned in the site_languages QA. Check lock ordering for deadlocks. Record NOT RUN if the daemon is down, or use the podman shim.
Automated (Vitest + Vue Test Utils, task test:web)
- One spec per row of "Setup states". Assert the copy, the disabled confirm button until every row has a language, that Journal and Archive are seeded and Notes is not, the single POST body, and the 409 / 500 transitions.
- Mock set: GET with Journal, Notes, Archive (8, 3, 5 articles); GET with only Notes; GET with only Gallery; GET with nothing pending; GET with a substituted suggestion; POST 200 { assigned: 16 }; POST 409; POST 500.
- Route guard: a reader is redirected; an owner reaches the page; the back link goes to /settings/sites/:key/languages, and to Settings, Sites for an unknown :key.
- The Languages page banner links to /settings/sites/:key/languages/setup when needs_setup is true.
- task test:web, the type check, bun lint, and a diff check for comments.
Visual (task visual:check -- localization-site-languages, hard gate at 10 %)
- Run once at the end of the slice (group L2, 7 states) with the board fixtures Journal, Notes, Archive and Gallery (SETUP in locale-fixtures.js: 8, 3 and 5 articles). Desktop 1440 and mobile 390, light and dark.
- Not checked visually (no frame): nothing-pending, unknown :key, substituted seed.
Assumptions recorded for gaps without a frame
- Nothing pending: the Done alert without a count.
- Substituted seed: the Languages "broader" wording.
- Unknown or complete 🔑 the global list is shown and the back link falls back to Settings, Sites.
- Setup route: one global page (Option 1), reached from a per-site banner.
Fix round additions
- Skipped list and stable lock loop: TestLanguageSetupSkippedChoices, TestLanguageSetupLocksUntilStable (test/localization_fix_http_test.go).
- Setup activity events: TestLanguageActivity.
- Two simultaneous setups on SQLite: TestLanguageConcurrencyOnSQLite.
Manual
- Keyboard order and focus return after "Try again" and "Check again".
- Real two-owner run: start setup in two browsers and confirm the second sees "Setup is already running".
- A copy of a real database with articles: run setup, check the articles list and one public read still match, then restart and confirm nothing changes.