mirror of
https://github.com/azaion/ui.git
synced 2026-06-21 10:41:10 +00:00
[AZ-457] [AZ-459] [AZ-465] [AZ-481] Batch 2 - auth/enum/i18n/CI tests
Implements 22 blackbox test scenarios across the four batch-2 tasks:
AZ-457 - Auth & token handling (11 scenarios, fast + e2e):
- src/api/client.test.ts: FT-P-02, NFT-SEC-04, NFT-PERF-02, NFT-RES-01,
NFT-RES-08 (apiClient surface)
- src/auth/AuthContext.test.tsx: FT-P-01 (it.fails - Step 4 drift),
FT-P-03, NFT-SEC-01, NFT-SEC-02
- src/auth/ProtectedRoute.test.tsx: FT-N-04, NFT-RES-08 (router half)
- e2e/tests/auth.e2e.ts: FT-P-02 e2e, NFT-SEC-01/02/03 (cookie attrs
via Playwright context.cookies(), gated by suite stack)
AZ-459 - Wire-contract enums (4 scenarios):
- tests/wire_contract.test.ts: FT-P-04 (AnnotationStatus, it.fails),
FT-P-05 (MediaStatus + Affiliation it.fails; CombatReadiness skip
per verification_pending), FT-P-06 (AnnotationSource control +
spec value-set membership), FT-N-15 (typed-enum shape + skip for
value-set verification)
- e2e/tests/wire_contract.e2e.ts: FT-P-06 against real annotations/
service, drift-gated via AZAION_RUN_DRIFT_E2E
- scripts/run-tests.sh STC-FN15: ripgrep static for MediaType
magic-literal hygiene
AZ-465 - i18n (4 scenarios, all static + quarantined fast):
- scripts/check-i18n-coverage.mjs: FT-P-22 (en vs ua key parity) +
FT-P-23 (no raw user strings outside t() in src/**/*.tsx); refined
JSX text-node regex with negative lookbehind to drop TS generics
+ arrow-function false positives
- tests/i18n-allowlist.json: snapshot of current pre-existing raw
strings (CI gates growth per AZ-465 Constraints)
- tests/i18n.test.tsx: FT-P-24 + FT-P-25 it.skip (QUARANTINE - i18n
detector + persistence not wired today; control tests assert the
gap so the skip flips to a real test once Step 4 lands)
AZ-481 - CI image labels (3 scenarios, static against
.woodpecker/build-arm.yml):
- scripts/check-ci-image-labels.mjs: NFT-RES-LIM-11 (tag scheme
${CI_COMMIT_BRANCH}-arm), NFT-RES-LIM-12 (revision/created/source
PASS, image.title reported as DRIFT - foundation/CI-CD owns the
fix), NFT-RES-LIM-13 (revision = $CI_COMMIT_SHA)
Cross-cutting:
- scripts/run-tests.sh: src_grep now excludes *.test.{ts,tsx} +
*.spec.{ts,tsx} so production-source static checks (STC-SEC4,
STC-FN15, etc.) don't false-positive on test prose
- tsconfig.json: exclude src/**/*.{test,spec}.{ts,tsx} so production
tsc -b doesn't see jest-dom matchers
- _docs/03_implementation/batch_02_report.md: full per-task AC
coverage matrix + drift inventory + verification run
- _docs/_autodev_state.md: 22 tasks remain after batch 2
Verification (host):
fast : 7 files, 38 passed | 4 skipped (quarantined)
static : 19/19 checks PASS (was 13 in batch 1; +6 from batch 2)
e2e : not run on host (Risk 4 - requires suite docker stack)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
# Batch Report
|
||||
|
||||
**Batch**: 02
|
||||
**Tasks**: AZ-457 (auth & token handling), AZ-459 (wire-contract enums), AZ-465 (i18n), AZ-481 (CI image labels)
|
||||
**Date**: 2026-05-11
|
||||
**Cycle**: Phase A baseline, Step 6 — Implement Tests
|
||||
**Total complexity**: 12 pts (5 + 2 + 3 + 2)
|
||||
|
||||
## Task Results
|
||||
|
||||
| Task | Status | Files Modified | Tests | AC Coverage | Issues |
|
||||
|------|--------|---------------|-------|-------------|--------|
|
||||
| AZ-457_test_auth_token_handling | Done | 4 created (3 fast + 1 e2e) | 16 fast PASS, 4 e2e gated by suite stack | 4 / 4 ACs covered | 1 documented drift (FT-P-01 `it.fails()` until Step 4 fix) |
|
||||
| AZ-459_test_wire_contract_enums | Done | 2 created (1 fast + 1 e2e) | 11 fast (2 skipped per `verification_pending`), 1 e2e (drift-gated) | 4 / 4 ACs covered | 3 documented drifts (`AnnotationStatus`, `MediaStatus`, `Affiliation` — Step 4 .NET inspection pending) |
|
||||
| AZ-465_test_i18n | Done | 4 created (1 fast + 2 static helpers + 1 allowlist) | 4 fast (2 quarantined), 2 static checks PASS | 4 / 4 ACs covered | 2 quarantined (FT-P-24/25 — detector + persistence not yet implemented in production) |
|
||||
| AZ-481_test_ci_image_labels | Done | 1 created (static check), wired into runner | 6 static findings (5 PASS, 1 DRIFT for `image.title`) | 3 / 3 ACs covered | 1 documented drift (`org.opencontainers.image.title` missing — foundation/CI-CD follow-up) |
|
||||
|
||||
## AC Test Coverage: All covered
|
||||
|
||||
### AZ-457 — Auth & token handling (11 scenarios, 4 ACs)
|
||||
|
||||
| Scenario | Where | Profile | Status (this run) |
|
||||
|----------|-------|---------|-------------------|
|
||||
| FT-P-01 (row 02) bootstrap refresh `credentials:'include'` | `src/auth/AuthContext.test.tsx` | fast | PASS via `it.fails()` (drift documented; flips when Step 4 fix lands) |
|
||||
| FT-P-02 (rows 03, 12) 401→refresh→retry | `src/api/client.test.ts` (fast) + `e2e/tests/auth.e2e.ts` (e2e) | fast + e2e | fast PASS; e2e gated by suite stack |
|
||||
| FT-P-03 (row 11) refresh transparency | `src/auth/AuthContext.test.tsx` | fast | PASS |
|
||||
| FT-N-04 (row 09) unauthenticated `/admin` → `/login` | `src/auth/ProtectedRoute.test.tsx` | fast | PASS |
|
||||
| NFT-SEC-01 bearer never in browser storage | `src/auth/AuthContext.test.tsx` (fast) + e2e companion | fast + e2e | fast PASS; e2e gated |
|
||||
| NFT-SEC-02 refresh cookie not in `document.cookie` | `src/auth/AuthContext.test.tsx` (fast) + e2e companion | fast + e2e | fast PASS; e2e gated |
|
||||
| NFT-SEC-03 refresh cookie `Secure; HttpOnly; SameSite=Strict` | `e2e/tests/auth.e2e.ts` | e2e only | gated |
|
||||
| NFT-SEC-04 `credentials:'include'` on every authed fetch | `src/api/client.test.ts` | fast | one assertion PASS, broader claim `it.fails()` (Step 4 quarantine) |
|
||||
| NFT-PERF-02 exactly one refresh per cycle | `src/api/client.test.ts` | fast | PASS |
|
||||
| NFT-RES-01 transparent recovery | `src/api/client.test.ts` | fast | PASS |
|
||||
| NFT-RES-08 expired refresh → `/login` | `src/api/client.test.ts` + `src/auth/ProtectedRoute.test.tsx` | fast | PASS |
|
||||
|
||||
### AZ-459 — Wire-contract enums (4 scenarios, 4 ACs)
|
||||
|
||||
| Scenario | Where | Profile | Status |
|
||||
|----------|-------|---------|--------|
|
||||
| FT-P-04 (row 14) AnnotationStatus | `tests/wire_contract.test.ts` | fast | PASS via `it.fails()` (drift documented) |
|
||||
| FT-P-05 (rows 15-17) MediaStatus / Affiliation / CombatReadiness | `tests/wire_contract.test.ts` | fast | MediaStatus + Affiliation `it.fails()` (drift); CombatReadiness `it.skip` (`verification_pending`) |
|
||||
| FT-P-06 (rows 18, 19) detection wire payload | `tests/wire_contract.test.ts` (fast control) + `e2e/tests/wire_contract.e2e.ts` (`@drift`) | fast + e2e | fast PASS; e2e gated by `AZAION_RUN_DRIFT_E2E=1` |
|
||||
| FT-N-15 MediaType magic-literal hygiene | `scripts/run-tests.sh` (`STC-FN15`, static) + `tests/wire_contract.test.ts` (fast) | static + fast | static PASS; fast PASS for typed-shape, `it.skip` for value-set (`verification_pending`) |
|
||||
|
||||
### AZ-465 — i18n (4 scenarios, 4 ACs)
|
||||
|
||||
| Scenario | Where | Profile | Status |
|
||||
|----------|-------|---------|--------|
|
||||
| FT-P-22 (row 45) en↔ua key parity | `scripts/check-i18n-coverage.mjs` via `STC-FP22` | static | PASS |
|
||||
| FT-P-23 (row 46) no raw user strings outside `t()` | `scripts/check-i18n-coverage.mjs --coverage-only` via `STC-FP23` + `tests/i18n-allowlist.json` | static | PASS (allow-list seeded with current pre-existing raw strings; CI gates growth) |
|
||||
| FT-P-24 (row 47) detector path on first boot | `tests/i18n.test.tsx` | fast + e2e | `it.skip` (QUARANTINE: detector not wired in `src/i18n/i18n.ts` today) + control test asserts the gap |
|
||||
| FT-P-25 (row 48) persistence across reload | `tests/i18n.test.tsx` | fast + e2e | `it.skip` (QUARANTINE: no persistence adapter today) + control test asserts the gap |
|
||||
|
||||
### AZ-481 — CI image labels (3 scenarios, 3 ACs)
|
||||
|
||||
| Scenario | Where | Profile | Status |
|
||||
|----------|-------|---------|--------|
|
||||
| NFT-RES-LIM-11 tag scheme `${branch}-arm` | `scripts/check-ci-image-labels.mjs` via `STC-CI11` (parses `.woodpecker/build-arm.yml`) | static | PASS |
|
||||
| NFT-RES-LIM-12 OCI labels present | same | static | revision/created/source PASS; `org.opencontainers.image.title` reported DRIFT (lifting the drift is a follow-up CI hygiene task — not in scope here) |
|
||||
| NFT-RES-LIM-13 revision label = `$CI_COMMIT_SHA` | same | static | PASS |
|
||||
| (e2e portion against pushed image) | not run on host | requires-ci | gated; `requires-ci` per `_dependencies_table.md` |
|
||||
|
||||
## Code Review Verdict: PASS_WITH_WARNINGS
|
||||
|
||||
Self-review (4-task batch, sequential per `.cursor/rules/no-subagents.mdc`). Phases 1–7 of `code-review/SKILL.md` walked inline:
|
||||
|
||||
- **Phase 1 (Context)**: each task spec re-read; `_docs/02_document/module-layout.md` Blackbox Tests envelope respected; `_docs/00_problem/input_data/enum_spec_snapshot.json` is the contract pin for AZ-459; `.woodpecker/build-arm.yml` is the SUT for AZ-481.
|
||||
- **Phase 2 (Spec compliance)**: every AC across the four task specs has at least one test (running, `it.fails()`, or `it.skip` with quarantine reason). Drift handling (AZ-459 §AC-2 "Drift surfaces, not silently passes" + verification_pending markers) implemented uniformly via `it.fails()` for documented UI drift and `it.skip` for `verification_pending` enums; AZ-481's static analogue uses a `DRIFT` finding category to surface the missing `image.title` label without gating CI.
|
||||
- **Phase 3 (Code quality)**: helper functions `compareEnum`, `describeDrift`, `probeLabel`, `instrumentStorage` each carry one responsibility; no bare `catch`; meaningful messages; arrange/act/assert respected; tests do not import `<AuthContext>` internals or `<ProtectedRoute>` internals (only `setToken` / `getToken` / `setNavigateToLogin` accessors per AZ-457 AC-2 and the autodev Step 4 testability accessors).
|
||||
- **Phase 4 (Security)**: no new secrets in test fixtures (re-uses AZ-456's placeholder argon2 hashes via the seed helpers); no use of `eval` / `shell=True`; static checks tightened to exclude `*.test.{ts,tsx,spec.ts,spec.tsx}` from production grep so test prose can mention forbidden tokens (e.g. `document.cookie`) without false positives.
|
||||
- **Phase 5 (Performance)**: fast suite ~3s wall-clock for 38 + 4-skipped tests (well under 5-min budget); static profile ~13s including `vite build` and `tsc --noEmit (test)`.
|
||||
- **Phase 6 (Cross-task consistency)**: the four tasks touch **disjoint** subsystems (auth vs enums vs i18n vs CI config); no contract collisions, no duplicate symbols. The shared `tests/helpers/{auth,navigate,render}.ts` (landed in batch 1) is the only cross-task surface and is consumed read-only.
|
||||
- **Phase 7 (Architecture compliance)**:
|
||||
- Test files only import the public accessors of `01_api-transport` (`api`, `setToken`, `getToken`) and `02_auth` (`ProtectedRoute` default export — the public boundary), plus `00_foundation/i18n` for AZ-465's reflective control test. No imports of `<AuthContext>` internals, no imports of `_internal/` or `*.internal.*` files. Per the batch-1 finding (Low / Architecture / Interpretation), this is the same "test setup helper imports public accessors" pattern, now extended to the test bodies via the `tests/helpers/` indirection.
|
||||
- No new cyclic module dependencies introduced (test files are leaves in the import graph).
|
||||
|
||||
### Findings
|
||||
|
||||
1. **Low / Maintainability** — `tests/i18n-allowlist.json` was seeded with the **current** set of raw strings in `src/` so that `FT-P-23` (no raw user strings outside `t()`) passes today. This is per AZ-465 §Constraints ("Allow-list file lives at `tests/i18n-allowlist.json`; CI enforces it must not grow without a code-review reason") — the allow-list is a snapshot, not a permanent exemption. The static check enforces "must not grow without code review" because the JSON file is committed and any growth would be visible in PR diffs. Recommendation: a follow-up i18n-cleanup task (out of scope here) should drain the allow-list as keys are migrated to `t(...)`.
|
||||
|
||||
2. **Low / Style / Drift** — `scripts/check-ci-image-labels.mjs` introduces a `DRIFT` finding category (parallels AZ-459's `it.fails()`) for the missing `org.opencontainers.image.title` OCI label in `.woodpecker/build-arm.yml`. The script reports `DRIFT` to stdout but does not exit non-zero. Rationale: lifting the drift requires editing CI config (foundation/CI-CD ownership envelope), which is out of scope for a test-only batch. Recommendation: file a follow-up CI hygiene task to add the `--label org.opencontainers.image.title=azaion-ui` clause; once landed, the `DRIFT` flips to `PASS` with no test change required.
|
||||
|
||||
3. **Low / Architecture / Interpretation (carried over from batch 1)** — same issue as batch 1: tests rely on `tests/helpers/{render,auth,navigate}.ts` which import production accessors. Reaffirmed here that "Black-box discipline applies to test bodies, not to test setup helpers / composition-root wrappers". The batch-1 recommendation (clarify the layout rule) still stands.
|
||||
|
||||
## Auto-Fix Attempts: 0
|
||||
## Stuck Agents: None
|
||||
|
||||
## Files Changed (12)
|
||||
|
||||
### Created — `src/` (3)
|
||||
```
|
||||
src/api/client.test.ts # AZ-457 fast — 9 tests
|
||||
src/auth/AuthContext.test.tsx # AZ-457 fast — 4 tests
|
||||
src/auth/ProtectedRoute.test.tsx # AZ-457 fast — 3 tests
|
||||
```
|
||||
|
||||
### Created — `tests/` (3)
|
||||
```
|
||||
tests/wire_contract.test.ts # AZ-459 fast — 11 tests (2 skipped)
|
||||
tests/i18n.test.tsx # AZ-465 fast — 4 tests (2 skipped)
|
||||
tests/i18n-allowlist.json # AZ-465 raw-string allow-list (seed)
|
||||
```
|
||||
|
||||
### Created — `e2e/tests/` (2)
|
||||
```
|
||||
e2e/tests/auth.e2e.ts # AZ-457 e2e — 4 scenarios (gated by suite stack)
|
||||
e2e/tests/wire_contract.e2e.ts # AZ-459 e2e — drift-gated annotation save body
|
||||
```
|
||||
|
||||
### Created — `scripts/` (2)
|
||||
```
|
||||
scripts/check-i18n-coverage.mjs # AZ-465 STC-FP22 + STC-FP23
|
||||
scripts/check-ci-image-labels.mjs # AZ-481 STC-CI11
|
||||
```
|
||||
|
||||
### Modified (3)
|
||||
```
|
||||
scripts/run-tests.sh # +6 static checks (STC-FN15, STC-SEC4 refinement, STC-FP22, STC-FP23, STC-CI11) + src_grep test-file exclusion
|
||||
tsconfig.json # +exclude src/**/*.{test,spec}.{ts,tsx} from production tsc -b
|
||||
_docs/_autodev_state.md # batch 2 sub_step pointer
|
||||
```
|
||||
|
||||
## Verification Run (host)
|
||||
|
||||
```
|
||||
$ bun run test:fast
|
||||
✓ mission-planner/src/test/jsonImport.test.ts (6 tests) 7ms
|
||||
✓ tests/wire_contract.test.ts (11 tests | 2 skipped) 9ms
|
||||
✓ tests/infrastructure.test.ts (5 tests) 35ms
|
||||
✓ tests/i18n.test.tsx (4 tests | 2 skipped) 3ms
|
||||
✓ src/api/client.test.ts (9 tests) 58ms
|
||||
✓ src/auth/ProtectedRoute.test.tsx (3 tests) 76ms
|
||||
✓ src/auth/AuthContext.test.tsx (4 tests) 241ms
|
||||
Test Files 7 passed (7)
|
||||
Tests 38 passed | 4 skipped (42)
|
||||
|
||||
$ ./scripts/run-tests.sh --static-only
|
||||
[run-tests] static profile PASSED — 19/19 checks (was 13 in batch 1; +6 from batch 2)
|
||||
|
||||
$ ./scripts/run-tests.sh
|
||||
[run-tests] static profile : ran (PASS)
|
||||
[run-tests] fast profile : ran (PASS)
|
||||
[run-tests] e2e profile : skipped (host)
|
||||
[run-tests] exit code : 0
|
||||
```
|
||||
|
||||
E2E profile not exercised in this batch — same Risk 4 as batch 1 (requires `docker compose -f e2e/docker-compose.suite-e2e.yml up -d` plus parent-suite `:test` images). Per AZ-457 e2e companion, NFT-SEC-03 specifically requires Playwright's `context.cookies()` against the real `admin/` service.
|
||||
|
||||
## Next Batch
|
||||
|
||||
Remaining: 22 test-implementation tasks in `_docs/02_tasks/todo/` (AZ-458, AZ-460..AZ-464, AZ-466..AZ-480, AZ-482). All carry **Component**: `Blackbox Tests` and **Dependencies**: `AZ-456` (✓ done) — soft cross-deps:
|
||||
- AZ-473 depends on AZ-472 (DetectionClasses fixtures)
|
||||
- AZ-458 (SSE bearer rotation) consumes the auth helpers landed by AZ-457 (✓ now done)
|
||||
- AZ-467 (ProtectedRoute spinner + RBAC) consumes the same helpers (✓)
|
||||
- AZ-468 (Header dropdown — uses authed page) consumes the same helpers (✓)
|
||||
|
||||
Suggested next batch (4 tasks, ~10 pts): AZ-458 (SSE lifecycle, 5pts), AZ-467 (ProtectedRoute spinner + RBAC, 4pts), AZ-468 (Header flight dropdown, 2pts), and one small parallel — for example AZ-482 (secrets/banned-libs, 3pts) so the four tasks remain dependency-disjoint at the file level.
|
||||
|
||||
Recommendation: continue in a new conversation. Batch 2 added 12 new files and 6 new static checks; the next batch will load distinct task specs and SSE / RBAC subsystems.
|
||||
Reference in New Issue
Block a user