Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/lib
/pnpm-lock.yaml
lib/
dist/
pnpm-lock.yaml
2 changes: 1 addition & 1 deletion packages/cli/src/commands/gen-emit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ async function processSourceFile(
}

if (lexicons.length === 0) {
console.warn(` ⚠ ${sourcePath}: No lexicon lexicons found`);
console.warn(` ⚠ ${sourcePath}: No lexicons found`);
return;
}

Expand Down
51 changes: 51 additions & 0 deletions packages/cli/tests/integration/cli.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { expect, test, describe } from "vitest";
import { runCLI } from "../test-utils.js";

describe("CLI Integration", () => {
test("shows error when called without arguments", async () => {
const { stdout, stderr, code } = await runCLI();
expect(code).toBe(1);
expect(stderr).toContain("No command specified");
expect(stderr).toContain("Run `$ prototypey --help` for more info");
});

test("shows version", async () => {
const { stdout, stderr } = await runCLI(["--version"]);
expect(stderr).toBe("");
expect(stdout).toContain("prototypey, 0.0.0");
});

test("shows help for gen-inferred command", async () => {
const { stdout, stderr } = await runCLI(["gen-inferred", "--help"]);
expect(stderr).toBe("");
expect(stdout).toContain("gen-inferred <outdir> <schemas...>");
expect(stdout).toContain(
"Generate type-inferred code from lexicon schemas",
);
});

test("shows help for gen-emit command", async () => {
const { stdout, stderr } = await runCLI(["gen-emit", "--help"]);
expect(stderr).toBe("");
expect(stdout).toContain("gen-emit <outdir> <sources...>");
expect(stdout).toContain(
"Emit JSON lexicon schemas from authored TypeScript",
);
});

test("handles unknown command", async () => {
const { stdout, stderr, code } = await runCLI(["unknown-command"]);
expect(code).toBe(1);
expect(stderr).toContain("Invalid command: unknown-command");
expect(stderr).toContain("Run `$ prototypey --help` for more info");
});

test("handles missing arguments", async () => {
const { stdout, stderr, code } = await runCLI(["gen-inferred"]);
expect(code).toBe(1);
expect(stderr).toContain("Insufficient arguments!");
expect(stderr).toContain(
"Run `$ prototypey gen-inferred --help` for more info",
);
});
});
155 changes: 155 additions & 0 deletions packages/cli/tests/integration/error-handling.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import { expect, test, describe, beforeEach, afterEach } from "vitest";
import { mkdir, writeFile, rm } from "node:fs/promises";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { runCLI } from "../test-utils.js";

describe("CLI Error Handling", () => {
let testDir: string;
let outDir: string;
let schemasDir: string;

beforeEach(async () => {
// Create a temporary directory for test files
testDir = join(tmpdir(), `prototypey-error-test-${Date.now()}`);
outDir = join(testDir, "output");
schemasDir = join(testDir, "schemas");
await mkdir(testDir, { recursive: true });
await mkdir(outDir, { recursive: true });
await mkdir(schemasDir, { recursive: true });
});

afterEach(async () => {
// Clean up test directory
await rm(testDir, { recursive: true, force: true });
});

test("handles non-existent schema files gracefully", async () => {
const { stdout, stderr, code } = await runCLI([
"gen-inferred",
outDir,
join(schemasDir, "non-existent.json"),
]);

expect(code).toBe(0); // Should not crash
expect(stdout).toContain("No schema files found matching patterns");
expect(stderr).toBe("");
});

test("handles invalid JSON schema files", async () => {
// Create an invalid JSON file
const invalidSchema = join(schemasDir, "invalid.json");
await writeFile(invalidSchema, "not valid json");

const { stdout, stderr, code } = await runCLI([
"gen-inferred",
outDir,
invalidSchema,
]);

expect(code).toBe(1); // Should exit with error
expect(stderr).toContain("Error generating inferred types");
});

test("handles schema files with missing id", async () => {
// Create a schema with missing id
const schemaFile = join(schemasDir, "missing-id.json");
await writeFile(
schemaFile,
JSON.stringify({
lexicon: 1,
defs: { main: { type: "record" } },
}),
);

const { stdout, stderr, code } = await runCLI([
"gen-inferred",
outDir,
schemaFile,
]);

expect(code).toBe(0); // Should not crash
expect(stdout).toContain("Found 1 schema file(s)");
expect(stdout).toContain("Generated inferred types in");
// Should skip the invalid file silently
});

test("handles schema files with missing defs", async () => {
// Create a schema with missing defs
const schemaFile = join(schemasDir, "missing-defs.json");
await writeFile(
schemaFile,
JSON.stringify({
lexicon: 1,
id: "app.test.missing",
}),
);

const { stdout, stderr, code } = await runCLI([
"gen-inferred",
outDir,
schemaFile,
]);

expect(code).toBe(0); // Should not crash
expect(stdout).toContain("Found 1 schema file(s)");
expect(stdout).toContain("Generated inferred types in");
// Should skip the invalid file silently
});

test("handles non-existent source files for gen-emit", async () => {
const { stdout, stderr, code } = await runCLI([
"gen-emit",
outDir,
join(schemasDir, "non-existent.ts"),
]);

expect(code).toBe(0); // Should not crash
expect(stdout).toContain("No source files found matching patterns");
expect(stderr).toBe("");
});

test("handles valid TypeScript files with no lexicon exports for gen-emit", async () => {
// Create a valid TypeScript file with no lexicon exports
const validSource = join(schemasDir, "no-namespace.ts");
await writeFile(validSource, "export const x = 1;");

const { stdout, stderr, code } = await runCLI([
"gen-emit",
outDir,
validSource,
]);

expect(code).toBe(0); // Should not crash
expect(stdout).toContain("Found 1 source file(s)");
expect(stderr).toContain("No lexicons found");
});

test("handles permission errors when writing output", async () => {
// This test might be platform-specific, so we'll make it lenient
// Create a schema file first
const schemaFile = join(schemasDir, "test.json");
await writeFile(
schemaFile,
JSON.stringify({
lexicon: 1,
id: "app.test.permission",
defs: { main: { type: "record" } },
}),
);

// Try to write to a directory that might have permission issues
// We'll use a path that likely won't exist and is invalid
const invalidOutDir = "/invalid/path/that/does/not/exist";

const { stdout, stderr, code } = await runCLI([
"gen-inferred",
invalidOutDir,
schemaFile,
]);

// Should handle the error gracefully
expect(code).toBe(1);
expect(stderr).toContain("Error generating inferred types");
});
});
Loading