diff --git a/packages/create-cloudflare/e2e-tests/helpers.ts b/packages/create-cloudflare/e2e-tests/helpers.ts index ac4f19036cd6..932db627d403 100644 --- a/packages/create-cloudflare/e2e-tests/helpers.ts +++ b/packages/create-cloudflare/e2e-tests/helpers.ts @@ -1,5 +1,4 @@ import { spawn } from "cross-spawn"; -import { red } from "helpers/colors"; export const keys = { enter: "\x0d", @@ -18,12 +17,16 @@ export type PromptHandler = { export type RunnerConfig = { promptHandlers?: PromptHandler[]; - argv: string[]; + argv?: string[]; }; -export const runC3 = async ({ argv, promptHandlers = [] }: RunnerConfig) => { +export const runC3 = async ({ + argv = [], + promptHandlers = [], +}: RunnerConfig) => { const proc = spawn("node", ["./dist/cli.js", ...argv]); const output: string[] = []; + const stderr: string[] = []; await new Promise((resolve, rejects) => { proc.stdout.on("data", (data) => { @@ -51,7 +54,7 @@ export const runC3 = async ({ argv, promptHandlers = [] }: RunnerConfig) => { }); proc.stderr.on("data", (data) => { - console.error(red(data.toString())); + stderr.push(data); }); proc.on("close", (code) => { @@ -67,5 +70,8 @@ export const runC3 = async ({ argv, promptHandlers = [] }: RunnerConfig) => { }); }); - return { output: output.join("\n").trim() }; + return { + output: output.join("\n").trim(), + stderr: stderr.join("\n").trim(), + }; }; diff --git a/packages/create-cloudflare/e2e-tests/pages.test.ts b/packages/create-cloudflare/e2e-tests/pages.test.ts index ae5cd33e9932..27c53ca1f6d7 100644 --- a/packages/create-cloudflare/e2e-tests/pages.test.ts +++ b/packages/create-cloudflare/e2e-tests/pages.test.ts @@ -1,10 +1,11 @@ -import { existsSync, rmSync, mkdirSync } from "fs"; +import { existsSync, rmSync } from "fs"; import { tmpdir } from "os"; import { join } from "path"; import { FrameworkMap } from "frameworks/index"; import { readJSON } from "helpers/files"; import { describe, expect, test, afterEach, beforeEach } from "vitest"; -import { runC3 } from "./helpers"; +import { keys, runC3 } from "./helpers"; +import type { RunnerConfig } from "./helpers"; /* Areas for future improvement: @@ -18,7 +19,6 @@ describe("E2E", () => { beforeEach(() => { projectPath = join(tmpdir(), "c3-test-pages"); rmSync(projectPath, { recursive: true, force: true }); - mkdirSync(projectPath); }); afterEach(() => { @@ -27,8 +27,11 @@ describe("E2E", () => { } }); - const runCli = async (framework: string, args: string[] = []) => { - const argv = [ + const runCli = async ( + framework: string, + { argv = [], promptHandlers = [] }: RunnerConfig + ) => { + const args = [ projectPath, "--type", "webFramework", @@ -37,17 +40,17 @@ describe("E2E", () => { "--no-deploy", ]; - if (args.length > 0) { - argv.push(...args); + if (argv.length > 0) { + args.push(...args); } else { - argv.push("--no-git"); + args.push("--no-git"); } // For debugging purposes, uncomment the following to see the exact // command the test uses. You can then run this via the command line. // console.log("COMMAND: ", `node ${["./dist/cli.js", ...argv].join(" ")}`); - await runC3({ argv }); + await runC3({ argv: args, promptHandlers }); // Relevant project files should have been created expect(projectPath).toExist(); @@ -69,19 +72,57 @@ describe("E2E", () => { test.each(["astro", "hono", "next", "nuxt", "react", "remix", "vue"])( "%s", async (name) => { - await runCli(name); + await runCli(name, {}); } ); - test.skip.each([ - // Not possible since it requires interactive input - "solid", - "svelte", - // Not possible atm since `npx qwik add cloudflare-pages` - // requires interactive confirmation - "qwik", - ])("%s", async (name) => { - await runCli(name); + test("qwik", async () => { + await runCli("qwik", { + promptHandlers: [ + { + matcher: /Yes looks good, finish update/, + input: [keys.enter], + }, + ], + }); + }); + + test("solid", async () => { + await runCli("solid", { + promptHandlers: [ + { + matcher: /Which template do you want to use/, + input: [keys.enter], + }, + { + matcher: /Server Side Rendering/, + input: [keys.enter], + }, + { + matcher: /Use TypeScript/, + input: [keys.enter], + }, + ], + }); + }); + + test("svelte", async () => { + await runCli("svelte", { + promptHandlers: [ + { + matcher: /Which Svelte app template/, + input: [keys.enter], + }, + { + matcher: /Add type checking with TypeScript/, + input: [keys.down, keys.enter], + }, + { + matcher: /Select additional options/, + input: [keys.enter], + }, + ], + }); }); // This test blows up in CI due to Github providing an unusual git user email address. @@ -91,7 +132,7 @@ describe("E2E", () => { // internal.cloudapp.net>) not allowed // ``` test.skip("Hono (wrangler defaults)", async () => { - await runCli("hono", ["--wrangler-defaults"]); + await runCli("hono", { argv: ["--wrangler-defaults"] }); // verify that wrangler-defaults defaults to `true` for using git expect(join(projectPath, ".git")).toExist(); diff --git a/packages/create-cloudflare/src/helpers/command.ts b/packages/create-cloudflare/src/helpers/command.ts index 09a726928842..633bec8a5198 100644 --- a/packages/create-cloudflare/src/helpers/command.ts +++ b/packages/create-cloudflare/src/helpers/command.ts @@ -57,12 +57,10 @@ export const runCommand = async ( promise() { const [executable, ...args] = command; - const squelch = opts.silent || process.env.VITEST; - const cmd = spawn(executable, [...args], { // TODO: ideally inherit stderr, but npm install uses this for warnings // stdio: [ioMode, ioMode, "inherit"], - stdio: squelch ? "pipe" : "inherit", + stdio: opts.silent ? "pipe" : "inherit", env: { ...process.env, ...opts.env, @@ -72,7 +70,7 @@ export const runCommand = async ( let output = ``; - if (opts?.captureOutput ?? squelch) { + if (opts?.captureOutput ?? opts.silent) { cmd.stdout?.on("data", (data) => { output += data; });