A CLI for scaffolding ATProto web applications

tests: add some more tests

besaid.zone b38875c9 978fe71f

verified
+101 -7
+98 -6
__tests__/cli.test.ts
··· 1 1 import type { SyncOptions } from "execa"; 2 2 3 3 import { execaCommandSync } from "execa"; 4 + import { 5 + existsSync, 6 + mkdirSync, 7 + readdirSync, 8 + rmSync, 9 + writeFileSync, 10 + } from "node:fs"; 4 11 import { join } from "node:path"; 5 - import { expect, test } from "vitest"; 12 + import { afterEach, beforeAll, expect, test } from "vitest"; 6 13 7 14 const CLI_PATH = join(import.meta.dirname, ".."); 15 + const DEFAULT_APP_NAME = "my-app"; 16 + const appPath = join(import.meta.dirname, "..", DEFAULT_APP_NAME); 8 17 9 18 async function run(args: string[], options?: SyncOptions) { 10 19 return execaCommandSync(`node ${CLI_PATH} ${args.join(" ")}`, { 11 20 env: { ...process.env, _VITE_TEST_CLI: "true" }, 21 + reject: false, 12 22 ...options, 13 23 }); 14 24 } 15 25 26 + function createExistingProject() { 27 + mkdirSync(DEFAULT_APP_NAME, { recursive: true }); 28 + const pkgJson = join(DEFAULT_APP_NAME, "package.json"); 29 + writeFileSync(pkgJson, '{"name": "my-app"}'); 30 + } 31 + 32 + function cleanUpTestFolders() { 33 + if (existsSync(appPath)) { 34 + rmSync(appPath, { recursive: true, force: true }); 35 + } 36 + } 37 + 38 + beforeAll(() => cleanUpTestFolders()); 39 + afterEach(() => cleanUpTestFolders()); 40 + 16 41 test("should prompt for project name", async () => { 17 42 const { stdout } = await run(["init"]); 18 43 expect(stdout).toContain("Please provide a name for this project:"); 19 44 }); 20 45 21 46 test("should prompt framework", async () => { 22 - const { stdout } = await run(["init", "my-app"]); 47 + const { stdout } = await run(["init", DEFAULT_APP_NAME]); 23 48 expect(stdout).toContain("Select a framework:"); 24 49 }); 25 50 26 51 test("should prompt variant", async () => { 27 - const { stdout } = await run(["init", "my-app", "--framework", "react"]); 52 + const { stdout } = await run([ 53 + "init", 54 + DEFAULT_APP_NAME, 55 + "--framework", 56 + "react", 57 + ]); 28 58 expect(stdout).toContain("Select a framework variant:"); 29 59 }); 30 60 31 - test.skip("should fail if no command is specified", async () => { 32 - const { stdout } = await run([]); 33 - expect(stdout).toContain("USAGE create-atproto-app create"); 61 + test("should fail if no command is specified", async () => { 62 + const { stderr } = await run([]); 63 + expect(stderr).toContain("No command specified."); 64 + }); 65 + 66 + test("should successfully create a project", async () => { 67 + const { stdout } = await run([ 68 + "init", 69 + "--name", 70 + DEFAULT_APP_NAME, 71 + "--framework", 72 + "react", 73 + "--variant", 74 + "react-ts", 75 + ]); 76 + 77 + expect(stdout).toContain("Done!"); 78 + }); 79 + 80 + test("should warn if project name already exists", async () => { 81 + createExistingProject(); 82 + const { stdout } = await run([ 83 + "init", 84 + "--name", 85 + DEFAULT_APP_NAME, 86 + "--framework", 87 + "react", 88 + "--variant", 89 + "react-ts", 90 + ]); 91 + expect(stdout).toContain("A project with the name of"); 92 + }); 93 + 94 + test("should successfully scaffold a react project", async () => { 95 + const { stdout } = await run([ 96 + "init", 97 + "--name", 98 + DEFAULT_APP_NAME, 99 + "--framework", 100 + "react", 101 + "--variant", 102 + "react-ts", 103 + ]); 104 + expect(stdout).toContain("Project created!"); 105 + expect( 106 + readdirSync(join(appPath, "src")).some((files) => files.endsWith(".tsx")), 107 + ); 108 + }); 109 + 110 + test("should successfully scaffold a svelte project", async () => { 111 + const { stdout } = await run([ 112 + "init", 113 + "--name", 114 + DEFAULT_APP_NAME, 115 + "--framework", 116 + "svelte", 117 + "--variant", 118 + "svelte-ts", 119 + ]); 120 + expect(stdout).toContain("Project created!"); 121 + expect( 122 + readdirSync(join(appPath, "src")).some((files) => 123 + files.endsWith(".svelte"), 124 + ), 125 + ); 34 126 });
+3 -1
src/commands/init.ts
··· 168 168 169 169 execSync(templateCommand); 170 170 171 - removeViteTemplateFiles(root, removableTemplateFiles(variant)); 171 + const files = removableTemplateFiles(variant); 172 + 173 + removeViteTemplateFiles(root, files); 172 174 173 175 for (const file of readdirSync(templateDir)) { 174 176 const sourceTemplateFiles = resolve(templateDir, file);