feat(KB-141): fix workspace type resolution and add clean-checkout typecheck tests

- Remove dist-dependent workspace type resolution from all tsconfig files

- Add clean-checkout typecheck regression test to CI suite

- Update package.json type definitions for core, engine, dashboard, and cli packages

- Update README with typecheck testing documentation

- Clean up unused test files and component dependencies
This commit is contained in:
gsxdsm
2026-03-30 08:24:16 -07:00
parent 55c4cb155e
commit 0e61a45d72
21 changed files with 186 additions and 59 deletions

View File

@@ -1,16 +1,105 @@
import { execFileSync } from "node:child_process";
import { execSync } from "node:child_process";
import { resolve } from "node:path";
import { describe, it, expect } from "vitest";
import { rename, access } from "node:fs/promises";
import { describe, it, expect, beforeAll, afterAll } from "vitest";
describe("typecheck", () => {
it("passes tsc --noEmit --skipLibCheck false", () => {
const cwd = resolve(__dirname, "../..");
expect(() =>
execFileSync("npx", ["tsc", "--noEmit", "--skipLibCheck", "false"], {
/**
* Clean-checkout typecheck regression test.
*
* This test verifies that `pnpm typecheck` succeeds from a clean checkout
* state without relying on pre-built dist/ artifacts. It temporarily moves
* any existing dist directories to ensure the typecheck runs against
* source files and project references.
*/
describe("clean-checkout typecheck", () => {
const cwd = resolve(__dirname, "../..");
const distPaths = [
"packages/core/dist",
"packages/engine/dist",
"packages/dashboard/dist",
"packages/cli/dist",
];
const movedSuffix = ".moved-for-test";
const movedPaths = distPaths.map((p) => `${p}${movedSuffix}`);
// Helper to check if a path exists
async function pathExists(path: string): Promise<boolean> {
try {
await access(path);
return true;
} catch {
return false;
}
}
beforeAll(async () => {
// Move any existing dist directories to simulate clean checkout
for (let i = 0; i < distPaths.length; i++) {
const distPath = resolve(cwd, distPaths[i]);
const movedPath = resolve(cwd, movedPaths[i]);
if (await pathExists(distPath)) {
await rename(distPath, movedPath);
}
}
});
afterAll(async () => {
// Restore moved directories even if test failed
for (let i = 0; i < distPaths.length; i++) {
const distPath = resolve(cwd, distPaths[i]);
const movedPath = resolve(cwd, movedPaths[i]);
if (await pathExists(movedPath)) {
try {
await rename(movedPath, distPath);
} catch {
// Best effort - if restore fails, we'll rebuild in subsequent steps
}
}
}
});
it("passes pnpm typecheck without relying on dist/ artifacts", () => {
let error: Error | null = null;
let stdout = "";
let stderr = "";
try {
stdout = execSync("pnpm typecheck", {
cwd,
stdio: "pipe",
timeout: 60_000,
}),
).not.toThrow();
encoding: "utf-8",
timeout: 120_000,
stdio: ["pipe", "pipe", "pipe"],
});
} catch (e) {
error = e as Error;
// Capture stdout/stderr from the error object if available
const execError = e as { stdout?: string; stderr?: string };
stdout = execError.stdout ?? "";
stderr = execError.stderr ?? "";
}
// Assertion-based verification - fail on non-zero exit
if (error) {
const failureContext = [
"pnpm typecheck failed with non-zero exit code",
"",
"--- STDOUT ---",
stdout,
"",
"--- STDERR ---",
stderr,
"",
"--- ERROR ---",
error.message,
].join("\n");
expect.fail(failureContext);
}
// Verify that typecheck ran and succeeded - just check no error was thrown
// The fact that we got here without error means it passed
expect(error).toBeNull();
});
});