@cdwr/core
Version:
A set of core utilities for the Codeware ecosystem.
288 lines (279 loc) • 9.43 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// packages/core/src/testing.ts
var testing_exports = {};
__export(testing_exports, {
SchemaRegistry: () => SchemaRegistry,
createSchemaTests: () => createSchemaTests
});
module.exports = __toCommonJS(testing_exports);
// packages/core/src/lib/testing/create-schema-tests.ts
var import_path2 = require("path");
var import_vitest = require("vitest");
// packages/core/src/lib/testing/import-schema-files.ts
var import_fast_glob = __toESM(require("fast-glob"), 1);
var importSchemaFiles = async (schemaDir) => {
const schemaFiles = await (0, import_fast_glob.default)(["**/**.schema.ts"], {
cwd: schemaDir,
absolute: true
});
await Promise.all(schemaFiles.map((file) => import(file)));
};
// packages/core/src/lib/testing/run-schema-tests.ts
var import_promises = require("fs/promises");
var import_path = require("path");
var import_fast_glob2 = __toESM(require("fast-glob"), 1);
// packages/core/src/lib/testing/schema-registry.class.ts
var SchemaRegistry = class {
static registry = /* @__PURE__ */ new Map();
/**
* Registers a schema against a fixture key.
*
* The fixture key should represent where to find the fixture data.
* For example, you have a fixture named `fly-app.json` that contains
* api data matching the schema.
*
* The fixture is stored in `{fixtures}/api/fly-app.json`,
* hence the fixture key for this schema would be `api/fly-app`.
*
* @param fixtureKey - The fixture key to register the schema against
* @param schema - The schema to register
* @param metadata - The metadata for the schema
*
* @example
*
* ```ts
* // app.schema.ts
* // Create a schema that is used in your
* // application or library
* const AppSchema = z.object({
* name: z.string(),
* region: z.string()
* });
*
* // schemas.spec.ts
* // Register the schema against a fixture key
* // to enable automated schema validation.
* // Tag `api` to group related schemas in the test report.
* SchemaRegistry.register('api/fly-app', AppSchema, {
* name: 'Fly app',
* tags: ['api']
* });
* ```
*/
static register(fixtureKey, schema, metadata) {
this.registry.set(fixtureKey, { schema, ...metadata });
}
static get(fixtureKey) {
return this.registry.get(fixtureKey);
}
static getByTag(tag) {
return Array.from(this.registry.entries()).filter(
(entry) => entry[1].tags?.includes(tag)
);
}
static getAll() {
return Array.from(this.registry.entries());
}
};
// packages/core/src/lib/testing/validate-schema.ts
var import_zod = require("zod");
function validateSchema(schema, data, options = {}) {
const schemaName = options.name || "Schema";
try {
const parsed = schema.parse(data);
return {
success: true,
details: `${schemaName} validation passed`,
parsed
};
} catch (error) {
if (error instanceof import_zod.z.ZodError) {
return {
success: false,
details: `${schemaName} validation failed`,
errors: error.errors.map((err) => ({
path: err.path,
code: err.code,
message: err.message
}))
};
}
return {
success: false,
details: `Unexpected error: ${error}`
};
}
}
// packages/core/src/lib/testing/run-schema-tests.ts
async function runSchemaTests(fixtureDir) {
const fixtures = await (0, import_fast_glob2.default)([`**/*.json`], {
cwd: fixtureDir,
absolute: true
});
const results = [];
for (const fullPixturePath of fixtures) {
try {
const fixtureFile = fullPixturePath.replace((0, import_path.join)(fixtureDir, "/"), "");
const fixtureKey = fixtureFile.replace(".json", "");
const metadata = SchemaRegistry.get(fixtureKey);
if (!metadata) {
results.push({
schemaName: `Unknown Schema (${fixtureKey})`,
status: "failure",
details: `No schema registered for fixture: ${fixtureKey}`,
fixtureFile,
fixtureKey,
metadata: void 0,
errors: null
});
continue;
}
const fixtureData = JSON.parse(await (0, import_promises.readFile)(fullPixturePath, "utf-8"));
const validationResult = validateSchema(metadata.schema, fixtureData, {
name: metadata.name
});
results.push({
schemaName: metadata.name,
status: validationResult.success ? "success" : "failure",
details: validationResult.details,
fixtureFile,
fixtureKey,
transformed: validationResult.parsed,
metadata,
errors: validationResult.errors
});
} catch (error) {
results.push({
schemaName: fullPixturePath,
status: "failure",
details: `Failed to process fixture: ${error}`,
fixtureFile: "",
fixtureKey: "",
metadata: void 0,
errors: null
});
}
}
for (const [fixtureKey, metadata] of SchemaRegistry.getAll()) {
if (!results.some((result) => result.schemaName === metadata.name)) {
results.push({
schemaName: metadata.name,
status: "skipped",
details: `No fixture found for schema: ${metadata.name}`,
fixtureFile: "",
fixtureKey,
metadata,
errors: null
});
}
}
return results.sort((a, b) => a.schemaName.localeCompare(b.schemaName));
}
// packages/core/src/lib/testing/create-schema-tests.ts
var logTestReport = (results) => {
console.table(
results.map(({ schemaName, status, fixtureFile }) => ({
Schema: schemaName,
Fixture: fixtureFile,
Status: status === "success" ? "\u2705" : status === "failure" ? "\u274C" : "\u26A0\uFE0F"
}))
);
};
var createSchemaTests = (options) => {
const {
schemaDir,
fixturesPath = "__fixtures__",
description = "Schema Validation",
groups = [],
snapshots = false
} = options;
(0, import_vitest.describe)(description, () => {
(0, import_vitest.it)("validates all schemas against fixtures", async () => {
await importSchemaFiles(schemaDir);
const results = await runSchemaTests((0, import_path2.join)(schemaDir, fixturesPath));
if (groups.length > 0) {
groups.forEach(({ name, tags }) => {
const groupResults = results.filter(
(result) => tags.some((tag) => result.metadata?.tags?.includes(tag))
);
if (groupResults.length > 0) {
console.log(`
${name} Schemas:`);
logTestReport(groupResults);
}
});
const ungroupedResults = results.filter(
(result) => !groups.some(
({ tags }) => tags.some((tag) => result.metadata?.tags?.includes(tag))
)
);
if (ungroupedResults.length > 0) {
console.log("\nOther Schemas:");
logTestReport(ungroupedResults);
}
} else if (results.length > 0) {
logTestReport(results);
} else {
console.log("No schemas to validate");
}
results.forEach(({ schemaName, details, errors, status }, index) => {
if (status === "success") {
return;
}
console.log(
`
${status === "skipped" ? "\u26A0\uFE0F " : "\u{1F534} "} [${index}] Schema validation ${status}: ${schemaName}`
);
if (details) {
console.log(" Details:", details);
}
if (errors) {
console.log(" Errors:", errors);
}
});
results.forEach((result) => {
if (result.status === "success" && snapshots) {
(0, import_vitest.expect)(result.transformed).toMatchSnapshot(
`${result.schemaName} transformed shape`
);
}
(0, import_vitest.expect)(
result.status !== "failure",
`Schema ${result.schemaName} validation failed`
).toBe(true);
});
});
});
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
SchemaRegistry,
createSchemaTests
});