Testing patterns for @template/contracts Zod schemas. Validates shared fixtures to ensure contract correctness and prevent regressions. Trigger: When contracts change, new contracts are created, or schema validation tests are needed.
NOTE: The test infrastructure described below (fixtures directory, vitest) is not yet set up in this project. Install vitest and create
packages/contracts/fixtures/before using these patterns.
shared-contracts - Contract definitionscontract-versioning - SemVer and changelogcontract-enforcement - Enforce contract usageEnsure @template/contracts Zod schemas remain correct and backward-compatible by validating shared JSON fixtures against every schema.
packages/contracts/
├── src/ # Zod schemas (source of truth)
│ ├── auth.ts
│ ├── chat.ts
│ ├── common.ts
│ └── courses.ts
├── fixtures/ # Shared JSON fixtures
│ ├── auth/
│ │ ├── login-request.json
│ │ └── login-response.json
│ ├── chat/
│ │ ├── chat-message.json
│ │ └── chat-session.json
│ └── common/
│ └── pagination.json
└── tests/
└── fixtures.test.ts # Validates all fixtures against schemas
import { describe, it, expect } from "vitest";
import { LoginRequestSchema } from "../src/auth";
import loginRequestFixture from "../fixtures/auth/login-request.json";
describe("LoginRequestSchema", () => {
it("validates valid login request fixture", () => {
const result = LoginRequestSchema.safeParse(loginRequestFixture);
expect(result.success).toBe(true);
});
it("rejects invalid login request (missing email)", () => {
const invalid = { password: "test123" };
const result = LoginRequestSchema.safeParse(invalid);
expect(result.success).toBe(false);
});
});
import { describe, it, expect } from "vitest";
import { readdirSync, readFileSync } from "node:fs";
import { join } from "node:path";
import * as schemas from "../src/index";
const FIXTURES_DIR = join(__dirname, "../fixtures");
function loadFixture(domain: string, filename: string): unknown {
const path = join(FIXTURES_DIR, domain, filename);
return JSON.parse(readFileSync(path, "utf-8"));
}
// Map fixture filenames to their corresponding schemas
const FIXTURE_SCHEMA_MAP: Record<string, keyof typeof schemas> = {
"login-request.json": "LoginRequestSchema",
"chat-message.json": "ChatMessageSchema",
// Add new mappings here
};
describe("Contract Fixtures", () => {
for (const [filename, schemaName] of Object.entries(FIXTURE_SCHEMA_MAP)) {
const domain = filename.split("-")[0] === "login" ? "auth" : "chat";
it(`${schemaName} validates ${filename}`, () => {
const fixture = loadFixture(domain, filename);
const schema = schemas[schemaName];
const result = (schema as { safeParse: (d: unknown) => { success: boolean } }).safeParse(fixture);
expect(result.success).toBe(true);
});
}
});
Fixtures are plain JSON files representing valid instances of each schema:
// fixtures/auth/login-request.json
{
"email": "[email protected]",
"password": "securePassword123"
}
// fixtures/chat/chat-message.json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"role": "user",
"content": "Hello, how can I invest?",
"createdAt": "2026-03-01T12:00:00.000Z"
}
# From root
pnpm test
# From contracts package
cd packages/contracts && pnpm test
| Action | Invoke? |
|---|---|
| Contract created | ✅ Yes |
| Contract field changed | ✅ Yes |
| Version bump requested | ✅ Yes |
| Breaking change suspected | ✅ Yes |
| UI-only type change | ❌ No |
shared-contracts skillpackages/contracts/fixtures/