import { expect, test } from "bun:test"; import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { format } from "prettier"; import { scaffoldApp } from "../src/create.ts"; import { currentCliVersion } from "../src/update-notifier.ts"; test("scaffoldApp creates a comprehensive .gitignore", () => { const parent = mkdtempSync(join(tmpdir(), "wrnexus-create-")); const root = join(parent, "demo-app"); try { scaffoldApp(root, "demo-app"); const file = join(root, ".gitignore"); expect(existsSync(file)).toBe(true); const contents = readFileSync(file, "utf8"); for (const entry of [ "node_modules/", "dist/", ".wrnexus/", ".env.*", "!.env.example", "*.log", "*.db", "coverage/", "mobile/android/", ".vscode/", "*.tsbuildinfo", ]) { expect(contents).toContain(entry); } } finally { rmSync(parent, { recursive: true, force: true }); } }); test("scaffoldApp includes production build and start scripts", () => { const parent = mkdtempSync(join(tmpdir(), "wrnexus-create-")); const root = join(parent, "production-app"); try { scaffoldApp(root, "production-app"); const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); expect(pkg.scripts.build).toBe("wrnexus build ."); expect(pkg.scripts.start).toBe("bun dist/server.js"); expect(pkg.scripts.production).toBe("bun run build && bun run start"); } finally { rmSync(parent, { recursive: true, force: true }); } }); test("scaffoldApp pins the current framework and exposes llms.txt publicly", () => { const parent = mkdtempSync(join(tmpdir(), "wrnexus-create-")); const root = join(parent, "current-app"); try { scaffoldApp(root, "current-app"); const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); const version = currentCliVersion(); expect(pkg.wrnexus.version).toBe(version); expect(pkg.dependencies["@wrnexus/helpers"]).toBe(version); for (const dependency of Object.values(pkg.dependencies) as string[]) { expect(dependency).toBe(version); } expect(pkg.devDependencies["@wrnexus/cli"]).toBe(version); expect(pkg.devDependencies["@iconify/tailwind4"]).toBe("^1.2.3"); expect(pkg.devDependencies["@iconify-json/lucide"]).toBe("^1.2.118"); expect(readFileSync(join(root, "app", "styles", "global.css"), "utf8")).toContain( '@plugin "@iconify/tailwind4";', ); expect(existsSync(join(root, "public", "llms.txt"))).toBe(true); expect(existsSync(join(root, "llms.txt"))).toBe(false); expect(readFileSync(join(root, ".prettierignore"), "utf8")).toContain("CLAUDE.md"); expect(readFileSync(join(root, ".vscode", "settings.json"), "utf8")).toContain( '"editor.formatOnSave": true', ); expect(readFileSync(join(root, ".vscode", "settings.json"), "utf8")).toContain( '"editor.defaultFormatter": "wrnexus.wrnexus"', ); expect(readFileSync(join(root, ".vscode", "extensions.json"), "utf8")).toContain( "wrnexus.wrnexus", ); expect(readFileSync(join(root, "app", "pages", "index.wrn"), "utf8")).toContain( 'href="/api/hello"', ); expect(existsSync(join(root, "app", "pages", "about.wrn"))).toBe(true); } finally { rmSync(parent, { recursive: true, force: true }); } }); test("scaffoldApp emits Prettier-compliant editor and framework files", async () => { const parent = mkdtempSync(join(tmpdir(), "wrnexus-create-")); const root = join(parent, "formatted-app"); try { scaffoldApp(root, "formatted-app"); for (const relative of [ "app/styles/global.css", "eslint.config.js", ".vscode/settings.json", ".vscode/extensions.json", ]) { const file = join(root, relative); const source = readFileSync(file, "utf8"); const formatted = await format(source, { filepath: file, printWidth: 100, tabWidth: 2, useTabs: false, semi: true, singleQuote: false, trailingComma: "all", endOfLine: "lf", }); expect(formatted).toBe(source); } } finally { rmSync(parent, { recursive: true, force: true }); } });