test(fixtures): add vite-kitchen fixture repo

Minimal Vite + React + TS + Tailwind app with a typed-props Button
component (the future react-docgen-typescript scan target), landed at
fixtures/ outside the pnpm workspace and turbo graph. Its dependencies
exist on paper only — the runner installs them after cloning (story 04);
no lockfile, never pnpm-installed here.

Ignore surfaces follow the docs/product/reference precedent: fallow,
root ESLint, prettier, and the coverage:diff ALLOWED_GLOBS all skip
fixtures/**.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016j8z4VHjedXDTjEDNg7qHK
This commit is contained in:
2026-07-12 21:36:21 +02:00
parent fe9b2c4151
commit 1ae4a2385c
14 changed files with 164 additions and 1 deletions

View File

@@ -10,7 +10,8 @@
"**/turbo/generators/templates/**", "**/turbo/generators/templates/**",
"**/*.generated.ts", "**/*.generated.ts",
"**/*.d.ts", "**/*.d.ts",
"docs/product/reference/**" "docs/product/reference/**",
"fixtures/**"
], ],
"dynamicallyLoaded": [ "dynamicallyLoaded": [
"packages/**/__factories__/**", "packages/**/__factories__/**",

View File

@@ -3,3 +3,7 @@ compliance/*.yml
# Design reference material (ADR-029) — committed byte-for-byte, never reformat # Design reference material (ADR-029) — committed byte-for-byte, never reformat
docs/product/reference/ docs/product/reference/
# Test fixture repos — served to tests as standalone git repos, outside the
# pnpm workspace and turbo graph; never reformat
fixtures/

View File

@@ -29,6 +29,9 @@ export default [
"playwright.config.ts", "playwright.config.ts",
// Design reference material (ADR-029) — read-only prototypes, never linted // Design reference material (ADR-029) — read-only prototypes, never linted
"docs/product/reference/**", "docs/product/reference/**",
// Test fixture repos — standalone apps outside the pnpm workspace and
// turbo graph, served to tests as git remotes; never linted
"fixtures/**",
], ],
}, },
js.configs.recommended, js.configs.recommended,

3
fixtures/vite-kitchen/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
node_modules
dist
*.local

View File

@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>vite-kitchen</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View File

@@ -0,0 +1,24 @@
{
"name": "vite-kitchen",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc --noEmit && vite build",
"preview": "vite preview"
},
"dependencies": {
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@tailwindcss/vite": "^4.1.7",
"@types/react": "^19.1.0",
"@types/react-dom": "^19.1.0",
"@vitejs/plugin-react": "^4.4.1",
"tailwindcss": "^4.1.7",
"typescript": "~5.8.3",
"vite": "^6.3.5"
}
}

View File

@@ -0,0 +1,12 @@
import { Button } from "./components/Button";
export function App() {
return (
<main className="flex min-h-screen flex-col items-center justify-center gap-4 bg-slate-50">
<h1 className="text-2xl font-semibold text-slate-900">vite-kitchen</h1>
<Button variant="primary" size="md">
Order up
</Button>
</main>
);
}

View File

@@ -0,0 +1,45 @@
import type { ReactNode } from "react";
export interface ButtonProps {
/** Visual emphasis of the button. */
variant?: "primary" | "secondary" | "ghost";
/** Control scale — padding and font size. */
size?: "sm" | "md" | "lg";
/** Disables interaction and dims the control. */
disabled?: boolean;
/** Button label content. */
children: ReactNode;
}
const variantClasses: Record<NonNullable<ButtonProps["variant"]>, string> = {
primary: "bg-blue-600 text-white hover:bg-blue-700",
secondary: "bg-slate-200 text-slate-900 hover:bg-slate-300",
ghost: "bg-transparent text-blue-600 hover:bg-blue-50",
};
const sizeClasses: Record<NonNullable<ButtonProps["size"]>, string> = {
sm: "px-2.5 py-1.5 text-sm",
md: "px-4 py-2 text-base",
lg: "px-6 py-3 text-lg",
};
/**
* The kitchen's one interactive component. Its name and typed props are the
* target of the registry scan (react-docgen-typescript) in later stories.
*/
export function Button({
variant = "primary",
size = "md",
disabled = false,
children,
}: ButtonProps) {
return (
<button
type="button"
className={`rounded-md font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50 ${variantClasses[variant]} ${sizeClasses[size]}`}
disabled={disabled}
>
{children}
</button>
);
}

View File

@@ -0,0 +1 @@
@import "tailwindcss";

View File

@@ -0,0 +1,15 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { App } from "./App";
import "./index.css";
const rootElement = document.getElementById("root");
if (!rootElement) {
throw new Error("vite-kitchen: #root element not found");
}
createRoot(rootElement).render(
<StrictMode>
<App />
</StrictMode>,
);

View File

@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"strict": true,
"noEmit": true,
"isolatedModules": true,
"skipLibCheck": true,
"noUnusedLocals": true,
"noUnusedParameters": true
},
"include": ["src", "vite.config.ts"]
}

View File

@@ -0,0 +1,8 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
// https://vite.dev/config/
export default defineConfig({
plugins: [react(), tailwindcss()],
});

View File

@@ -55,6 +55,10 @@ const ALLOWED_GLOBS = [
// Design reference material (ADR-029) — read-only prototypes committed // Design reference material (ADR-029) — read-only prototypes committed
// under docs/product/reference/; never executed, never tested. // under docs/product/reference/; never executed, never tested.
/^docs\/product\/reference\//, /^docs\/product\/reference\//,
// Test fixture repos — standalone apps outside the pnpm workspace and
// turbo graph (walking-skeleton story 01); served to tests as git remotes,
// never executed by vitest, never in any lcov.
/^fixtures\//,
// Shell scripts (not Vitest-covered) // Shell scripts (not Vitest-covered)
/\.sh$/, /\.sh$/,
/\.bash$/, /\.bash$/,

View File

@@ -314,6 +314,21 @@ describe("computeDiffCoverage", () => {
assert.equal(result.summary.filesChanged, 3); assert.equal(result.summary.filesChanged, 3);
}); });
test("skips fixtures/ files (fixture repos, walking-skeleton story 01)", () => {
const lcov = parseLcov(lcovText);
const diff = new Map([
// Standalone fixture apps served to tests as git remotes — never
// executed by vitest, never in any lcov
["fixtures/vite-kitchen/src/components/Button.tsx", new Set([1, 2, 3])],
["fixtures/vite-kitchen/src/main.tsx", new Set([1, 2])],
["fixtures/vite-kitchen/vite.config.ts", new Set([1])],
]);
const result = computeDiffCoverage(diff, lcov);
assert.equal(result.status, "pass");
assert.equal(result.summary.filesGated, 0);
assert.equal(result.summary.filesChanged, 3);
});
test("end-to-end fixture: mixed pass/fail/skip/no-data", () => { test("end-to-end fixture: mixed pass/fail/skip/no-data", () => {
const lcov = parseLcov(lcovText); const lcov = parseLcov(lcovText);
const diff = parseGitDiff(diffText); const diff = parseGitDiff(diffText);