test: remove all test files for a clean restart (task 0003)
Temporary: clear the entire test suite (unit, subprocess, the shared helper, and the parser-integration placeholder) so the tests can be rebuilt from scratch. Fixtures and the test tooling (bunfig, report script) are kept. Note: `bun test` now errors on an empty suite, so the flake's tests check is red until tests return.
This commit is contained in:
@@ -1,25 +0,0 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
|
||||||
|
|
||||||
import { runCli } from "./test-support.ts";
|
|
||||||
|
|
||||||
const CLI = `${import.meta.dir}/index.ts`;
|
|
||||||
|
|
||||||
describe("cli", () => {
|
|
||||||
test("exits with non-zero code when no file argument is given", async () => {
|
|
||||||
const { exitCode, stderr } = await runCli(["view"], CLI);
|
|
||||||
|
|
||||||
expect(exitCode).not.toBe(0);
|
|
||||||
expect(stderr).toMatch(/missing required argument|usage/i);
|
|
||||||
});
|
|
||||||
test("exits with non-zero code when file does not exist", async () => {
|
|
||||||
const { exitCode, stderr } = await runCli(
|
|
||||||
["view", "/no/such/kitchen-recipe-does-not-exist.md"],
|
|
||||||
CLI,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(exitCode).toBe(1);
|
|
||||||
expect(stderr.trim().length).toBeGreaterThan(0);
|
|
||||||
expect(stderr).toMatch(/cannot read|no such file|ENOENT/i);
|
|
||||||
expect(stderr).toContain("/no/such/kitchen-recipe-does-not-exist.md");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
|
||||||
import { join } from "node:path";
|
|
||||||
|
|
||||||
import { runCli, stripAnsi } from "./test-support.ts";
|
|
||||||
|
|
||||||
const CLI = `${import.meta.dir}/index.ts`;
|
|
||||||
const FIXTURE = join(import.meta.dir, "..", "..", "..", "fixtures", "prose.md");
|
|
||||||
|
|
||||||
describe("cli — integration", () => {
|
|
||||||
test("renders a real recipe fixture end-to-end", async () => {
|
|
||||||
const { exitCode, stdout } = await runCli(["view", FIXTURE], CLI);
|
|
||||||
const output = stripAnsi(stdout);
|
|
||||||
const lines = output.split("\n");
|
|
||||||
const lineOf = (needle: string): number => lines.findIndex((line) => line.includes(needle));
|
|
||||||
|
|
||||||
expect(exitCode).toBe(0);
|
|
||||||
|
|
||||||
expect(output).toContain("title: Buttered Toast");
|
|
||||||
expect(output).toContain("servings: 2");
|
|
||||||
expect(output).toContain("tags:");
|
|
||||||
expect(output).toContain("breakfast");
|
|
||||||
expect(output).toContain("simple");
|
|
||||||
|
|
||||||
expect(lines.some((line) => /^─+$/.test(line))).toBe(true);
|
|
||||||
|
|
||||||
expect(output).toContain("Buttered Toast");
|
|
||||||
expect(output).toContain("Method");
|
|
||||||
expect(output).toContain("Timing");
|
|
||||||
expect(output).toContain("Serving");
|
|
||||||
|
|
||||||
expect(output).toContain("The simplest breakfast");
|
|
||||||
expect(output).toContain("Toast the bread until golden on both sides.");
|
|
||||||
expect(output).toContain("Spread the butter while the toast is still warm");
|
|
||||||
expect(output).toContain("Cut into triangles and serve at once.");
|
|
||||||
|
|
||||||
const separatorLine = lines.findIndex((line) => /^─+$/.test(line));
|
|
||||||
expect(lineOf("servings: 2")).toBeLessThan(separatorLine);
|
|
||||||
expect(separatorLine).toBeLessThan(lineOf("Method"));
|
|
||||||
expect(lineOf("Method")).toBeLessThan(lineOf("Timing"));
|
|
||||||
expect(lineOf("Timing")).toBeLessThan(lineOf("Serving"));
|
|
||||||
expect(lineOf("Method")).toBeLessThan(lineOf("Toast the bread until golden on both sides."));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
|
||||||
|
|
||||||
import type { DocumentAST } from "@kitchen-md/core";
|
|
||||||
import chalk from "chalk";
|
|
||||||
|
|
||||||
import { render } from "./render.ts";
|
|
||||||
import { stripAnsi } from "./test-support.ts";
|
|
||||||
|
|
||||||
describe("render", () => {
|
|
||||||
test("renders a paragraph as prose followed by a blank line", () => {
|
|
||||||
const ast: DocumentAST = {
|
|
||||||
frontmatter: {},
|
|
||||||
blocks: [{ type: "paragraph", children: [{ type: "text", value: "Hello world" }] }],
|
|
||||||
diagnostics: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(stripAnsi(render(ast))).toBe("Hello world\n\n");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("renders a heading followed by a single newline (not a blank line)", () => {
|
|
||||||
const ast: DocumentAST = {
|
|
||||||
frontmatter: {},
|
|
||||||
blocks: [{ type: "heading", level: 2, children: [{ type: "text", value: "Batter" }] }],
|
|
||||||
diagnostics: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(stripAnsi(render(ast))).toBe("Batter\n");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("renders frontmatter as raw YAML before the body", () => {
|
|
||||||
const ast: DocumentAST = {
|
|
||||||
frontmatter: { title: "Classic Pancakes", servings: 4 },
|
|
||||||
blocks: [{ type: "paragraph", children: [{ type: "text", value: "A simple breakfast." }] }],
|
|
||||||
diagnostics: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
const output = stripAnsi(render(ast));
|
|
||||||
|
|
||||||
expect(output.startsWith("title: Classic Pancakes\nservings: 4\n")).toBe(true);
|
|
||||||
expect(output).toContain("A simple breakfast.");
|
|
||||||
expect(output.indexOf("title: Classic Pancakes")).toBeLessThan(
|
|
||||||
output.indexOf("A simple breakfast."),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("renders a visual separator between the frontmatter and the body", () => {
|
|
||||||
const ast: DocumentAST = {
|
|
||||||
frontmatter: { title: "Classic Pancakes", servings: 4 },
|
|
||||||
blocks: [{ type: "paragraph", children: [{ type: "text", value: "A simple breakfast." }] }],
|
|
||||||
diagnostics: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
const lines = stripAnsi(render(ast)).split("\n");
|
|
||||||
const separatorIndex = lines.findIndex((line) => /^─+$/.test(line));
|
|
||||||
const frontmatterIndex = lines.findIndex((line) => line.includes("servings: 4"));
|
|
||||||
const bodyIndex = lines.findIndex((line) => line.includes("A simple breakfast."));
|
|
||||||
|
|
||||||
expect(separatorIndex).toBeGreaterThan(-1);
|
|
||||||
expect(separatorIndex).toBeGreaterThan(frontmatterIndex);
|
|
||||||
expect(separatorIndex).toBeLessThan(bodyIndex);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("styles headings distinctly by level and suppresses ANSI when colour is disabled", () => {
|
|
||||||
const h1: DocumentAST = {
|
|
||||||
frontmatter: {},
|
|
||||||
blocks: [{ type: "heading", level: 1, children: [{ type: "text", value: "Title" }] }],
|
|
||||||
diagnostics: [],
|
|
||||||
};
|
|
||||||
const h2: DocumentAST = {
|
|
||||||
frontmatter: {},
|
|
||||||
blocks: [{ type: "heading", level: 2, children: [{ type: "text", value: "Title" }] }],
|
|
||||||
diagnostics: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
const original = chalk.level;
|
|
||||||
try {
|
|
||||||
chalk.level = 1;
|
|
||||||
expect(render(h1)).toContain("\x1b[");
|
|
||||||
expect(render(h1)).not.toBe(render(h2));
|
|
||||||
|
|
||||||
chalk.level = 0;
|
|
||||||
expect(render(h1)).not.toContain("\x1b[");
|
|
||||||
} finally {
|
|
||||||
chalk.level = original;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
|
||||||
|
|
||||||
import { runCli } from "./test-support.ts";
|
|
||||||
|
|
||||||
describe("smoke", () => {
|
|
||||||
test("kitchen --help exits with code 0", async () => {
|
|
||||||
const { exitCode, stdout } = await runCli(["--help"], `${import.meta.dir}/index.ts`);
|
|
||||||
|
|
||||||
expect(exitCode).toBe(0);
|
|
||||||
expect(stdout).toMatch(/view/);
|
|
||||||
});
|
|
||||||
test.todo("kitchen parse <fixture> outputs structured JSON covering all annotation types");
|
|
||||||
});
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
export const stripAnsi = (s: string): string => s.replace(/\[[0-9;]*m/g, "");
|
|
||||||
|
|
||||||
export async function runCli(args: string[], cli: string) {
|
|
||||||
const proc = Bun.spawn(["bun", cli, ...args], { stdout: "pipe", stderr: "pipe" });
|
|
||||||
const exitCode = await proc.exited;
|
|
||||||
const stdout = await new Response(proc.stdout).text();
|
|
||||||
const stderr = await new Response(proc.stderr).text();
|
|
||||||
return { exitCode, stdout, stderr };
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
|
||||||
import { join } from "node:path";
|
|
||||||
|
|
||||||
import { stripAnsi } from "./test-support.ts";
|
|
||||||
import { formatViewError, viewFile } from "./view.ts";
|
|
||||||
|
|
||||||
const FIXTURE = join(import.meta.dir, "..", "..", "..", "fixtures", "prose.md");
|
|
||||||
|
|
||||||
describe("view", () => {
|
|
||||||
test("returns Ok with rendered output for a real recipe", () => {
|
|
||||||
const result = viewFile(FIXTURE);
|
|
||||||
|
|
||||||
expect(result.isOk()).toBe(true);
|
|
||||||
|
|
||||||
const output = stripAnsi(result._unsafeUnwrap());
|
|
||||||
expect(output).toContain("title: Buttered Toast");
|
|
||||||
expect(output).toContain("servings: 2");
|
|
||||||
expect(output).toMatch(/─+/);
|
|
||||||
expect(output).toContain("Buttered Toast");
|
|
||||||
expect(output).toContain("Method");
|
|
||||||
expect(output).toContain("Toast the bread until golden on both sides.");
|
|
||||||
expect(output).toContain("Cut into triangles and serve at once.");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("returns Err with a read-failed error for a missing file", () => {
|
|
||||||
const result = viewFile("/no/such/kitchen-view-missing.md");
|
|
||||||
|
|
||||||
expect(result.isErr()).toBe(true);
|
|
||||||
|
|
||||||
const error = result._unsafeUnwrapErr();
|
|
||||||
expect(error.tag).toBe("read-failed");
|
|
||||||
expect(error.path).toBe("/no/such/kitchen-view-missing.md");
|
|
||||||
expect(error.cause).toMatch(/ENOENT|no such file/i);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("formats a read-failed error as a human-readable message", () => {
|
|
||||||
expect(formatViewError({ tag: "read-failed", path: "/tmp/x.md", cause: "boom" })).toBe(
|
|
||||||
"cannot read '/tmp/x.md': boom",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
import { describe, test } from "bun:test";
|
|
||||||
|
|
||||||
describe("parser — integration", () => {
|
|
||||||
test.todo("parses the primary fixture into the complete Document AST");
|
|
||||||
test.todo("extracts every annotation type from the primary fixture");
|
|
||||||
test.todo("extracts an annotation from inside the fixture's blockquote");
|
|
||||||
test.todo("normalises the fixture's non-canonical unit (tablespoons -> tbsp)");
|
|
||||||
});
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
|
||||||
|
|
||||||
import { parse } from "./parse.ts";
|
|
||||||
|
|
||||||
describe("parser", () => {
|
|
||||||
describe("frontmatter", () => {
|
|
||||||
test("parses frontmatter fields as-is", () => {
|
|
||||||
const source =
|
|
||||||
"---\ntitle: Classic Pancakes\nservings: 4\ntags: [breakfast, quick]\n---\n\n# Classic Pancakes";
|
|
||||||
|
|
||||||
const result = parse(source);
|
|
||||||
|
|
||||||
expect(result.frontmatter).toEqual({
|
|
||||||
title: "Classic Pancakes",
|
|
||||||
servings: 4,
|
|
||||||
tags: ["breakfast", "quick"],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
test("returns an empty object for empty frontmatter", () => {
|
|
||||||
const source = "---\n---\n\n# Title";
|
|
||||||
|
|
||||||
const result = parse(source);
|
|
||||||
|
|
||||||
expect(result.frontmatter).toEqual({});
|
|
||||||
expect(result.blocks).toContainEqual({
|
|
||||||
type: "heading",
|
|
||||||
level: 1,
|
|
||||||
children: [{ type: "text", value: "Title" }],
|
|
||||||
});
|
|
||||||
expect(result.diagnostics).toEqual([]);
|
|
||||||
});
|
|
||||||
test("returns an empty object when there is no frontmatter", () => {
|
|
||||||
const result = parse("# Title");
|
|
||||||
|
|
||||||
expect(result.frontmatter).toEqual({});
|
|
||||||
expect(result.diagnostics).toEqual([]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("blocks", () => {
|
|
||||||
test("parses headings at every level (1-6)", () => {
|
|
||||||
const source = "# H1\n\n## H2\n\n### H3\n\n#### H4\n\n##### H5\n\n###### H6";
|
|
||||||
|
|
||||||
const result = parse(source);
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
frontmatter: {},
|
|
||||||
blocks: [
|
|
||||||
{ type: "heading", level: 1, children: [{ type: "text", value: "H1" }] },
|
|
||||||
{ type: "heading", level: 2, children: [{ type: "text", value: "H2" }] },
|
|
||||||
{ type: "heading", level: 3, children: [{ type: "text", value: "H3" }] },
|
|
||||||
{ type: "heading", level: 4, children: [{ type: "text", value: "H4" }] },
|
|
||||||
{ type: "heading", level: 5, children: [{ type: "text", value: "H5" }] },
|
|
||||||
{ type: "heading", level: 6, children: [{ type: "text", value: "H6" }] },
|
|
||||||
],
|
|
||||||
diagnostics: [],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
test("keeps blocks flat and in document order (a heading is a sibling of the following paragraph)", () => {
|
|
||||||
const result = parse("# Batter\n\nSift the flour into a bowl.");
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
frontmatter: {},
|
|
||||||
blocks: [
|
|
||||||
{ type: "heading", level: 1, children: [{ type: "text", value: "Batter" }] },
|
|
||||||
{
|
|
||||||
type: "paragraph",
|
|
||||||
children: [{ type: "text", value: "Sift the flour into a bowl." }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
diagnostics: [],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
test("parses paragraphs with typed inline nodes", () => {
|
|
||||||
const result = parse("Hello world");
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
frontmatter: {},
|
|
||||||
blocks: [
|
|
||||||
{
|
|
||||||
type: "paragraph",
|
|
||||||
children: [{ type: "text", value: "Hello world" }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
diagnostics: [],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user