feat: enforce frontend quality guardrails
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { dirname, join } from "node:path";
|
||||
import test from "node:test";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const scriptsDirectory = dirname(fileURLToPath(import.meta.url));
|
||||
const projectDirectory = dirname(scriptsDirectory);
|
||||
const dependencyCruiser = join(
|
||||
projectDirectory,
|
||||
"node_modules/dependency-cruiser/bin/dependency-cruise.mjs",
|
||||
);
|
||||
const dependencyConfig = join(projectDirectory, "dependency-cruiser.cjs");
|
||||
|
||||
async function withFixture(files, run) {
|
||||
const fixtureDirectory = await mkdtemp(join(tmpdir(), "wealth-ledger-deps-"));
|
||||
try {
|
||||
await Promise.all(
|
||||
Object.entries(files).map(async ([relativePath, contents]) => {
|
||||
const filePath = join(fixtureDirectory, relativePath);
|
||||
await mkdir(dirname(filePath), { recursive: true });
|
||||
await writeFile(filePath, contents);
|
||||
}),
|
||||
);
|
||||
return await run(fixtureDirectory);
|
||||
} finally {
|
||||
await rm(fixtureDirectory, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
function cruise(fixtureDirectory) {
|
||||
return spawnSync(
|
||||
process.execPath,
|
||||
[
|
||||
dependencyCruiser,
|
||||
"src",
|
||||
"--config",
|
||||
dependencyConfig,
|
||||
"--output-type",
|
||||
"err-long",
|
||||
],
|
||||
{ cwd: fixtureDirectory, encoding: "utf8" },
|
||||
);
|
||||
}
|
||||
|
||||
function output(result) {
|
||||
return `${result.stdout}${result.stderr}`;
|
||||
}
|
||||
|
||||
test("rejects a source import cycle", async () => {
|
||||
await withFixture(
|
||||
{
|
||||
"tsconfig.app.json": JSON.stringify({ compilerOptions: {} }),
|
||||
"src/shared/i18n/index.ts": 'export { value } from "./zod";\n',
|
||||
"src/shared/i18n/zod.ts": 'export { value } from ".";\n',
|
||||
},
|
||||
(fixtureDirectory) => {
|
||||
const result = cruise(fixtureDirectory);
|
||||
assert.notEqual(result.status, 0, output(result));
|
||||
assert.match(output(result), /no-circular/);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test("rejects a deep import into another slice", async () => {
|
||||
await withFixture(
|
||||
{
|
||||
"tsconfig.app.json": JSON.stringify({ compilerOptions: {} }),
|
||||
"src/features/auth/ui/Form.ts": 'import "../../../shared/i18n/zod";\n',
|
||||
"src/shared/i18n/index.ts": "export {};\n",
|
||||
"src/shared/i18n/zod.ts": "export {};\n",
|
||||
},
|
||||
(fixtureDirectory) => {
|
||||
const result = cruise(fixtureDirectory);
|
||||
assert.notEqual(result.status, 0, output(result));
|
||||
assert.match(output(result), /slices-must-use-public-api/);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test("rejects an index.tsx import from another slice", async () => {
|
||||
await withFixture(
|
||||
{
|
||||
"tsconfig.app.json": JSON.stringify({ compilerOptions: {} }),
|
||||
"src/features/auth/ui/Form.ts": 'import "../../../shared/i18n";\n',
|
||||
"src/shared/i18n/index.tsx": "export {};\n",
|
||||
},
|
||||
(fixtureDirectory) => {
|
||||
const result = cruise(fixtureDirectory);
|
||||
assert.notEqual(result.status, 0, output(result));
|
||||
assert.match(output(result), /slices-must-use-public-api/);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test("allows imports within a slice and through another slice public API", async () => {
|
||||
await withFixture(
|
||||
{
|
||||
"tsconfig.app.json": JSON.stringify({ compilerOptions: {} }),
|
||||
"src/features/auth/model/local.ts": "export const local = true;\n",
|
||||
"src/features/auth/ui/Form.ts": [
|
||||
'import { local } from "../model/local";\n',
|
||||
'import { value } from "../../../shared/i18n";\n',
|
||||
"void local;\n",
|
||||
"void value;\n",
|
||||
].join(""),
|
||||
"src/shared/i18n/index.ts": 'export { value } from "./zod";\n',
|
||||
"src/shared/i18n/zod.ts": "export const value = true;\n",
|
||||
},
|
||||
(fixtureDirectory) => {
|
||||
const result = cruise(fixtureDirectory);
|
||||
assert.equal(result.status, 0, output(result));
|
||||
},
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user