300 lines
8.6 KiB
TypeScript
300 lines
8.6 KiB
TypeScript
import { expect, test, beforeEach, afterEach } from 'bun:test'
|
|
import { initRenderer, SchemaMismatchError } from ".";
|
|
import { z } from "zod"
|
|
import { mkdtempSync, rmSync, existsSync, readFileSync } from "node:fs"
|
|
import { join } from "node:path"
|
|
import { tmpdir } from "node:os"
|
|
|
|
const ifExampleSchema = z.object({
|
|
web: z.boolean(),
|
|
header: z.object({
|
|
render: z.boolean(),
|
|
text: z.string()
|
|
})
|
|
})
|
|
|
|
let tmp: string
|
|
|
|
beforeEach(() => {
|
|
tmp = mkdtempSync(join(tmpdir(), "tdir-test-"))
|
|
})
|
|
|
|
afterEach(() => {
|
|
rmSync(tmp, { recursive: true, force: true })
|
|
})
|
|
|
|
test("createRenderer validates schema matches templates", () => {
|
|
const createRenderer = initRenderer("./testdata/if_example")
|
|
expect(() => createRenderer(ifExampleSchema)).not.toThrow()
|
|
expect(() => createRenderer(z.object({ web: z.boolean() }))).toThrow(SchemaMismatchError)
|
|
expect(() => createRenderer(z.object({
|
|
web: z.string(),
|
|
header: z.object({ render: z.boolean(), text: z.string() })
|
|
}))).toThrow(SchemaMismatchError)
|
|
})
|
|
|
|
test("render validates context via zod", () => {
|
|
const createRenderer = initRenderer("./testdata/if_example")
|
|
const render = createRenderer(ifExampleSchema)
|
|
expect(() => render(tmp, {} as any)).toThrow(z.ZodError)
|
|
expect(() => render(tmp, { web: "nope" } as any)).toThrow(z.ZodError)
|
|
expect(() => render(tmp, { web: true, header: { render: true } } as any)).toThrow(z.ZodError)
|
|
})
|
|
|
|
test("renders with web=true, header rendered", () => {
|
|
const createRenderer = initRenderer("./testdata/if_example")
|
|
const render = createRenderer(ifExampleSchema)
|
|
render(tmp, { web: true, header: { render: true, text: "My Title" } })
|
|
|
|
const outFile = join(tmp, "web", "if_example.html")
|
|
expect(existsSync(outFile)).toBe(true)
|
|
|
|
const content = readFileSync(outFile, "utf-8")
|
|
expect(content).toContain("My Title")
|
|
expect(content).toContain("<head>")
|
|
expect(content).toContain("<body>")
|
|
})
|
|
|
|
test("wrong schema throws error",() => {
|
|
const createRenderer = initRenderer("./testdata/if_example")
|
|
expect(() => createRenderer(z.object({
|
|
web: z.string(),
|
|
header: z.object({
|
|
render: z.string(),
|
|
text: z.boolean()
|
|
})
|
|
}))).toThrow(new SchemaMismatchError({message: 'expected z.boolean() but schema has z.string()', path: 'web'}))
|
|
})
|
|
|
|
test("wrong schema throws error",() => {
|
|
const createRenderer = initRenderer("./testdata/if_example")
|
|
expect(() => createRenderer(z.object({
|
|
web: z.boolean(),
|
|
header: z.object({
|
|
render: z.string(),
|
|
text: z.boolean()
|
|
})
|
|
}))).toThrow(new SchemaMismatchError({message: 'expected z.boolean() but schema has z.string()', path: 'header.render'}))
|
|
})
|
|
|
|
test("wrong schema throws error",() => {
|
|
const createRenderer = initRenderer("./testdata/if_example")
|
|
expect(() => createRenderer(z.object({
|
|
web: z.boolean(),
|
|
header: z.object({
|
|
render: z.boolean(),
|
|
text: z.boolean()
|
|
})
|
|
}))).toThrow(new SchemaMismatchError({message: 'expected z.string() but schema has z.boolean()', path: 'header.text'}))
|
|
})
|
|
|
|
test("renders with web=true, header not rendered", () => {
|
|
const createRenderer = initRenderer("./testdata/if_example")
|
|
const render = createRenderer(ifExampleSchema)
|
|
render(tmp, { web: true, header: { render: false, text: "Ignored" } })
|
|
|
|
const outFile = join(tmp, "web", "if_example.html")
|
|
expect(existsSync(outFile)).toBe(true)
|
|
|
|
const content = readFileSync(outFile, "utf-8")
|
|
expect(content).not.toContain("Ignored")
|
|
expect(content).not.toContain("<head>")
|
|
expect(content).toContain("<body>")
|
|
})
|
|
|
|
test("renders with web=false, skips directory", () => {
|
|
const createRenderer = initRenderer("./testdata/if_example")
|
|
const render = createRenderer(ifExampleSchema)
|
|
render(tmp, { web: false, header: { render: true, text: "Hello" } })
|
|
|
|
expect(existsSync(join(tmp, "web"))).toBe(false)
|
|
})
|
|
|
|
test("vars in path are added to schema",() => {
|
|
const createRenderer = initRenderer("./testdata/var_in_path")
|
|
expect(() => createRenderer(z.object({
|
|
web: z.boolean(),
|
|
header: z.object({
|
|
render: z.boolean(),
|
|
text: z.boolean()
|
|
})
|
|
}))).toThrow(new SchemaMismatchError({message: 'expected z.object() but schema has z.boolean()', path: 'web'}))
|
|
})
|
|
|
|
test("vars in path renders correctrly",() => {
|
|
const createRenderer = initRenderer("./testdata/var_in_path")
|
|
const render = createRenderer(z.object({
|
|
web: z.object({
|
|
create: z.boolean(),
|
|
dir: z.string()
|
|
}),
|
|
header: z.object({
|
|
render: z.boolean(),
|
|
text: z.string()
|
|
})
|
|
}))
|
|
render(tmp,{
|
|
web: {
|
|
create: true,
|
|
dir: "web"
|
|
},
|
|
header: {
|
|
render: false,
|
|
text: "test"
|
|
}
|
|
})
|
|
expect(existsSync(join(tmp, "web"))).toBe(true)
|
|
const outFile = join(tmp, "web", "var_in_path_example.html")
|
|
expect(existsSync(outFile)).toBe(true)
|
|
|
|
const content = readFileSync(outFile, "utf-8")
|
|
expect(content).not.toContain("Ignored")
|
|
expect(content).not.toContain("<head>")
|
|
expect(content).toContain("<body>")
|
|
})
|
|
|
|
test("vars in path renders correctrly",() => {
|
|
const createRenderer = initRenderer("./testdata/var_in_path")
|
|
const render = createRenderer(z.object({
|
|
web: z.object({
|
|
create: z.boolean(),
|
|
dir: z.string()
|
|
}),
|
|
header: z.object({
|
|
render: z.boolean(),
|
|
text: z.string()
|
|
})
|
|
}))
|
|
render(tmp,{
|
|
web: {
|
|
create: true,
|
|
dir: "test"
|
|
},
|
|
header: {
|
|
render: true,
|
|
text: "test"
|
|
}
|
|
})
|
|
expect(existsSync(join(tmp, "test"))).toBe(true)
|
|
const outFile = join(tmp, "test", "var_in_path_example.html")
|
|
expect(existsSync(outFile)).toBe(true)
|
|
|
|
const content = readFileSync(outFile, "utf-8")
|
|
expect(content).toContain("test")
|
|
expect(content).toContain("<head>")
|
|
expect(content).toContain("<body>")
|
|
})
|
|
|
|
test("nested if dir renders correctly",() => {
|
|
const createRenderer = initRenderer("./testdata/nested_if_dir")
|
|
const render = createRenderer(z.object({
|
|
web: z.boolean(),
|
|
webnested: z.boolean()
|
|
}))
|
|
render(tmp,{
|
|
web: true,
|
|
webnested: true
|
|
})
|
|
expect(existsSync(join(tmp, "web"))).toBe(true)
|
|
})
|
|
|
|
test("nested if dir renders correctly",() => {
|
|
const createRenderer = initRenderer("./testdata/nested_if_dir_named")
|
|
const render = createRenderer(z.object({
|
|
web: z.boolean(),
|
|
webnested: z.boolean()
|
|
}))
|
|
render(tmp,{
|
|
web: true,
|
|
webnested: true
|
|
})
|
|
expect(existsSync(join(tmp, "nested" , "web"))).toBe(true)
|
|
})
|
|
|
|
test("multiple dirs 1 var",() => {
|
|
const createRenderer = initRenderer("./testdata/multi_dir_one_var")
|
|
const render = createRenderer(z.object({
|
|
web: z.boolean(),
|
|
}))
|
|
render(tmp,{
|
|
web: true,
|
|
})
|
|
expect(existsSync(join(tmp, "dir1"))).toBe(true)
|
|
expect(existsSync(join(tmp, "dir2"))).toBe(true)
|
|
expect(existsSync(join(tmp, "dir1", "dir1n"))).toBe(true)
|
|
})
|
|
|
|
test("file if",() => {
|
|
const createRenderer = initRenderer("./testdata/file_if")
|
|
const render = createRenderer(z.object({
|
|
web: z.boolean(),
|
|
file: z.boolean(),
|
|
text: z.string()
|
|
}))
|
|
render(tmp,{
|
|
web: true,
|
|
file: true,
|
|
text: "test"
|
|
})
|
|
expect(existsSync(join(tmp, "web"))).toBe(true)
|
|
const outFile = join(tmp, "web", "example.txt")
|
|
expect(existsSync(outFile)).toBe(true)
|
|
|
|
const content = readFileSync(outFile, "utf-8")
|
|
expect(content).toContain("test")
|
|
})
|
|
|
|
test("no endif should throw",() => {
|
|
const createRenderer = initRenderer("./testdata/no_end_if")
|
|
const render = createRenderer(z.object({
|
|
test: z.boolean(),
|
|
}))
|
|
expect( () => render(tmp,{
|
|
test: true,
|
|
})).toThrow()
|
|
})
|
|
|
|
test("if elseif else",() => {
|
|
const createRenderer = initRenderer("./testdata/if_elseif_else_in_file")
|
|
const render = createRenderer(z.object({
|
|
test: z.boolean(),
|
|
test2: z.boolean()
|
|
}))
|
|
render(tmp,{
|
|
test: true,
|
|
test2: true
|
|
})
|
|
let outFile = join(tmp, "test.txt")
|
|
expect(existsSync(outFile)).toBe(true)
|
|
|
|
let content = readFileSync(outFile, "utf-8")
|
|
expect(content).toContain("test")
|
|
render(tmp,{
|
|
test: false,
|
|
test2: true
|
|
})
|
|
outFile = join(tmp, "test.txt")
|
|
expect(existsSync(outFile)).toBe(true)
|
|
|
|
content = readFileSync(outFile, "utf-8")
|
|
expect(content).toContain("test2")
|
|
render(tmp,{
|
|
test: false,
|
|
test2: false
|
|
})
|
|
outFile = join(tmp, "test.txt")
|
|
expect(existsSync(outFile)).toBe(true)
|
|
|
|
content = readFileSync(outFile, "utf-8")
|
|
expect(content).toContain("test3")
|
|
})
|
|
|
|
test("if eq in path", () => {
|
|
const createRenderer = initRenderer("./testdata/eq_in_path")
|
|
const render = createRenderer(z.object({test: z.string()}))
|
|
render(tmp,{test:"test"})
|
|
expect(existsSync(join(tmp,"test"))).toBe(true)
|
|
render(tmp,{test:"foo"})
|
|
expect(existsSync(join(tmp,"test"))).toBe(false)
|
|
})
|