test: cover dashboard needsValidation and detail() nextAction regression risk
Round 3 of the TechLog contract task added two pieces of genuinely new logic with no assertion on their output: the totals.needsValidation count in getDashboard(), and the detail() rewrite that avoids a self-reference when computing WorkingCopyDetail.nextAction. Both would have passed every existing test if they regressed. - needsValidation is checked against an independent count derived from listDocuments()'s per-document nextAction, with sanity bounds so a filter that always returns 0 or the full count can't pass silently. - detail()'s nextAction is asserted on two fixtures whose expected value is justified by the asserted preconditions alongside it (published-at-current-version -> NONE; INVALID-but-current-validation -> FIX_VALIDATION). Verified locally that hardcoding nextAction to a constant in detail() makes the second assertion fail, and that zeroing needsValidation's count makes the dashboard assertion fail. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
639e1a49c9
commit
a0e0be6522
@@ -597,3 +597,45 @@ test("publication history, immutable snapshots, conflict fixtures and 404 bodies
|
||||
isProblem(404, "PUBLICATION_EVENT_NOT_FOUND"),
|
||||
);
|
||||
});
|
||||
|
||||
test("dashboard totals.needsValidation matches the documents whose next action is to validate or fix validation", async () => {
|
||||
const gateway = gatewayAt();
|
||||
const dashboard = await gateway.getDashboard();
|
||||
const documents = await gateway.listDocuments({ limit: 100 });
|
||||
|
||||
const expected = documents.items.filter(
|
||||
(item) =>
|
||||
item.nextAction === "VALIDATE" || item.nextAction === "FIX_VALIDATION",
|
||||
).length;
|
||||
// Cross-checked against `listDocuments`, not against the dashboard's own
|
||||
// arithmetic, so a broken `needsValidation` filter shows up as a mismatch
|
||||
// instead of being restated. Both branches (>0 and <total) must hold, or a
|
||||
// filter that always returns 0 or the full count would still pass silently.
|
||||
assert.ok(expected > 0);
|
||||
assert.ok(expected < documents.items.length);
|
||||
assert.equal(dashboard.totals.needsValidation, expected);
|
||||
});
|
||||
|
||||
test("getDocument's nextAction reflects the assembled WorkingCopyDetail, not a cached or default value", async () => {
|
||||
const gateway = gatewayAt();
|
||||
|
||||
// Published at exactly the current version (fixtures.ts: publishedVersion 4
|
||||
// === document version 4) is deriveNextAction's first, clock-independent
|
||||
// branch: nextAction must be "NONE" regardless of validation or preview state.
|
||||
const redis = await gateway.getDocument(FIXTURE_IDS.redisAdapterCase);
|
||||
assert.equal(redis.document.version, 4);
|
||||
assert.equal(redis.currentPublication?.status, "PUBLISHED");
|
||||
assert.equal(redis.currentPublication?.publishedVersion, 4);
|
||||
assert.equal(redis.nextAction, "NONE");
|
||||
|
||||
// Not published, and validated INVALID at the current version within the
|
||||
// validity window: nextAction must be "FIX_VALIDATION", which only follows
|
||||
// from currentValidation actually being read and its freshness actually
|
||||
// computed - a value a hardcoded or wrongly-sourced default would not produce.
|
||||
const edgeToken = await gateway.getDocument(FIXTURE_IDS.edgeTokenQuestion);
|
||||
assert.equal(edgeToken.document.version, 2);
|
||||
assert.equal(edgeToken.currentPublication, null);
|
||||
assert.equal(edgeToken.currentValidation?.status, "INVALID");
|
||||
assert.equal(edgeToken.currentValidation?.validatedVersion, 2);
|
||||
assert.equal(edgeToken.nextAction, "FIX_VALIDATION");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user