diff --git a/test/integration/nuxt/hackernews/LICENSE b/test/integration/nuxt/hackernews/LICENSE deleted file mode 100644 index b65dd9e62e2164..00000000000000 --- a/test/integration/nuxt/hackernews/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013-present, Yuxi (Evan) You - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/test/integration/nuxt/hackernews/test/dev-server-puppeteer.ts b/test/integration/nuxt/hackernews/test/dev-server-puppeteer.ts deleted file mode 100644 index fab5472778aa5c..00000000000000 --- a/test/integration/nuxt/hackernews/test/dev-server-puppeteer.ts +++ /dev/null @@ -1,107 +0,0 @@ -import assert from "assert"; -import { copyFileSync } from "fs"; -import { join } from "path"; -import { ConsoleMessage, Page, launch } from "puppeteer"; - -process.on("SIGINT", () => { - console.log("Caught interrupt signal"); - // Perform cleanup - process.exit(); -}); - -const root = join(import.meta.dir, "../"); - -copyFileSync(join(root, "components/Counter1.txt"), join(root, "components/CounterComponent.vue")); - -let url = "http://localhost:3000"; -if (process.argv.length > 2) { - url = process.argv[2]; -} - -const b = await launch({ - headless: "new", -}); - -const p = await b.newPage(); -// p.on("console", msg => console.log("[browser]", msg.text())); - -function waitForConsoleMessage(page: Page, regex: RegExp) { - const { resolve, promise } = Promise.withResolvers(); - function onMessage(msg: ConsoleMessage) { - const text = msg.text(); - if (regex.test(text)) { - page.off("console", onMessage); - resolve(); - } - } - p.on("console", onMessage); - return promise; -} - -await p.goto(url); -await waitForConsoleMessage(p, /counter a/); - -assert.strictEqual(await p.$eval("code.font-bold", x => x.innerText), Bun.version); - -let counter_root = (await p.$("#counter-fixture"))!; - -{ - const [has_class, style_json_string] = await counter_root.evaluate( - x => [(x as HTMLElement).classList.contains("rounded-bl-full"), JSON.stringify(getComputedStyle(x))] as const, - ); - assert.strictEqual(has_class, true); - const decoded_style = JSON.parse(style_json_string); - assert.strictEqual(decoded_style.borderTopLeftRadius, "0px"); - assert.strictEqual(decoded_style.borderTopRightRadius, "0px"); - assert.strictEqual(decoded_style.borderBottomRightRadius, "0px"); - assert.strictEqual(decoded_style.borderBottomLeftRadius, "9999px"); -} - -const getCount = () => counter_root.$eval("p", x => x.innerText); - -assert.strictEqual(await getCount(), "Count A: 0"); -await counter_root.$eval(".inc", x => (x as HTMLElement).click()); -assert.strictEqual(await getCount(), "Count A: 1"); -await counter_root.$eval(".inc", x => (x as HTMLElement).click()); -assert.strictEqual(await getCount(), "Count A: 2"); -await counter_root.$eval(".dec", x => (x as HTMLElement).click()); -assert.strictEqual(await getCount(), "Count A: 1"); - -p.reload({}); -await waitForConsoleMessage(p, /counter a/); - -assert.strictEqual(await p.$eval("code.font-bold", x => x.innerText), Bun.version); - -counter_root = (await p.$("#counter-fixture"))!; - -assert.strictEqual(await getCount(), "Count A: 0"); -await counter_root.$eval(".inc", x => (x as HTMLElement).click()); -assert.strictEqual(await getCount(), "Count A: 1"); -await counter_root.$eval(".inc", x => (x as HTMLElement).click()); -assert.strictEqual(await getCount(), "Count A: 2"); -await counter_root.$eval(".dec", x => (x as HTMLElement).click()); -assert.strictEqual(await getCount(), "Count A: 1"); - -copyFileSync(join(root, "components/Counter2.txt"), join(root, "components/CounterComponent.vue")); -await waitForConsoleMessage(p, /counter b loaded/); -assert.strictEqual(await getCount(), "Count B: 1"); -await counter_root.$eval(".inc", x => (x as HTMLElement).click()); -assert.strictEqual(await getCount(), "Count B: 3"); -await counter_root.$eval(".inc", x => (x as HTMLElement).click()); -assert.strictEqual(await getCount(), "Count B: 5"); -await counter_root.$eval(".dec", x => (x as HTMLElement).click()); -assert.strictEqual(await getCount(), "Count B: 3"); - -{ - const [has_class, style_json_string] = await counter_root.evaluate( - x => [(x as HTMLElement).classList.contains("rounded-br-full"), JSON.stringify(getComputedStyle(x))] as const, - ); - assert.strictEqual(has_class, true); - const decoded_style = JSON.parse(style_json_string); - assert.strictEqual(decoded_style.borderTopLeftRadius, "0px"); - assert.strictEqual(decoded_style.borderTopRightRadius, "0px"); - assert.strictEqual(decoded_style.borderBottomRightRadius, "9999px"); - assert.strictEqual(decoded_style.borderBottomLeftRadius, "0px"); -} - -await b.close(); diff --git a/test/integration/nuxt/hackernews/test/dev-server.test.ts b/test/integration/nuxt/hackernews/test/dev-server.test.ts deleted file mode 100644 index 96ab4469cefb6c..00000000000000 --- a/test/integration/nuxt/hackernews/test/dev-server.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { Subprocess } from "bun"; -import { afterAll, expect, test } from "bun:test"; -import { copyFileSync, rmSync } from "fs"; -import { join } from "path"; -import { bunEnv, bunExe } from "../../../../harness"; - -const root = join(import.meta.dir, "../"); -let dev_server: undefined | Subprocess<"ignore", "pipe", "inherit">; -let baseUrl: string; - -test("the dev server can start", async () => { - rmSync(join(root, ".nuxt"), { recursive: true, force: true }); - copyFileSync(join(root, "components/Counter1.txt"), join(root, "components/CounterComponent.vue")); - - const install = Bun.spawnSync([bunExe(), "i"], { cwd: root, env: bunEnv }); - if (install.exitCode !== 0) { - throw new Error("Failed to install dependencies"); - } - dev_server = Bun.spawn([bunExe(), "--bun", "node_modules/.bin/nuxi", "dev"], { - cwd: root, - env: bunEnv, - stdio: ["ignore", "pipe", "inherit"], - }); - dev_server.exited.then(() => { - dev_server = undefined; - }); - for await (const chunk of dev_server.stdout) { - console.error({ chunk }); - const str = new TextDecoder().decode(chunk); - const match = str.match(/http:\/\/localhost:\d+/); - if (match) { - baseUrl = match[0]; - } - if (str.toLowerCase().includes("built")) { - return; - } - } - console.error("Failed to start dev server :/"); - dev_server.kill(); - dev_server = undefined; -}, 30_000); - -test("ssr works for 100 requests", async () => { - expect(dev_server).not.toBeUndefined(); - expect(baseUrl).not.toBeUndefined(); - - const promises: Promise[] = []; - for (let i = 0; i < 100; i++) { - promises.push( - (async () => { - const x = await fetch(`${baseUrl}/news/1?i=${i}`, { - headers: { - "Cache-Control": "private, no-cache, no-store, must-revalidate", - }, - }); - expect(x.status).toBe(200); - const text = await x.text(); - console.count("Completed request"); - expect(text).toContain(`>${Bun.version}`); - })(), - ); - } - - const x = await Promise.allSettled(promises); - for (const y of x) { - expect(y.status).toBe("fulfilled"); - } -}, 10_000); - -test("hot reloading works on the client", async () => { - expect(dev_server).not.toBeUndefined(); - expect(baseUrl).not.toBeUndefined(); - - const result = Bun.spawnSync([bunExe(), "test/dev-server-puppeteer.ts", baseUrl], { - cwd: root, - env: bunEnv, - stdio: ["ignore", "inherit", "inherit"], - }); - expect(result.exitCode).toBe(0); -}, 30_000); - -afterAll(() => { - Bun.spawnSync(["pkill", "-P", dev_server!.pid.toString()]); -}); diff --git a/test/integration/nuxt/hackernews/test/nuxt-build.test.ts b/test/integration/nuxt/hackernews/test/nuxt-build.test.ts deleted file mode 100644 index 2d189b0c850013..00000000000000 --- a/test/integration/nuxt/hackernews/test/nuxt-build.test.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { expect, test } from "bun:test"; -import { copyFileSync, cpSync, mkdtempSync, readFileSync, readdirSync, rmSync, symlinkSync } from "fs"; -import { cp } from "fs/promises"; -import { tmpdir } from "os"; -import { join } from "path"; -import { bunEnv, bunExe } from "../../../../harness"; - -const root = join(import.meta.dir, "../"); - -let build_passed = false; - -async function tempDirToBuildIn() { - const dir = mkdtempSync(join(tmpdir(), "bun-nuxt-build-")); - const copy = [ - ".eslintrc", - "app.vue", - "bun.lockb", - "nuxt.config.ts", - "package.json", - "types.ts", - "components", - "composables", - "layouts", - "middleware", - "pages", - "public", - "server", - ]; - await Promise.all(copy.map(x => cp(join(root, x), join(dir, x), { recursive: true }))); - cpSync(join(root, "components/Counter1.txt"), join(dir, "components/CounterComponent.vue")); - cpSync(join(root, "tsconfig_for_build.json"), join(dir, "tsconfig.json")); - symlinkSync(join(root, "node_modules"), join(dir, "node_modules")); - return dir; -} - -function readdirRecursive(dir: string) { - let results: string[] = []; - - readdirSync(dir, { withFileTypes: true }).forEach(file => { - if (file.isDirectory()) { - results = results.concat(readdirRecursive(join(dir, file.name)).map(x => join(file.name, x))); - } else { - results.push(file.name); - } - }); - - return results; -} - -function hashAllFiles(dir: string) { - const files = readdirRecursive(dir).sort(); - const hashes: Record = {}; - for (const file of files) { - const hash = new Bun.CryptoHasher("sha256"); - hash.update(readFileSync(join(dir, file))); - hashes[file] = hash.digest("hex"); - } - return hashes; -} - -test("nuxt build works", async () => { - copyFileSync(join(root, "components/Counter1.txt"), join(root, "components/CounterComponent.vue")); - - const install = Bun.spawnSync([bunExe(), "i"], { cwd: root, env: bunEnv }); - if (install.exitCode !== 0) { - throw new Error("Failed to install dependencies"); - } - - const bunDir = await tempDirToBuildIn(); - const nodeDir = await tempDirToBuildIn(); - - const bunBuild = await Bun.spawn([bunExe(), "--bun", "node_modules/.bin/nuxi", "build"], { - cwd: bunDir, - // env: bunEnv, - stdio: ["ignore", "pipe", "inherit"], - env: { - ...bunEnv, - NODE_ENV: "production", - }, - }); - const nodeBuild = await Bun.spawn(["node", "node_modules/.bin/nuxi", "build"], { - cwd: nodeDir, - env: bunEnv, - stdio: ["ignore", "pipe", "inherit"], - }); - await Promise.all([bunBuild.exited, nodeBuild.exited]); - expect(nodeBuild.exitCode).toBe(0); - expect(bunBuild.exitCode).toBe(0); - - const bunCliOutputRaw = await Bun.readableStreamToText(bunBuild.stdout); - const nodeCliOutputRaw = await Bun.readableStreamToText(nodeBuild.stdout); - - /** - * Normalizes various outputs in build logs. - * This function applies a series of regular expressions to a given string - * to normalize file hashes, sizes, durations, and other build-related outputs. - * - * @param text - The input string containing build log output. - * @returns A string with normalized outputs. - */ - const normalizeOutput = (text: string): string => { - const regexPatterns: Array<[RegExp, string]> = [ - [/_([a-z0-9]+)\.(mjs|js)/g, "_.${2}"], // Normalize MJS/JS file hashes - [/\d+\.\d+ (kB|MB)/g, "X.XX $1"], // Normalize size discrepancies - [/\d+\.\d+s/g, "X.XXs"], // Normalize build duration - [/\d+ B (gzip)?/g, "XXX B $1"], // Normalize byte sizes, including gzip - [/(\.output\/server\/chunks\/app\/_nuxt\/[a-z0-9_-]+)\.[a-z0-9]+(\.mjs(\.map)?)/g, "$1.HASH$2"], // Normalize hashes in .output/server - [/_nuxt\/[a-z0-9_-]+-[a-z0-9]+(\.mjs|\.js|\.css)/g, "_nuxt/${1}.HASH${2}"], // Normalize hashes in _nuxt - [/\d+(\.\d+)?(s|ms|kB|MB)/g, "X.XX$2"], // Normalize time & size measurements - [/\/bun-nuxt-build-[a-zA-Z0-9]+\//g, "/bun-nuxt-build-XXXXXX/"], // Normalize dynamic paths in build output - [/\d+ kB/g, "XXX kB"], // Normalize kB sizes - [/_nuxt\/[a-z0-9_.-]+\.js/g, "_nuxt/filename.HASH.js"], // Normalize hashes in filenames - [/_nuxt\/error-(404|500)-styles\.[a-f0-9]+\.mjs/g, "_nuxt/error-HTTP_CODE-styles.HASH.mjs"], // Normalize error styles with HTTP codes - [/_nuxt\/[a-z0-9_-]+\.([a-f0-9]+)\.(js|mjs)/g, "_nuxt/${1}.HASH.${2}"], // Normalize hashes in filenames for .js and .mjs files - ]; - - return regexPatterns.reduce((acc, [pattern, replacement]) => acc.replace(pattern, replacement), text); - }; - - const bunCliOutput = normalizeOutput(bunCliOutputRaw); - const nodeCliOutput = normalizeOutput(nodeCliOutputRaw); - - expect(bunCliOutput).toBe(nodeCliOutput); - - const bunBuildDir = join(bunDir, ".nuxt"); - const nodeBuildDir = join(nodeDir, ".nuxt"); - - const toRemove = ["dist/client/_nuxt", "dist/server/_nuxt"]; - for (const key of toRemove) { - rmSync(join(bunBuildDir, key), { recursive: true }); - rmSync(join(nodeBuildDir, key), { recursive: true }); - } - - const bunBuildHash = hashAllFiles(bunBuildDir); - const nodeBuildHash = hashAllFiles(nodeBuildDir); - - try { - expect(bunBuildHash).toEqual(nodeBuildHash); - } catch (error) { - console.log("bunBuildDir", bunBuildDir); - console.log("nodeBuildDir", nodeBuildDir); - - // print diffs for every file if not the same - for (const key in bunBuildHash) { - if (bunBuildHash[key] !== nodeBuildHash[key]) { - console.log(key + ":"); - try { - expect(readFileSync(join(bunBuildDir, key)).toString()).toBe( - readFileSync(join(nodeBuildDir, key)).toString(), - ); - } catch (error) { - console.error(error); - } - } - } - throw error; - } - - build_passed = true; -}, 300_000); - -const version_string = "[production needs a constant string]";