mirror of
https://github.com/chenasraf/simple-scaffold.git
synced 2026-05-17 17:28:09 +00:00
232 lines
6.5 KiB
TypeScript
232 lines
6.5 KiB
TypeScript
import { describe, test, expect, beforeEach, afterEach } from "vitest"
|
|
import mockFs from "mock-fs"
|
|
import { Console } from "console"
|
|
import { validateConfig, validateTemplatePaths, assertConfigValid } from "../src/validate"
|
|
|
|
const validConfig = {
|
|
name: "test",
|
|
templates: ["templates"],
|
|
output: "output",
|
|
}
|
|
|
|
describe("validate", () => {
|
|
describe("validateConfig", () => {
|
|
test("returns no errors for valid config", () => {
|
|
expect(validateConfig(validConfig)).toEqual([])
|
|
})
|
|
|
|
test("returns no errors with all optional fields", () => {
|
|
const errors = validateConfig({
|
|
...validConfig,
|
|
subdir: true,
|
|
subdirHelper: "camelCase",
|
|
data: { key: "value" },
|
|
logLevel: "debug",
|
|
dryRun: true,
|
|
overwrite: true,
|
|
inputs: {
|
|
author: { type: "text", message: "Author", required: true },
|
|
},
|
|
})
|
|
expect(errors).toEqual([])
|
|
})
|
|
|
|
test("errors on missing name", () => {
|
|
const errors = validateConfig({ ...validConfig, name: "" })
|
|
expect(errors.length).toBeGreaterThan(0)
|
|
expect(errors[0]).toContain("name")
|
|
})
|
|
|
|
test("errors on missing templates", () => {
|
|
const errors = validateConfig({ ...validConfig, templates: [] })
|
|
expect(errors.length).toBeGreaterThan(0)
|
|
expect(errors[0]).toContain("templates")
|
|
})
|
|
|
|
test("errors on invalid logLevel", () => {
|
|
const errors = validateConfig({ ...validConfig, logLevel: "verbose" })
|
|
expect(errors.length).toBeGreaterThan(0)
|
|
expect(errors[0]).toContain("logLevel")
|
|
})
|
|
|
|
test("errors on subdirHelper without subdir", () => {
|
|
const errors = validateConfig({
|
|
...validConfig,
|
|
subdirHelper: "camelCase",
|
|
})
|
|
expect(errors.length).toBeGreaterThan(0)
|
|
expect(errors[0]).toContain("subdirHelper")
|
|
})
|
|
|
|
test("no error on subdirHelper with subdir", () => {
|
|
const errors = validateConfig({
|
|
...validConfig,
|
|
subdir: true,
|
|
subdirHelper: "camelCase",
|
|
})
|
|
expect(errors).toEqual([])
|
|
})
|
|
|
|
test("errors on select input without options", () => {
|
|
const errors = validateConfig({
|
|
...validConfig,
|
|
inputs: {
|
|
license: { type: "select" },
|
|
},
|
|
})
|
|
expect(errors.length).toBeGreaterThan(0)
|
|
expect(errors.some((e) => e.includes("select") && e.includes("options"))).toBe(true)
|
|
})
|
|
|
|
test("no error on select input with options", () => {
|
|
const errors = validateConfig({
|
|
...validConfig,
|
|
inputs: {
|
|
license: { type: "select", options: ["MIT", "Apache"] },
|
|
},
|
|
})
|
|
expect(errors).toEqual([])
|
|
})
|
|
|
|
test("errors on confirm input with non-boolean default", () => {
|
|
const errors = validateConfig({
|
|
...validConfig,
|
|
inputs: {
|
|
flag: { type: "confirm", default: "yes" },
|
|
},
|
|
})
|
|
expect(errors.length).toBeGreaterThan(0)
|
|
expect(errors.some((e) => e.includes("confirm") && e.includes("boolean"))).toBe(true)
|
|
})
|
|
|
|
test("errors on number input with non-number default", () => {
|
|
const errors = validateConfig({
|
|
...validConfig,
|
|
inputs: {
|
|
port: { type: "number", default: "3000" },
|
|
},
|
|
})
|
|
expect(errors.length).toBeGreaterThan(0)
|
|
expect(errors.some((e) => e.includes("number"))).toBe(true)
|
|
})
|
|
|
|
test("valid input types pass", () => {
|
|
const errors = validateConfig({
|
|
...validConfig,
|
|
inputs: {
|
|
a: { type: "text", required: true },
|
|
b: { type: "select", options: ["x", "y"] },
|
|
c: { type: "confirm", default: false },
|
|
d: { type: "number", default: 42 },
|
|
},
|
|
})
|
|
expect(errors).toEqual([])
|
|
})
|
|
|
|
test("accepts function output", () => {
|
|
const errors = validateConfig({
|
|
...validConfig,
|
|
output: () => "dynamic-output",
|
|
})
|
|
expect(errors).toEqual([])
|
|
})
|
|
|
|
test("accepts function overwrite", () => {
|
|
const errors = validateConfig({
|
|
...validConfig,
|
|
overwrite: () => true,
|
|
})
|
|
expect(errors).toEqual([])
|
|
})
|
|
|
|
test("accepts afterScaffold string", () => {
|
|
const errors = validateConfig({
|
|
...validConfig,
|
|
afterScaffold: "npm install",
|
|
})
|
|
expect(errors).toEqual([])
|
|
})
|
|
|
|
test("accepts afterScaffold function", () => {
|
|
const errors = validateConfig({
|
|
...validConfig,
|
|
afterScaffold: () => {},
|
|
})
|
|
expect(errors).toEqual([])
|
|
})
|
|
})
|
|
|
|
describe("validateTemplatePaths", () => {
|
|
beforeEach(() => {
|
|
console = new Console(process.stdout, process.stderr)
|
|
mockFs({
|
|
templates: { "file.txt": "content" },
|
|
})
|
|
})
|
|
|
|
afterEach(() => {
|
|
mockFs.restore()
|
|
})
|
|
|
|
test("returns no errors for existing paths", async () => {
|
|
const errors = await validateTemplatePaths(["templates"])
|
|
expect(errors).toEqual([])
|
|
})
|
|
|
|
test("returns error for missing paths", async () => {
|
|
const errors = await validateTemplatePaths(["nonexistent"])
|
|
expect(errors.length).toBe(1)
|
|
expect(errors[0]).toContain("nonexistent")
|
|
})
|
|
|
|
test("skips glob patterns", async () => {
|
|
const errors = await validateTemplatePaths(["templates/**/*"])
|
|
expect(errors).toEqual([])
|
|
})
|
|
|
|
test("skips negation patterns", async () => {
|
|
const errors = await validateTemplatePaths(["!excluded"])
|
|
expect(errors).toEqual([])
|
|
})
|
|
})
|
|
|
|
describe("assertConfigValid", () => {
|
|
beforeEach(() => {
|
|
console = new Console(process.stdout, process.stderr)
|
|
mockFs({
|
|
templates: { "file.txt": "content" },
|
|
})
|
|
})
|
|
|
|
afterEach(() => {
|
|
mockFs.restore()
|
|
})
|
|
|
|
test("does not throw for valid config", async () => {
|
|
await expect(assertConfigValid(validConfig)).resolves.toBeUndefined()
|
|
})
|
|
|
|
test("throws formatted error for invalid config", async () => {
|
|
await expect(assertConfigValid({ name: "", templates: [], output: "" })).rejects.toThrow(
|
|
"Invalid scaffold config",
|
|
)
|
|
})
|
|
|
|
test("includes all errors in message", async () => {
|
|
try {
|
|
await assertConfigValid({ name: "", templates: [], output: "out" })
|
|
} catch (e) {
|
|
const msg = (e as Error).message
|
|
expect(msg).toContain("name")
|
|
expect(msg).toContain("templates")
|
|
}
|
|
})
|
|
|
|
test("checks template path existence", async () => {
|
|
await expect(
|
|
assertConfigValid({ name: "test", templates: ["missing"], output: "out" }),
|
|
).rejects.toThrow("does not exist")
|
|
})
|
|
})
|
|
})
|