diff --git a/.claude/tasks/0003-view-skeleton.md b/.claude/tasks/0003-view-skeleton.md index f2c8a10..3883114 100644 --- a/.claude/tasks/0003-view-skeleton.md +++ b/.claude/tasks/0003-view-skeleton.md @@ -68,4 +68,12 @@ They assert real observable behaviour against independent literals rather than r ### Review follow-up applied The `runCli` and `stripAnsi` test helpers were extracted into `packages/bin/src/test-support.ts` to remove duplication the review flagged across the bin test files. -The scaffold's remaining `test.todo` placeholders (future block/inline types, annotations, the smoke test) are left intact for their owning tasks. +The scaffold's remaining `test.todo` placeholders (future block/inline types, annotations) are left intact for their owning tasks. + +### End-to-end coverage pulled forward + +A reduced end-to-end smoke was pulled forward so the vertical slice is validated the way a user runs it. +`fixtures/prose.md` is a committed recipe using only the constructs this slice models — frontmatter, headings at levels 1–3, and plain-text paragraphs — so it renders losslessly today. +`integration_test.ts` runs `kitchen view fixtures/prose.md` as a subprocess and asserts the ANSI-stripped output: exit 0, frontmatter YAML before the body, the separator, every heading and paragraph, and flat document order. +`smoke_test.ts` covers `kitchen --help` exiting 0 with the `view` command listed. +This is a subset of task 0007's smoke, which still owns the full `fixtures/basic.md` end-to-end once 0004's richer nodes make that fixture render losslessly. diff --git a/fixtures/prose.md b/fixtures/prose.md new file mode 100644 index 0000000..671f1b6 --- /dev/null +++ b/fixtures/prose.md @@ -0,0 +1,22 @@ +--- +title: Buttered Toast +servings: 2 +tags: [breakfast, simple] +--- + +# Buttered Toast + +The simplest breakfast, and a good way to smoke-test the renderer. +Everything here is plain prose — no lists, code, or annotations yet. + +## Method + +Toast the bread until golden on both sides. + +### Timing + +Spread the butter while the toast is still warm so it soaks in. + +## Serving + +Cut into triangles and serve at once. diff --git a/packages/bin/src/integration_test.ts b/packages/bin/src/integration_test.ts index 770565d..164c824 100644 --- a/packages/bin/src/integration_test.ts +++ b/packages/bin/src/integration_test.ts @@ -1,33 +1,43 @@ import { describe, expect, test } from "bun:test"; -import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; -import { tmpdir } from "node:os"; 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("invokes core parser and produces output for a real fixture file", async () => { - const dir = mkdtempSync(join(tmpdir(), "kitchen-md-")); - const file = join(dir, "recipe.md"); - writeFileSync( - file, - "---\ntitle: Test Recipe\nservings: 2\n---\n\n# Heading One\n\nA plain paragraph of prose.\n", - ); + 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)); - try { - const { exitCode, stdout } = await runCli(["view", file], CLI); - const output = stripAnsi(stdout); + expect(exitCode).toBe(0); - expect(exitCode).toBe(0); - expect(output).toContain("title: Test Recipe"); - expect(output).toContain("servings: 2"); - expect(output).toMatch(/─+/); - expect(output).toContain("Heading One"); - expect(output).toContain("A plain paragraph of prose."); - } finally { - rmSync(dir, { recursive: true, force: true }); - } + 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.")); }); }); diff --git a/packages/bin/src/smoke_test.ts b/packages/bin/src/smoke_test.ts index 03dbde7..d8f0a94 100644 --- a/packages/bin/src/smoke_test.ts +++ b/packages/bin/src/smoke_test.ts @@ -1,6 +1,13 @@ -import { describe, test } from "bun:test"; +import { describe, expect, test } from "bun:test"; + +import { runCli } from "./test-support.ts"; describe("smoke", () => { - test.todo("kitchen --help exits with code 0"); + 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 outputs structured JSON covering all annotation types"); });