feat(coverage): L0 unification — close test gaps in nav, media, mp

Closes the per-layer threshold gaps surfaced by the 2026-05-13 PRD
audit. After this commit all five features pass their declared
100%/100%/95%/100% bands on entities + use-cases + controllers.

media (was: missing @vitest/coverage-v8 + missing vitest config block +
  one controller at 86.66% lines / 75% branches)
  - Added @vitest/coverage-v8 dev dep
  - Applied the standard helper-driven vitest config
  - Declared the coverage section in feature.manifest.ts
  - Added 2 tests to list-media.controller.test.ts covering the
    InputParseError branch (unknown fields + invalid limit)
  - Now: 16 files / 80 tests / 97.12% / controllers 100%

marketing-pages (was: get-site-settings.controller at 93.54% lines /
  90.9% branches)
  - Added 1 test to get-site-settings.controller.test.ts covering the
    InputParseError branch on unknown fields
  - Now: 22 files / 68 tests / 95.66% / controllers 100%

navigation (was: entities/errors/common.ts at 50% function hits +
  get-header.controller at 86.66% lines / 80% branches)
  - Root cause: InputParseError class never instantiated in any test
  - Added 2 tests to get-header.controller.test.ts covering the
    InputParseError branch + verifying the Zod cause is preserved.
    One test exercises both gap files at once (controller throws,
    InputParseError class is constructed).
  - Wired navigation/vitest.config.ts through the shared helper
  - Declared the coverage section in feature.manifest.ts
  - Now: 11 files / 45 tests / 98.04% / entities + controllers 100%

All 5 features now drive thresholds from the manifest via the helper.
The duplication problem the keystone eliminates is gone.

Repo-wide via `pnpm coverage:aggregate`:
  - statements 95.87% (lh 2994 / lf 3123)
  - branches   88.91% (brh 433 / brf 487)
  - functions  100%   (fnh 142 / fnf 142)
  - lines      95.87%

`pnpm coverage:diff -- --base HEAD~1` reports status: pass.

coverage/summary.json refreshed in the same commit so the trend
captures the post-unification state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-13 16:39:08 +02:00
parent 6428f10b82
commit bf0b049583
10 changed files with 191 additions and 56 deletions

View File

@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
import { getHeaderController } from "@/interface-adapters/controllers/get-header.controller";
import { getHeaderUseCase } from "@/application/use-cases/get-header.use-case";
import { MockHeaderRepository } from "@/infrastructure/repositories/header.repository.mock";
import { InputParseError } from "@/entities/errors/common";
describe("getHeaderController", () => {
it("returns the header with items", async () => {
@@ -14,4 +15,29 @@ describe("getHeaderController", () => {
expect(result.items.length).toBeGreaterThan(0);
expect(result.items[0]?.label).toBe("Home");
});
it("throws InputParseError on unknown fields (strict schema)", async () => {
const repo = new MockHeaderRepository();
const useCase = getHeaderUseCase(repo);
const controller = getHeaderController(useCase);
await expect(controller({ unknownField: 1 })).rejects.toThrow(
InputParseError,
);
});
it("InputParseError preserves the cause from Zod", async () => {
const repo = new MockHeaderRepository();
const useCase = getHeaderUseCase(repo);
const controller = getHeaderController(useCase);
try {
await controller({ unknownField: 1 });
expect.fail("expected InputParseError");
} catch (err) {
expect(err).toBeInstanceOf(InputParseError);
expect((err as Error).name).toBe("InputParseError");
expect((err as InputParseError).cause).toBeDefined();
}
});
});