@typokit/testing 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,62 @@
1
+ import type { TypoKitApp } from "@typokit/core";
2
+ import type { RouteContract } from "@typokit/types";
3
+ export { createIntegrationSuite, registerSeed, getSeed, } from "./integration-suite.js";
4
+ export type { IntegrationSuite, IntegrationSuiteOptions, InMemoryDatabase, SeedFn, } from "./integration-suite.js";
5
+ export { createFactory } from "./factory.js";
6
+ export type { Factory, FactoryOptions } from "./factory.js";
7
+ export { toMatchSchema, matchSchema, registerSchemaValidators, getSchemaValidator, clearSchemaValidators, } from "./schema-matcher.js";
8
+ export type { SchemaMatchResult, SchemaMatchers } from "./schema-matcher.js";
9
+ export { generateContractTests, detectTestRunner, } from "./contract-generator.js";
10
+ export type { ContractTestRoute, ContractTestOptions, ContractTestOutput, TestRunner, } from "./contract-generator.js";
11
+ /** Response returned by test client methods */
12
+ export interface TestResponse<TBody = unknown> {
13
+ status: number;
14
+ body: TBody;
15
+ headers: Record<string, string>;
16
+ }
17
+ /** Options for test client request methods */
18
+ export interface TestRequestOptions {
19
+ body?: unknown;
20
+ query?: Record<string, string | string[]>;
21
+ headers?: Record<string, string>;
22
+ }
23
+ /** Type-safe request options using a RouteContract */
24
+ export interface TypedRequestOptions<TContract extends RouteContract<unknown, unknown, unknown, unknown>> {
25
+ body?: TContract["body"] extends void ? never : TContract["body"];
26
+ query?: TContract["query"] extends void ? never : TContract["query"];
27
+ headers?: Record<string, string>;
28
+ }
29
+ /** A test client for making typed HTTP requests against a TypoKit app */
30
+ export interface TestClient {
31
+ /** Send a GET request */
32
+ get<TResponse = unknown>(path: string, options?: TestRequestOptions): Promise<TestResponse<TResponse>>;
33
+ /** Send a POST request */
34
+ post<TResponse = unknown>(path: string, options?: TestRequestOptions): Promise<TestResponse<TResponse>>;
35
+ /** Send a PUT request */
36
+ put<TResponse = unknown>(path: string, options?: TestRequestOptions): Promise<TestResponse<TResponse>>;
37
+ /** Send a PATCH request */
38
+ patch<TResponse = unknown>(path: string, options?: TestRequestOptions): Promise<TestResponse<TResponse>>;
39
+ /** Send a DELETE request */
40
+ delete<TResponse = unknown>(path: string, options?: TestRequestOptions): Promise<TestResponse<TResponse>>;
41
+ /** Send a contract-typed request */
42
+ request<TContract extends RouteContract<unknown, unknown, unknown, unknown>>(method: string, path: string, options?: TypedRequestOptions<TContract>): Promise<TestResponse<TContract["response"]>>;
43
+ /** Shut down the test server */
44
+ close(): Promise<void>;
45
+ /** The base URL the test server is listening on */
46
+ baseUrl: string;
47
+ }
48
+ /**
49
+ * Create a test client for a TypoKit application.
50
+ *
51
+ * Starts the app on a random port and returns a typed HTTP client.
52
+ * Call `client.close()` when done to shut down the server.
53
+ *
54
+ * ```ts
55
+ * const client = await createTestClient(app);
56
+ * const res = await client.get<{ message: string }>("/hello");
57
+ * expect(res.status).toBe(200);
58
+ * await client.close();
59
+ * ```
60
+ */
61
+ export declare function createTestClient(app: TypoKitApp): Promise<TestClient>;
62
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,119 @@
1
+ // @typokit/testing — Test Client, Integration Suite & Factories
2
+ export { createIntegrationSuite, registerSeed, getSeed, } from "./integration-suite.js";
3
+ export { createFactory } from "./factory.js";
4
+ export { toMatchSchema, matchSchema, registerSchemaValidators, getSchemaValidator, clearSchemaValidators, } from "./schema-matcher.js";
5
+ export { generateContractTests, detectTestRunner, } from "./contract-generator.js";
6
+ // ─── Internal Helpers ────────────────────────────────────────
7
+ /** Build a URL with query parameters */
8
+ function buildUrl(base, path, query) {
9
+ let url = `${base}${path}`;
10
+ if (query && Object.keys(query).length > 0) {
11
+ const params = new URLSearchParams();
12
+ for (const [key, value] of Object.entries(query)) {
13
+ if (Array.isArray(value)) {
14
+ for (const v of value) {
15
+ params.append(key, v);
16
+ }
17
+ }
18
+ else {
19
+ params.append(key, value);
20
+ }
21
+ }
22
+ url += `?${params.toString()}`;
23
+ }
24
+ return url;
25
+ }
26
+ /** Parse response headers into a flat Record */
27
+ function parseHeaders(headers) {
28
+ const result = {};
29
+ headers.forEach((value, key) => {
30
+ result[key] = value;
31
+ });
32
+ return result;
33
+ }
34
+ /** Execute an HTTP request and return a TestResponse */
35
+ async function executeRequest(baseUrl, method, path, options = {}) {
36
+ const url = buildUrl(baseUrl, path, options.query);
37
+ const headers = { ...options.headers };
38
+ let bodyStr;
39
+ if (options.body !== undefined) {
40
+ if (!headers["content-type"]) {
41
+ headers["content-type"] = "application/json";
42
+ }
43
+ bodyStr =
44
+ typeof options.body === "string"
45
+ ? options.body
46
+ : JSON.stringify(options.body);
47
+ }
48
+ const response = await fetch(url, {
49
+ method,
50
+ headers,
51
+ body: bodyStr,
52
+ });
53
+ const responseHeaders = parseHeaders(response.headers);
54
+ const contentType = response.headers.get("content-type") ?? "";
55
+ let body;
56
+ if (contentType.includes("application/json")) {
57
+ body = (await response.json());
58
+ }
59
+ else {
60
+ body = (await response.text());
61
+ }
62
+ return {
63
+ status: response.status,
64
+ body,
65
+ headers: responseHeaders,
66
+ };
67
+ }
68
+ // ─── createTestClient ────────────────────────────────────────
69
+ /**
70
+ * Create a test client for a TypoKit application.
71
+ *
72
+ * Starts the app on a random port and returns a typed HTTP client.
73
+ * Call `client.close()` when done to shut down the server.
74
+ *
75
+ * ```ts
76
+ * const client = await createTestClient(app);
77
+ * const res = await client.get<{ message: string }>("/hello");
78
+ * expect(res.status).toBe(200);
79
+ * await client.close();
80
+ * ```
81
+ */
82
+ export async function createTestClient(app) {
83
+ // Start on port 0 for auto-assigned random port
84
+ await app.listen(0);
85
+ // Get the actual port from the underlying server
86
+ const nativeServer = app.getNativeServer();
87
+ const addr = nativeServer.address();
88
+ if (!addr || typeof addr === "string") {
89
+ throw new Error("Failed to determine server port");
90
+ }
91
+ const port = addr.port;
92
+ const baseUrl = `http://127.0.0.1:${port}`;
93
+ const client = {
94
+ baseUrl,
95
+ get(path, options) {
96
+ return executeRequest(baseUrl, "GET", path, options);
97
+ },
98
+ post(path, options) {
99
+ return executeRequest(baseUrl, "POST", path, options);
100
+ },
101
+ put(path, options) {
102
+ return executeRequest(baseUrl, "PUT", path, options);
103
+ },
104
+ patch(path, options) {
105
+ return executeRequest(baseUrl, "PATCH", path, options);
106
+ },
107
+ delete(path, options) {
108
+ return executeRequest(baseUrl, "DELETE", path, options);
109
+ },
110
+ request(method, path, options) {
111
+ return executeRequest(baseUrl, method, path, options);
112
+ },
113
+ async close() {
114
+ await app.close();
115
+ },
116
+ };
117
+ return client;
118
+ }
119
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import type { TypoKitApp } from "@typokit/core";
2
+ import type { TestClient } from "./index.js";
3
+ /** A simple in-memory database for integration testing */
4
+ export interface InMemoryDatabase {
5
+ /** Insert a record into a table */
6
+ insert(table: string, record: Record<string, unknown>): void;
7
+ /** Find all records in a table */
8
+ findAll(table: string): Record<string, unknown>[];
9
+ /** Find a record by id field */
10
+ findById(table: string, id: string): Record<string, unknown> | undefined;
11
+ /** Delete all records from a table */
12
+ clearTable(table: string): void;
13
+ /** Delete all records from all tables */
14
+ clear(): void;
15
+ /** Get the list of table names */
16
+ tables(): string[];
17
+ }
18
+ /** A seed function populates an in-memory database with test data */
19
+ export type SeedFn = (db: InMemoryDatabase) => void;
20
+ /** Register a named seed data fixture */
21
+ export declare function registerSeed(name: string, seed: SeedFn): void;
22
+ /** Get a registered seed function by name */
23
+ export declare function getSeed(name: string): SeedFn | undefined;
24
+ /** Options for creating an integration test suite */
25
+ export interface IntegrationSuiteOptions {
26
+ /** Whether to spin up an in-memory database (default: false) */
27
+ database?: boolean;
28
+ /** Name of a registered seed data fixture to apply */
29
+ seed?: string;
30
+ }
31
+ /** An integration test suite with managed server and database lifecycle */
32
+ export interface IntegrationSuite {
33
+ /** Start the server and seed the database */
34
+ setup(): Promise<void>;
35
+ /** Stop the server and clean up */
36
+ teardown(): Promise<void>;
37
+ /** The typed test client (available after setup) */
38
+ readonly client: TestClient;
39
+ /** The in-memory database (null if database option is false) */
40
+ readonly db: InMemoryDatabase | null;
41
+ }
42
+ /**
43
+ * Create an integration test suite for a TypoKit application.
44
+ *
45
+ * Sets up an isolated server and optionally an in-memory database
46
+ * with seeded test data. Each call creates a fully independent
47
+ * instance with no shared mutable state.
48
+ *
49
+ * ```ts
50
+ * const suite = createIntegrationSuite(app, {
51
+ * database: true,
52
+ * seed: "users",
53
+ * });
54
+ *
55
+ * // In beforeEach / setup
56
+ * await suite.setup();
57
+ *
58
+ * // In tests
59
+ * const res = await suite.client.get("/users");
60
+ *
61
+ * // In afterEach / teardown
62
+ * await suite.teardown();
63
+ * ```
64
+ */
65
+ export declare function createIntegrationSuite(app: TypoKitApp, options?: IntegrationSuiteOptions): IntegrationSuite;
66
+ //# sourceMappingURL=integration-suite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration-suite.d.ts","sourceRoot":"","sources":["../src/integration-suite.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAK7C,0DAA0D;AAC1D,MAAM,WAAW,gBAAgB;IAC/B,mCAAmC;IACnC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAE7D,kCAAkC;IAClC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAElD,gCAAgC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAEzE,sCAAsC;IACtC,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAEhC,yCAAyC;IACzC,KAAK,IAAI,IAAI,CAAC;IAEd,kCAAkC;IAClC,MAAM,IAAI,MAAM,EAAE,CAAC;CACpB;AAyCD,qEAAqE;AACrE,MAAM,MAAM,MAAM,GAAG,CAAC,EAAE,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAIpD,yCAAyC;AACzC,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAE7D;AAED,6CAA6C;AAC7C,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAExD;AAID,qDAAqD;AACrD,MAAM,WAAW,uBAAuB;IACtC,gEAAgE;IAChE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,2EAA2E;AAC3E,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB,mCAAmC;IACnC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1B,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAE5B,gEAAgE;IAChE,QAAQ,CAAC,EAAE,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACtC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,UAAU,EACf,OAAO,GAAE,uBAA4B,GACpC,gBAAgB,CAuDlB"}
@@ -0,0 +1,110 @@
1
+ // @typokit/testing — Integration Test Suite
2
+ import { createTestClient } from "./index.js";
3
+ function createInMemoryDatabase() {
4
+ const store = new Map();
5
+ return {
6
+ insert(table, record) {
7
+ if (!store.has(table)) {
8
+ store.set(table, []);
9
+ }
10
+ // Clone the record to prevent shared references
11
+ store.get(table).push({ ...record });
12
+ },
13
+ findAll(table) {
14
+ return (store.get(table) ?? []).map((r) => ({ ...r }));
15
+ },
16
+ findById(table, id) {
17
+ const records = store.get(table);
18
+ if (!records)
19
+ return undefined;
20
+ const found = records.find((r) => r["id"] === id);
21
+ return found ? { ...found } : undefined;
22
+ },
23
+ clearTable(table) {
24
+ store.delete(table);
25
+ },
26
+ clear() {
27
+ store.clear();
28
+ },
29
+ tables() {
30
+ return [...store.keys()];
31
+ },
32
+ };
33
+ }
34
+ const seedRegistry = new Map();
35
+ /** Register a named seed data fixture */
36
+ export function registerSeed(name, seed) {
37
+ seedRegistry.set(name, seed);
38
+ }
39
+ /** Get a registered seed function by name */
40
+ export function getSeed(name) {
41
+ return seedRegistry.get(name);
42
+ }
43
+ /**
44
+ * Create an integration test suite for a TypoKit application.
45
+ *
46
+ * Sets up an isolated server and optionally an in-memory database
47
+ * with seeded test data. Each call creates a fully independent
48
+ * instance with no shared mutable state.
49
+ *
50
+ * ```ts
51
+ * const suite = createIntegrationSuite(app, {
52
+ * database: true,
53
+ * seed: "users",
54
+ * });
55
+ *
56
+ * // In beforeEach / setup
57
+ * await suite.setup();
58
+ *
59
+ * // In tests
60
+ * const res = await suite.client.get("/users");
61
+ *
62
+ * // In afterEach / teardown
63
+ * await suite.teardown();
64
+ * ```
65
+ */
66
+ export function createIntegrationSuite(app, options = {}) {
67
+ let client = null;
68
+ let db = null;
69
+ const suite = {
70
+ async setup() {
71
+ // Create a fresh in-memory database if requested
72
+ if (options.database) {
73
+ db = createInMemoryDatabase();
74
+ // Apply seed data if specified
75
+ if (options.seed) {
76
+ const seedFn = getSeed(options.seed);
77
+ if (!seedFn) {
78
+ throw new Error(`Unknown seed fixture: "${options.seed}". Register it with registerSeed() first.`);
79
+ }
80
+ seedFn(db);
81
+ }
82
+ }
83
+ // Start the server and create a test client
84
+ client = await createTestClient(app);
85
+ },
86
+ async teardown() {
87
+ // Close the test client / server
88
+ if (client) {
89
+ await client.close();
90
+ client = null;
91
+ }
92
+ // Clear the database
93
+ if (db) {
94
+ db.clear();
95
+ db = null;
96
+ }
97
+ },
98
+ get client() {
99
+ if (!client) {
100
+ throw new Error("Integration suite not set up. Call suite.setup() first.");
101
+ }
102
+ return client;
103
+ },
104
+ get db() {
105
+ return db;
106
+ },
107
+ };
108
+ return suite;
109
+ }
110
+ //# sourceMappingURL=integration-suite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration-suite.js","sourceRoot":"","sources":["../src/integration-suite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import type { ValidatorFn, ValidatorMap } from "@typokit/types";
2
+ /**
3
+ * Register compiled validators for use with toMatchSchema().
4
+ * Call this in your test setup with validators from your build output.
5
+ *
6
+ * ```ts
7
+ * import { registerSchemaValidators } from "@typokit/testing";
8
+ * registerSchemaValidators({
9
+ * PublicUser: (input) => ({ success: true, data: input }),
10
+ * CreateUserInput: myTypiaValidator,
11
+ * });
12
+ * ```
13
+ */
14
+ export declare function registerSchemaValidators(validators: ValidatorMap): void;
15
+ /**
16
+ * Get a validator by schema name. Throws if not registered.
17
+ */
18
+ export declare function getSchemaValidator(schemaName: string): ValidatorFn;
19
+ /** Clear all registered validators (for test isolation) */
20
+ export declare function clearSchemaValidators(): void;
21
+ /** Result of a schema match operation */
22
+ export interface SchemaMatchResult {
23
+ pass: boolean;
24
+ message: string;
25
+ }
26
+ /**
27
+ * Core schema matching logic shared by all framework adapters.
28
+ */
29
+ export declare function matchSchema(received: unknown, schemaName: string): SchemaMatchResult;
30
+ /**
31
+ * Custom matcher for Jest, Vitest, and Rstest expect() chains.
32
+ *
33
+ * All three frameworks share compatible matcher APIs:
34
+ * - `this.isNot` indicates `.not.toMatchSchema()` usage
35
+ * - Return `{ pass, message() }` object
36
+ *
37
+ * Usage:
38
+ * ```ts
39
+ * import { toMatchSchema, registerSchemaValidators } from "@typokit/testing";
40
+ *
41
+ * // For Jest:
42
+ * expect.extend({ toMatchSchema });
43
+ *
44
+ * // For Vitest:
45
+ * expect.extend({ toMatchSchema });
46
+ *
47
+ * // For Rstest:
48
+ * expect.extend({ toMatchSchema });
49
+ *
50
+ * // Then in tests:
51
+ * expect(responseBody).toMatchSchema("PublicUser");
52
+ * ```
53
+ */
54
+ export declare function toMatchSchema(this: {
55
+ isNot?: boolean;
56
+ } | void, received: unknown, schemaName: string): {
57
+ pass: boolean;
58
+ message: () => string;
59
+ };
60
+ /**
61
+ * Type declaration for extending expect() in Jest, Vitest, and Rstest.
62
+ *
63
+ * Users should add to their test setup:
64
+ * ```ts
65
+ * declare module "expect" {
66
+ * interface AsymmetricMatchers {
67
+ * toMatchSchema(schemaName: string): void;
68
+ * }
69
+ * interface Matchers<R> {
70
+ * toMatchSchema(schemaName: string): R;
71
+ * }
72
+ * }
73
+ * ```
74
+ */
75
+ export interface SchemaMatchers<R = unknown> {
76
+ toMatchSchema(schemaName: string): R;
77
+ }
78
+ //# sourceMappingURL=schema-matcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-matcher.d.ts","sourceRoot":"","sources":["../src/schema-matcher.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EAEb,MAAM,gBAAgB,CAAC;AAOxB;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,YAAY,GAAG,IAAI,CAEvE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,CAWlE;AAED,2DAA2D;AAC3D,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAID,yCAAyC;AACzC,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAgBD;;GAEG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,MAAM,GACjB,iBAAiB,CAoBnB;AAID;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,EAChC,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,MAAM,GACjB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,MAAM,CAAA;CAAE,CAO1C;AAID;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,OAAO;IACzC,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,CAAC,CAAC;CACtC"}
@@ -0,0 +1,99 @@
1
+ // @typokit/testing — toMatchSchema custom matcher
2
+ // Adapters for Jest, Vitest, and Rstest
3
+ // ─── Schema Registry ─────────────────────────────────────────
4
+ /** Global registry of compiled validators keyed by schema name */
5
+ let validatorRegistry = {};
6
+ /**
7
+ * Register compiled validators for use with toMatchSchema().
8
+ * Call this in your test setup with validators from your build output.
9
+ *
10
+ * ```ts
11
+ * import { registerSchemaValidators } from "@typokit/testing";
12
+ * registerSchemaValidators({
13
+ * PublicUser: (input) => ({ success: true, data: input }),
14
+ * CreateUserInput: myTypiaValidator,
15
+ * });
16
+ * ```
17
+ */
18
+ export function registerSchemaValidators(validators) {
19
+ validatorRegistry = { ...validatorRegistry, ...validators };
20
+ }
21
+ /**
22
+ * Get a validator by schema name. Throws if not registered.
23
+ */
24
+ export function getSchemaValidator(schemaName) {
25
+ const validator = validatorRegistry[schemaName];
26
+ if (!validator) {
27
+ const available = Object.keys(validatorRegistry);
28
+ throw new Error(`Schema "${schemaName}" not registered. ` +
29
+ `Available schemas: ${available.length > 0 ? available.join(", ") : "(none)"}. ` +
30
+ `Call registerSchemaValidators() in your test setup.`);
31
+ }
32
+ return validator;
33
+ }
34
+ /** Clear all registered validators (for test isolation) */
35
+ export function clearSchemaValidators() {
36
+ validatorRegistry = {};
37
+ }
38
+ // ─── Core Matcher Logic ──────────────────────────────────────
39
+ /**
40
+ * Format validation errors into a human-readable message.
41
+ */
42
+ function formatErrors(errors) {
43
+ return errors
44
+ .map((e) => ` • ${e.path}: expected ${e.expected}, received ${JSON.stringify(e.actual)}`)
45
+ .join("\n");
46
+ }
47
+ /**
48
+ * Core schema matching logic shared by all framework adapters.
49
+ */
50
+ export function matchSchema(received, schemaName) {
51
+ const validator = getSchemaValidator(schemaName);
52
+ const result = validator(received);
53
+ if (result.success) {
54
+ return {
55
+ pass: true,
56
+ message: `Expected value NOT to match schema "${schemaName}", but it did.`,
57
+ };
58
+ }
59
+ const errorDetails = result.errors && result.errors.length > 0
60
+ ? `\nField errors:\n${formatErrors(result.errors)}`
61
+ : "";
62
+ return {
63
+ pass: false,
64
+ message: `Expected value to match schema "${schemaName}", but validation failed.${errorDetails}`,
65
+ };
66
+ }
67
+ // ─── Jest / Vitest / Rstest Adapter ──────────────────────────
68
+ /**
69
+ * Custom matcher for Jest, Vitest, and Rstest expect() chains.
70
+ *
71
+ * All three frameworks share compatible matcher APIs:
72
+ * - `this.isNot` indicates `.not.toMatchSchema()` usage
73
+ * - Return `{ pass, message() }` object
74
+ *
75
+ * Usage:
76
+ * ```ts
77
+ * import { toMatchSchema, registerSchemaValidators } from "@typokit/testing";
78
+ *
79
+ * // For Jest:
80
+ * expect.extend({ toMatchSchema });
81
+ *
82
+ * // For Vitest:
83
+ * expect.extend({ toMatchSchema });
84
+ *
85
+ * // For Rstest:
86
+ * expect.extend({ toMatchSchema });
87
+ *
88
+ * // Then in tests:
89
+ * expect(responseBody).toMatchSchema("PublicUser");
90
+ * ```
91
+ */
92
+ export function toMatchSchema(received, schemaName) {
93
+ const result = matchSchema(received, schemaName);
94
+ return {
95
+ pass: result.pass,
96
+ message: () => result.message,
97
+ };
98
+ }
99
+ //# sourceMappingURL=schema-matcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-matcher.js","sourceRoot":"","sources":["../src/schema-matcher.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,wCAAwC;AAQxC,gEAAgE;AAEhE,kEAAkE;AAClE,IAAI,iBAAiB,GAAiB,EAAE,CAAC;AAEzC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,wBAAwB,CAAC,UAAwB;IAC/D,iBAAiB,GAAG,EAAE,GAAG,iBAAiB,EAAE,GAAG,UAAU,EAAE,CAAC;AAC9D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAAkB;IACnD,MAAM,SAAS,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAChD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACjD,MAAM,IAAI,KAAK,CACb,WAAW,UAAU,oBAAoB;YACvC,sBAAsB,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI;YAChF,qDAAqD,CACxD,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,qBAAqB;IACnC,iBAAiB,GAAG,EAAE,CAAC;AACzB,CAAC;AAUD,gEAAgE;AAEhE;;GAEG;AACH,SAAS,YAAY,CAAC,MAA8B;IAClD,OAAO,MAAM;SACV,GAAG,CACF,CAAC,CAAC,EAAE,EAAE,CACJ,OAAO,CAAC,CAAC,IAAI,cAAc,CAAC,CAAC,QAAQ,cAAc,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAChF;SACA,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CACzB,QAAiB,EACjB,UAAkB;IAElB,MAAM,SAAS,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAEnC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO;YACL,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,uCAAuC,UAAU,gBAAgB;SAC3E,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAChB,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QACvC,CAAC,CAAC,oBAAoB,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;QACnD,CAAC,CAAC,EAAE,CAAC;IAET,OAAO;QACL,IAAI,EAAE,KAAK;QACX,OAAO,EAAE,mCAAmC,UAAU,4BAA4B,YAAY,EAAE;KACjG,CAAC;AACJ,CAAC;AAED,gEAAgE;AAEhE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,aAAa,CAE3B,QAAiB,EACjB,UAAkB;IAElB,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAEjD,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO;KAC9B,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@typokit/testing",
3
+ "exports": {
4
+ ".": {
5
+ "import": "./dist/index.js",
6
+ "types": "./dist/index.d.ts"
7
+ }
8
+ },
9
+ "version": "0.1.4",
10
+ "type": "module",
11
+ "files": [
12
+ "dist",
13
+ "src"
14
+ ],
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "dependencies": {
18
+ "@typokit/core": "0.1.4",
19
+ "@typokit/types": "0.1.4"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^22.0.0",
23
+ "@typokit/server-native": "0.1.4",
24
+ "@typokit/platform-node": "0.1.4"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/KyleBastien/typokit",
29
+ "directory": "packages/testing"
30
+ },
31
+ "scripts": {
32
+ "test": "rstest run --passWithNoTests"
33
+ }
34
+ }