diff options
author | 2023-04-24 17:12:21 -0400 | |
---|---|---|
committer | 2023-04-24 14:12:21 -0700 | |
commit | f2112fc0de3fd2d8cea674990be6f5ff2bd11061 (patch) | |
tree | 81bb4853c41e30a23792647aab58819436406dbb | |
parent | 923ac39c0b718ac5d488f65232f0dcd7161423d4 (diff) | |
download | bun-f2112fc0de3fd2d8cea674990be6f5ff2bd11061.tar.gz bun-f2112fc0de3fd2d8cea674990be6f5ff2bd11061.tar.zst bun-f2112fc0de3fd2d8cea674990be6f5ff2bd11061.zip |
Continue bundler tests (#2691)
* start refine + skipping some packagejson tests
* some more tests
* stuff
* tests for minify branch
* pkgjson
* add minify/MergeAdjacentVars
* add test for #2699
* more tests!
* more tests
* finish splitting tests
* all but 2 import star tests are good
* test
Diffstat (limited to '')
-rw-r--r-- | test/bundler/bundler_browser.test.ts | 284 | ||||
-rw-r--r-- | test/bundler/bundler_cjs2esm.test.ts | 151 | ||||
-rw-r--r-- | test/bundler/bundler_edgecase.test.ts | 85 | ||||
-rw-r--r-- | test/bundler/bundler_minify.test.ts | 76 | ||||
-rw-r--r-- | test/bundler/esbuild/default.test.ts | 132 | ||||
-rw-r--r-- | test/bundler/esbuild/importstar.test.ts | 81 | ||||
-rw-r--r-- | test/bundler/esbuild/loader.test.ts | 12 | ||||
-rw-r--r-- | test/bundler/esbuild/packagejson.test.ts | 885 | ||||
-rw-r--r-- | test/bundler/esbuild/splitting.test.ts | 394 | ||||
-rw-r--r-- | test/bundler/esbuild/ts.test.ts | 206 | ||||
-rw-r--r-- | test/bundler/expectBundled.ts | 70 |
11 files changed, 1717 insertions, 659 deletions
diff --git a/test/bundler/bundler_browser.test.ts b/test/bundler/bundler_browser.test.ts new file mode 100644 index 000000000..89570a445 --- /dev/null +++ b/test/bundler/bundler_browser.test.ts @@ -0,0 +1,284 @@ +import assert from "assert"; +import dedent from "dedent"; +import { bundlerTest, expectBundled, itBundled, testForFile } from "./expectBundled"; +var { describe, test, expect } = testForFile(import.meta.path); + +describe("bundler", () => { + const nodePolyfillList = { + "assert": "polyfill", + "buffer": "polyfill", + "child_process": "no-op", + "cluster": "no-op", + "console": "polyfill", + "constants": "polyfill", + "crypto": "polyfill", + "dgram": "no-op", + "dns": "no-op", + "domain": "polyfill", + "events": "polyfill", + "fs": "no-op", + "http": "polyfill", + "https": "polyfill", + "module": "no-op", + "net": "polyfill", + "os": "polyfill", + "path": "polyfill", + "perf_hooks": "no-op", + "process": "polyfill", + "punycode": "polyfill", + "querystring": "polyfill", + "readline": "no-op", + "repl": "no-op", + "stream": "polyfill", + "string_decoder": "polyfill", + "sys": "polyfill", + "timers": "polyfill", + "tls": "no-op", + "tty": "polyfill", + "url": "polyfill", + "util": "polyfill", + "v8": "no-op", + "vm": "no-op", + "zlib": "polyfill", + }; + itBundled("browser/NodeFS", { + files: { + "/entry.js": /* js */ ` + import * as fs from "node:fs"; + import * as fs2 from "fs"; + import { readFileSync } from "fs"; + console.log(typeof fs); + console.log(typeof fs2); + console.log(typeof readFileSync); + `, + }, + platform: "browser", + run: { + stdout: "function\nfunction\nundefined", + }, + }); + // TODO: use nodePolyfillList to generate the code in here. + const NodePolyfills = itBundled("browser/NodePolyfills", { + files: { + "/entry.js": /* js */ ` + import * as assert from "node:assert"; + import * as buffer from "node:buffer"; + import * as child_process from "node:child_process"; + import * as cluster from "node:cluster"; + import * as console2 from "node:console"; + import * as constants from "node:constants"; + import * as crypto from "node:crypto"; + import * as dgram from "node:dgram"; + import * as dns from "node:dns"; + import * as domain from "node:domain"; + import * as events from "node:events"; + import * as fs from "node:fs"; + import * as http from "node:http"; + import * as https from "node:https"; + import * as module2 from "node:module"; + import * as net from "node:net"; + import * as os from "node:os"; + import * as path from "node:path"; + import * as perf_hooks from "node:perf_hooks"; + import * as process from "node:process"; + import * as punycode from "node:punycode"; + import * as querystring from "node:querystring"; + import * as readline from "node:readline"; + import * as repl from "node:repl"; + import * as stream from "node:stream"; + import * as string_decoder from "node:string_decoder"; + import * as sys from "node:sys"; + import * as timers from "node:timers"; + import * as tls from "node:tls"; + import * as tty from "node:tty"; + import * as url from "node:url"; + import * as util from "node:util"; + import * as v8 from "node:v8"; + import * as vm from "node:vm"; + import * as zlib from "node:zlib"; + function scan(obj) { + if (typeof obj === 'function') obj = obj() + return Object.keys(obj).length === 0 ? 'no-op' : 'polyfill' + } + console.log('assert :', scan(assert)) + console.log('buffer :', scan(buffer)) + console.log('child_process :', scan(child_process)) + console.log('cluster :', scan(cluster)) + console.log('console :', console2 === console ? 'equal' : 'polyfill') + console.log('constants :', scan(constants)) + console.log('crypto :', scan(crypto)) + console.log('dgram :', scan(dgram)) + console.log('dns :', scan(dns)) + console.log('domain :', scan(domain)) + console.log('events :', scan(events)) + console.log('fs :', scan(fs)) + console.log('http :', scan(http)) + console.log('https :', scan(https)) + console.log('module :', scan(module2)) + console.log('net :', scan(net)) + console.log('os :', scan(os)) + console.log('path :', scan(path)) + console.log('perf_hooks :', scan(perf_hooks)) + console.log('process :', scan(process)) + console.log('punycode :', scan(punycode)) + console.log('querystring :', scan(querystring)) + console.log('readline :', scan(readline)) + console.log('repl :', scan(repl)) + console.log('stream :', scan(stream)) + console.log('string_decoder :', scan(string_decoder)) + console.log('sys :', scan(sys)) + console.log('timers :', scan(timers)) + console.log('tls :', scan(tls)) + console.log('tty :', scan(tty)) + console.log('url :', scan(url)) + console.log('util :', scan(util)) + console.log('v8 :', scan(v8)) + console.log('vm :', scan(vm)) + console.log('zlib :', scan(zlib)) + `, + }, + platform: "browser", + onAfterBundle(api) { + assert(!api.readFile("/out.js").includes("\0"), "bundle should not contain null bytes"); + const file = api.readFile("/out.js"); + const imports = new Bun.Transpiler().scanImports(file); + expect(imports).toStrictEqual([]); + }, + run: { + stdout: ` + assert : polyfill + buffer : polyfill + child_process : no-op + cluster : no-op + console : polyfill + constants : polyfill + crypto : polyfill + dgram : no-op + dns : no-op + domain : polyfill + events : polyfill + fs : no-op + http : polyfill + https : polyfill + module : no-op + net : polyfill + os : polyfill + path : polyfill + perf_hooks : no-op + process : polyfill + punycode : polyfill + querystring : polyfill + readline : no-op + repl : no-op + stream : polyfill + string_decoder : polyfill + sys : polyfill + timers : polyfill + tls : no-op + tty : polyfill + url : polyfill + util : polyfill + v8 : no-op + vm : no-op + zlib : polyfill + `, + }, + }); + itBundled("browser/NodePolyfillExternal", { + skipOnEsbuild: true, + files: { + "/entry.js": NodePolyfills.options.files["/entry.js"], + }, + platform: "browser", + external: Object.keys(nodePolyfillList), + onAfterBundle(api) { + const file = api.readFile("/out.js"); + const imports = new Bun.Transpiler().scanImports(file); + expect(imports).toStrictEqual( + Object.keys(nodePolyfillList).map(x => ({ + kind: "import-statement", + path: "node:" + x, + })), + ); + }, + }); + + // unsure: do we want polyfills or no-op stuff like node:* has + // right now all error except bun:wrap which errors at resolve time, but is included if external + const bunModules: Record<string, "no-op" | "polyfill" | "error"> = { + "bun": "error", + "bun:ffi": "error", + "bun:dns": "error", + "bun:test": "error", + "bun:sqlite": "error", + "bun:wrap": "error", + "bun:internal": "error", + "bun:jsc": "error", + }; + + const nonErroringBunModules = Object.entries(bunModules) + .filter(x => x[1] !== "error") + .map(x => x[0]); + + // segfaults the test runner + itBundled.skip("browser/BunPolyfill", { + skipOnEsbuild: true, + files: { + "/entry.js": ` + ${nonErroringBunModules.map((x, i) => `import * as bun_${i} from "${x}";`).join("\n")} + function scan(obj) { + if (typeof obj === 'function') obj = obj() + return Object.keys(obj).length === 0 ? 'no-op' : 'polyfill' + } + ${nonErroringBunModules.map((x, i) => `console.log("${x.padEnd(12, " ")}:", scan(bun_${i}));`).join("\n")} + `, + }, + platform: "browser", + onAfterBundle(api) { + assert(!api.readFile("/out.js").includes("\0"), "bundle should not contain null bytes"); + const file = api.readFile("/out.js"); + const imports = new Bun.Transpiler().scanImports(file); + expect(imports).toStrictEqual([]); + }, + run: { + stdout: nonErroringBunModules.map(x => `${x.padEnd(12, " ")}: ${bunModules[x]}`).join("\n"), + }, + }); + + const ImportBunError = itBundled("browser/ImportBunError", { + skipOnEsbuild: true, + files: { + "/entry.js": ` + ${Object.keys(bunModules) + .map((x, i) => `import * as bun_${i} from "${x}";`) + .join("\n")} + ${Object.keys(bunModules) + .map((x, i) => `console.log("${x.padEnd(12, " ")}:", !!bun_${i});`) + .join("\n")} + `, + }, + platform: "browser", + bundleErrors: { + "/entry.js": Object.keys(bunModules) + .filter(x => bunModules[x] === "error") + .map(x => `Could not resolve: "${x}". Maybe you need to "bun install"?`), + }, + }); + + itBundled("browser/BunPolyfillExternal", { + skipOnEsbuild: true, + files: ImportBunError.options.files, + platform: "browser", + external: Object.keys(bunModules), + onAfterBundle(api) { + const file = api.readFile("/out.js"); + const imports = new Bun.Transpiler().scanImports(file); + expect(imports).toStrictEqual( + Object.keys(bunModules).map(x => ({ + kind: "import-statement", + path: x, + })), + ); + }, + }); +}); diff --git a/test/bundler/bundler_cjs2esm.test.ts b/test/bundler/bundler_cjs2esm.test.ts index a665449ae..3b3e01802 100644 --- a/test/bundler/bundler_cjs2esm.test.ts +++ b/test/bundler/bundler_cjs2esm.test.ts @@ -16,14 +16,155 @@ describe("bundler", () => { } `, }, - minifySyntax: true, - platform: "bun", - // TODO: better assertion - onAfterBundle(api) { - assert(!api.readFile("/out.js").includes("__commonJS"), "should not include the commonJS helper"); + cjs2esm: true, + run: { + stdout: "foo", }, + }); + itBundled("cjs2esm/ExportsFunction", { + files: { + "/entry.js": /* js */ ` + import { foo } from 'lib'; + console.log(foo()); + `, + "/node_modules/lib/index.js": /* js */ ` + exports.foo = function() { + return 'foo'; + } + `, + }, + cjs2esm: true, run: { stdout: "foo", }, }); + itBundled("cjs2esm/ModuleExportsFunctionTreeShaking", { + files: { + "/entry.js": /* js */ ` + import { foo } from 'lib'; + console.log(foo()); + `, + "/node_modules/lib/index.js": /* js */ ` + module.exports.foo = function() { + return 'foo'; + } + module.exports.bar = function() { + return 'remove_me'; + } + `, + }, + cjs2esm: true, + dce: true, + treeShaking: true, + run: { + stdout: "foo", + }, + }); + itBundled("cjs2esm/ModuleExportsEqualsRequire", { + files: { + "/entry.js": /* js */ ` + import { foo } from 'lib'; + console.log(foo); + `, + "/node_modules/lib/index.js": /* js */ ` + // bundler should see through this + module.exports = require('./library.js') + `, + "/node_modules/lib/library.js": /* js */ ` + module.exports.foo = 'bar'; + `, + }, + cjs2esm: true, + run: { + stdout: "bar", + }, + }); + itBundled("cjs2esm/ModuleExportsBasedOnNodeEnvProduction", { + files: { + "/entry.js": /* js */ ` + import { foo } from 'lib'; + console.log(foo); + `, + "/node_modules/lib/index.js": /* js */ ` + // bundler should see through this + if (process.env.NODE_ENV === 'production') { + module.exports = require('./library.prod.js') + } else { + module.exports = require('./library.dev.js') + } + `, + "/node_modules/lib/library.prod.js": /* js */ ` + module.exports.foo = 'production'; + `, + "/node_modules/lib/library.dev.js": /* js */ ` + module.exports.foo = 'FAILED'; + `, + }, + cjs2esm: true, + dce: true, + env: { + NODE_ENV: "production", + }, + run: { + stdout: "production", + }, + }); + itBundled("cjs2esm/ModuleExportsBasedOnNodeEnvDevelopment", { + files: { + "/entry.js": /* js */ ` + import { foo } from 'lib'; + console.log(foo); + `, + "/node_modules/lib/index.js": /* js */ ` + if (process.env.NODE_ENV === 'production') { + module.exports = require('./library.prod.js') + } else { + module.exports = require('./library.dev.js') + } + `, + "/node_modules/lib/library.prod.js": /* js */ ` + module.exports.foo = 'FAILED'; + `, + "/node_modules/lib/library.dev.js": /* js */ ` + module.exports.foo = 'development'; + `, + }, + cjs2esm: true, + dce: true, + env: { + NODE_ENV: "development", + }, + run: { + stdout: "development", + }, + }); + itBundled("cjs2esm/ModuleExportsEqualsRuntimeCondition", { + notImplemented: true, + files: { + "/entry.js": /* js */ ` + import { foo } from 'lib'; + console.log(foo); + `, + "/node_modules/lib/index.js": /* js */ ` + if (globalThis.USE_PROD) { + module.exports = require('./library.prod.js') + } else { + module.exports = require('./library.dev.js') + } + `, + // these should have the cjs transform + "/node_modules/lib/library.prod.js": /* js */ ` + module.exports.foo = 'production'; + `, + "/node_modules/lib/library.dev.js": /* js */ ` + module.exports.foo = 'development'; + `, + }, + cjs2esm: { + exclude: ["/node_modules/lib/index.js"], + }, + run: { + stdout: "development", + }, + }); }); diff --git a/test/bundler/bundler_edgecase.test.ts b/test/bundler/bundler_edgecase.test.ts index 98c8c0a8e..66c7f1b1d 100644 --- a/test/bundler/bundler_edgecase.test.ts +++ b/test/bundler/bundler_edgecase.test.ts @@ -9,6 +9,18 @@ describe("bundler", () => { "/entry.js": "", }, }); + itBundled("edgecase/EmptyCommonJSModule", { + files: { + "/entry.js": /* js */ ` + import * as module from './module.cjs'; + console.log(typeof module) + `, + "/module.cjs": /* js */ ``, + }, + run: { + stdout: "object", + }, + }); itBundled("edgecase/ImportStarFunction", { files: { "/entry.js": /* js */ ` @@ -83,4 +95,77 @@ describe("bundler", () => { }, capture: ['"Hello\0"'], }); + // https://github.com/oven-sh/bun/issues/2699 + itBundled("edgecase/ImportNamedFromExportStarCJS", { + files: { + "/entry.js": /* js */ ` + import { foo } from './foo'; + console.log(foo); + `, + "/foo.js": /* js */ ` + export * from './bar.cjs'; + `, + "/bar.cjs": /* js */ ` + module.exports = { foo: 'bar' }; + `, + }, + run: { + stdout: "bar", + }, + }); + itBundled("edgecase/NodeEnvDefaultUnset", { + files: { + "/entry.js": /* js */ ` + capture(process.env.NODE_ENV); + capture(process.env.NODE_ENV === 'production'); + capture(process.env.NODE_ENV === 'development'); + `, + }, + platform: "browser", + capture: ['"development"', "false", "true"], + env: { + // undefined will ensure this variable is not passed to the bundler + NODE_ENV: undefined, + }, + }); + itBundled("edgecase/NodeEnvDefaultDevelopment", { + files: { + "/entry.js": /* js */ ` + capture(process.env.NODE_ENV); + capture(process.env.NODE_ENV === 'production'); + capture(process.env.NODE_ENV === 'development'); + `, + }, + platform: "browser", + capture: ['"development"', "false", "true"], + env: { + NODE_ENV: "development", + }, + }); + itBundled("edgecase/NodeEnvDefaultProduction", { + files: { + "/entry.js": /* js */ ` + capture(process.env.NODE_ENV); + capture(process.env.NODE_ENV === 'production'); + capture(process.env.NODE_ENV === 'development'); + `, + }, + platform: "browser", + capture: ['"production"', "true", "false"], + env: { + NODE_ENV: "production", + }, + }); + itBundled("edgecase/ProcessEnvArbitrary", { + files: { + "/entry.js": /* js */ ` + capture(process.env.ARBITRARY); + `, + }, + platform: "browser", + capture: ["process.env.ARBITRARY"], + env: { + ARBITRARY: "secret environment stuff!", + }, + }); }); diff --git a/test/bundler/bundler_minify.test.ts b/test/bundler/bundler_minify.test.ts index 1744c60cb..d52252af0 100644 --- a/test/bundler/bundler_minify.test.ts +++ b/test/bundler/bundler_minify.test.ts @@ -1,5 +1,7 @@ -import { describe } from "bun:test"; -import { itBundled } from "./expectBundled"; +import assert from "assert"; +import dedent from "dedent"; +import { bundlerTest, expectBundled, itBundled, testForFile } from "./expectBundled"; +var { describe, test, expect } = testForFile(import.meta.path); describe("bundler", () => { itBundled("minify/TemplateStringFolding", { @@ -49,7 +51,77 @@ describe("bundler", () => { "!1", "!1", ], + minifySyntax: true, platform: "bun", minifySyntax: true, }); + itBundled("minify/FunctionExpressionRemoveName", { + notImplemented: true, + files: { + "/entry.js": /* js */ ` + capture(function remove() {}); + capture(function() {}); + capture(function rename_me() { rename_me() }); + `, + }, + // capture is pretty stupid and will stop at first ) + capture: ["function(", "function(", "function e("], + minifySyntax: true, + minifyIdentifiers: true, + platform: "bun", + }); + itBundled("minify/PrivateIdentifiersNameCollision", { + files: { + "/entry.js": /* js */ ` + class C { + ${new Array(500) + .fill(null) + .map((_, i) => `#identifier${i} = 123;`) + .join("\n")} + a = 456; + + getAllValues() { + return [ + ${new Array(500) + .fill(null) + .map((_, i) => `this.#identifier${i}`) + .join(",")} + ] + } + } + + const values = new C().getAllValues(); + for (const value of values) { + if(value !== 123) { throw new Error("Expected 123!"); } + } + + console.log("a = " + new C().a); + `, + }, + minifyIdentifiers: true, + run: { stdout: "a = 456" }, + }); + itBundled("minify/MergeAdjacentVars", { + files: { + "/entry.js": /* js */ ` + var a = 1; + var b = 2; + var c = 3; + + // some code to prevent inlining + a = 4; + console.log(a, b, c) + b = 5; + console.log(a, b, c) + c = 6; + console.log(a, b, c) + `, + }, + minifySyntax: true, + run: { stdout: "4 2 3\n4 5 3\n4 5 6" }, + onAfterBundle(api) { + const code = api.readFile("/out.js"); + assert([...code.matchAll(/var /g)].length === 1, "expected only 1 variable declaration statement"); + }, + }); }); diff --git a/test/bundler/esbuild/default.test.ts b/test/bundler/esbuild/default.test.ts index d504bd4da..421b1fd9f 100644 --- a/test/bundler/esbuild/default.test.ts +++ b/test/bundler/esbuild/default.test.ts @@ -279,7 +279,6 @@ describe("bundler", () => { function nested() { return import('./c') }, ] - import { deepEqual } from 'node:assert' deepEqual(a, 1, 'a'); deepEqual(a2, 4, 'a2'); deepEqual(c3, 2, 'c3'); @@ -305,7 +304,9 @@ describe("bundler", () => { export const a2 = 4; `, "/test.js": String.raw/* js */ ` - import './out.js'; + import { deepEqual } from 'node:assert'; + globalThis.deepEqual = deepEqual; + await import ('./out.js'); if (!globalThis.aWasImported) { throw new Error('"import \'./a\'" was tree-shaken when it should not have been.') } @@ -314,10 +315,11 @@ describe("bundler", () => { } `, }, - mode: "transform", + // mode: "transform", run: { file: "/test.js", }, + external: ["node:assert", "./a", "./b", "./c"], } as const; itBundled("default/ImportFormsWithNoBundle", { ...importFormsConfig, @@ -1859,7 +1861,7 @@ describe("bundler", () => { }); itBundled("default/ArgumentsSpecialCaseNoBundle", { files: { - "/entry.js": /* js */ ` + "/entry.cjs": /* js */ ` (async() => { var arguments = 'var'; @@ -1902,7 +1904,7 @@ describe("bundler", () => { // assertions: // we need this helper function to get "Arguments" objects, though this only applies for tests using v8 const argumentsFor = new Function('return arguments;'); - const assert = require('assert'); + const assert = (0, require)('assert'); assert.deepEqual(f1(), [argumentsFor(), argumentsFor()], 'f1()'); assert.deepEqual(f1(1), [1, argumentsFor(1)], 'f1(1)'); assert.deepEqual(f2(), [argumentsFor(), argumentsFor()], 'f2()'); @@ -1949,42 +1951,58 @@ describe("bundler", () => { assert.deepEqual(a19(1), [1, 'var'], 'a19(1)'); assert.deepEqual(await a20(), ['var', 'var'], 'a20()'); assert.deepEqual(await a20(1), [1, 'var'], 'a20(1)'); - })(); + })(1,3,5); `, }, - format: "cjs", + format: "esm", outfile: "/out.js", minifyIdentifiers: true, - mode: "transform", + // mode: "transform", }); itBundled("default/WithStatementTaintingNoBundle", { - // TODO: MANUAL CHECK: make sure the snapshot we use works. files: { "/entry.js": /* js */ ` (() => { let local = 1 let outer = 2 let outerDead = 3 - with ({}) { + console.log(local, outer, outerDead) + with ({ outer: 100, local: 150, hoisted: 200, extra: 500 }) { + console.log(outer, outerDead, hoisted, extra) var hoisted = 4 let local = 5 hoisted++ local++ + console.log(local, outer, outerDead, hoisted, extra) if (1) outer++ if (0) outerDead++ + console.log(local, outer, outerDead, hoisted, extra) } + console.log(local, outer, outerDead, hoisted) if (1) { hoisted++ local++ outer++ outerDead++ } + console.log(local, outer, outerDead, hoisted) })() `, }, format: "iife", minifyIdentifiers: true, mode: "transform", + run: { + runtime: "node", + stdout: ` + 1 2 3 + 100 3 200 500 + 6 100 3 5 500 + 6 101 3 5 500 + 1 2 3 undefined + 2 3 4 NaN + `, + }, }); itBundled("default/DirectEvalTaintingNoBundle", { files: { @@ -2279,6 +2297,7 @@ describe("bundler", () => { }, }); itBundled("default/AutoExternalNode", { + skipOnEsbuild: true, files: { "/entry.js": /* js */ ` // These URLs should be external automatically @@ -2287,9 +2306,12 @@ describe("bundler", () => { // This should be external and should be tree-shaken because it's side-effect free import "node:path"; + import "bun"; + import "bun:sqlite"; // This should be external too, but shouldn't be tree-shaken because it could be a run-time error import "node:what-is-this"; + import "bun:what-is-this"; `, }, platform: "node", @@ -2368,18 +2390,22 @@ describe("bundler", () => { get #bar() {} set #bar(x) {} } + + cool(Foo) + cool(Bar) `, }, minifyIdentifiers: true, - mode: "transform", onAfterBundle(api) { const text = api.readFile("/out.js"); assert(text.includes("doNotRenameMe"), "bundler should not have renamed `doNotRenameMe`"); assert(!text.includes("#foo"), "bundler should have renamed `#foo`"); + assert(text.includes("#"), "bundler keeps private variables private `#`"); }, }); // These labels should all share the same minified names itBundled("default/MinifySiblingLabelsNoBundle", { + notImplemented: true, files: { "/entry.js": /* js */ ` foo: { @@ -2403,48 +2429,68 @@ describe("bundler", () => { `, }, minifyIdentifiers: true, - mode: "transform", onAfterBundle(api) { const text = api.readFile("/out.js"); const labels = [...text.matchAll(/([a-z0-9]+):/gi)].map(x => x[1]); expect(labels).toStrictEqual([labels[0], labels[1], labels[0], labels[1], labels[0], labels[1]]); }, }); + // This is such a fun file. it crashes prettier and some other parsers. + const crazyNestedLabelFile = dedent` + L001:{L002:{L003:{L004:{L005:{L006:{L007:{L008:{L009:{L010:{L011:{L012:{L013:{L014:{L015:{L016:{console.log('a') + L017:{L018:{L019:{L020:{L021:{L022:{L023:{L024:{L025:{L026:{L027:{L028:{L029:{L030:{L031:{L032:{console.log('a') + L033:{L034:{L035:{L036:{L037:{L038:{L039:{L040:{L041:{L042:{L043:{L044:{L045:{L046:{L047:{L048:{console.log('a') + L049:{L050:{L051:{L052:{L053:{L054:{L055:{L056:{L057:{L058:{L059:{L060:{L061:{L062:{L063:{L064:{console.log('a') + L065:{L066:{L067:{L068:{L069:{L070:{L071:{L072:{L073:{L074:{L075:{L076:{L077:{L078:{L079:{L080:{console.log('a') + L081:{L082:{L083:{L084:{L085:{L086:{L087:{L088:{L089:{L090:{L091:{L092:{L093:{L094:{L095:{L096:{console.log('a') + L097:{L098:{L099:{L100:{L101:{L102:{L103:{L104:{L105:{L106:{L107:{L108:{L109:{L110:{L111:{L112:{console.log('a') + L113:{L114:{L115:{L116:{L117:{L118:{L119:{L120:{L121:{L122:{L123:{L124:{L125:{L126:{L127:{L128:{console.log('a') + L129:{L130:{L131:{L132:{L133:{L134:{L135:{L136:{L137:{L138:{L139:{L140:{L141:{L142:{L143:{L144:{console.log('a') + L145:{L146:{L147:{L148:{L149:{L150:{L151:{L152:{L153:{L154:{L155:{L156:{L157:{L158:{L159:{L160:{console.log('a') + L161:{L162:{L163:{L164:{L165:{L166:{L167:{L168:{L169:{L170:{L171:{L172:{L173:{L174:{L175:{L176:{console.log('a') + L177:{L178:{L179:{L180:{L181:{L182:{L183:{L184:{L185:{L186:{L187:{L188:{L189:{L190:{L191:{L192:{console.log('a') + L193:{L194:{L195:{L196:{L197:{L198:{L199:{L200:{L201:{L202:{L203:{L204:{L205:{L206:{L207:{L208:{console.log('a') + L209:{L210:{L211:{L212:{L213:{L214:{L215:{L216:{L217:{L218:{L219:{L220:{L221:{L222:{L223:{L224:{console.log('a') + L225:{L226:{L227:{L228:{L229:{L230:{L231:{L232:{L233:{L234:{L235:{L236:{L237:{L238:{L239:{L240:{console.log('a') + L241:{L242:{L243:{L244:{L245:{L246:{L247:{L248:{L249:{L250:{L251:{L252:{L253:{L254:{L255:{L256:{console.log('a') + L257:{L258:{L259:{L260:{L261:{L262:{L263:{L264:{L265:{L266:{L267:{L268:{L269:{L270:{L271:{L272:{console.log('a') + L273:{L274:{L275:{L276:{L277:{L278:{L279:{L280:{L281:{L282:{L283:{L284:{L285:{L286:{L287:{L288:{console.log('a') + L289:{L290:{L291:{L292:{L293:{L294:{L295:{L296:{L297:{L298:{L299:{L300:{L301:{L302:{L303:{L304:{console.log('a') + L305:{L306:{L307:{L308:{L309:{L310:{L311:{L312:{L313:{L314:{L315:{L316:{L317:{L318:{L319:{L320:{console.log('a') + L321:{L322:{L323:{L324:{L325:{L326:{L327:{L328:{L329:{L330:{L331:{L332:{L333:{}}}}}}}}}}}}}}}}}}console.log('a') + }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}console.log('a') + }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}console.log('a') + }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}console.log('a') + }}}}}}}}}}}}}}}}}}}}}}}}}}} + `; + itBundled("default/NestedLabelsBundle", { + files: { + "/entry.js": crazyNestedLabelFile, + }, + }); + itBundled("default/NestedLabelsNoBundle", { + files: { + "/entry.js": crazyNestedLabelFile, + }, + mode: "transform", + }); itBundled("default/MinifyNestedLabelsNoBundle", { files: { - "/entry.js": dedent` - L001:{L002:{L003:{L004:{L005:{L006:{L007:{L008:{L009:{L010:{L011:{L012:{L013:{L014:{L015:{L016:{console.log('a') - L017:{L018:{L019:{L020:{L021:{L022:{L023:{L024:{L025:{L026:{L027:{L028:{L029:{L030:{L031:{L032:{console.log('a') - L033:{L034:{L035:{L036:{L037:{L038:{L039:{L040:{L041:{L042:{L043:{L044:{L045:{L046:{L047:{L048:{console.log('a') - L049:{L050:{L051:{L052:{L053:{L054:{L055:{L056:{L057:{L058:{L059:{L060:{L061:{L062:{L063:{L064:{console.log('a') - L065:{L066:{L067:{L068:{L069:{L070:{L071:{L072:{L073:{L074:{L075:{L076:{L077:{L078:{L079:{L080:{console.log('a') - L081:{L082:{L083:{L084:{L085:{L086:{L087:{L088:{L089:{L090:{L091:{L092:{L093:{L094:{L095:{L096:{console.log('a') - L097:{L098:{L099:{L100:{L101:{L102:{L103:{L104:{L105:{L106:{L107:{L108:{L109:{L110:{L111:{L112:{console.log('a') - L113:{L114:{L115:{L116:{L117:{L118:{L119:{L120:{L121:{L122:{L123:{L124:{L125:{L126:{L127:{L128:{console.log('a') - L129:{L130:{L131:{L132:{L133:{L134:{L135:{L136:{L137:{L138:{L139:{L140:{L141:{L142:{L143:{L144:{console.log('a') - L145:{L146:{L147:{L148:{L149:{L150:{L151:{L152:{L153:{L154:{L155:{L156:{L157:{L158:{L159:{L160:{console.log('a') - L161:{L162:{L163:{L164:{L165:{L166:{L167:{L168:{L169:{L170:{L171:{L172:{L173:{L174:{L175:{L176:{console.log('a') - L177:{L178:{L179:{L180:{L181:{L182:{L183:{L184:{L185:{L186:{L187:{L188:{L189:{L190:{L191:{L192:{console.log('a') - L193:{L194:{L195:{L196:{L197:{L198:{L199:{L200:{L201:{L202:{L203:{L204:{L205:{L206:{L207:{L208:{console.log('a') - L209:{L210:{L211:{L212:{L213:{L214:{L215:{L216:{L217:{L218:{L219:{L220:{L221:{L222:{L223:{L224:{console.log('a') - L225:{L226:{L227:{L228:{L229:{L230:{L231:{L232:{L233:{L234:{L235:{L236:{L237:{L238:{L239:{L240:{console.log('a') - L241:{L242:{L243:{L244:{L245:{L246:{L247:{L248:{L249:{L250:{L251:{L252:{L253:{L254:{L255:{L256:{console.log('a') - L257:{L258:{L259:{L260:{L261:{L262:{L263:{L264:{L265:{L266:{L267:{L268:{L269:{L270:{L271:{L272:{console.log('a') - L273:{L274:{L275:{L276:{L277:{L278:{L279:{L280:{L281:{L282:{L283:{L284:{L285:{L286:{L287:{L288:{console.log('a') - L289:{L290:{L291:{L292:{L293:{L294:{L295:{L296:{L297:{L298:{L299:{L300:{L301:{L302:{L303:{L304:{console.log('a') - L305:{L306:{L307:{L308:{L309:{L310:{L311:{L312:{L313:{L314:{L315:{L316:{L317:{L318:{L319:{L320:{console.log('a') - L321:{L322:{L323:{L324:{L325:{L326:{L327:{L328:{L329:{L330:{L331:{L332:{L333:{}}}}}}}}}}}}}}}}}}console.log('a') - }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}console.log('a') - }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}console.log('a') - }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}console.log('a') - }}}}}}}}}}}}}}}}}}}}}}}}}}} - `, + "/entry.js": crazyNestedLabelFile, }, minifyWhitespace: true, minifyIdentifiers: true, minifySyntax: true, mode: "transform", }); + itBundled("default/MinifyNestedLabelsBundle", { + files: { + "/entry.js": crazyNestedLabelFile, + }, + minifyWhitespace: true, + minifyIdentifiers: true, + minifySyntax: true, + }); itBundled("default/ExportsAndModuleFormatCommonJS", { files: { "/entry.js": /* js */ ` @@ -4474,8 +4520,14 @@ describe("bundler", () => { } const a = capture(api.readFile("/out/a.js")); const b = capture(api.readFile("/out/b.js")); - expect(a).toEqual(b); expect(a).not.toEqual(["one", "two", "three", "four"]); + expect(b).not.toEqual(["one", "two", "three", "four"]); + try { + expect(a).toEqual(b); + } catch (error) { + console.error("Comments should not affect minified names!"); + throw error; + } }, }); itBundled("default/ImportRelativeAsPackage", { diff --git a/test/bundler/esbuild/importstar.test.ts b/test/bundler/esbuild/importstar.test.ts index c9b78f7be..0b7daa532 100644 --- a/test/bundler/esbuild/importstar.test.ts +++ b/test/bundler/esbuild/importstar.test.ts @@ -32,6 +32,10 @@ describe("bundler", () => { "/foo.js": `export const foo = 123`, }, run: { + // esbuild: + // stdout: '{"default":{"foo":123},"foo":123} 123 234', + + // bun: stdout: '{"foo":123} 123 234', }, }); @@ -209,7 +213,7 @@ describe("bundler", () => { "/foo.js": `exports.foo = 123`, }, run: { - stdout: '{"default":{"foo":123},"foo":123} 123 234', + stdout: '{"foo":123} 123 234', }, }); itBundled("importstar/ImportStarCommonJSNoCapture", { @@ -247,6 +251,7 @@ describe("bundler", () => { runtimeFiles: { "/foo.js": `console.log('foo')`, }, + external: ["./foo"], run: { stdout: "foo\n234", }, @@ -263,6 +268,7 @@ describe("bundler", () => { runtimeFiles: { "/foo.js": `export const foo = 123`, }, + external: ["./foo"], run: { stdout: '{"foo":123} 123 234', }, @@ -275,6 +281,7 @@ describe("bundler", () => { console.log(ns.foo, ns.foo, foo) `, }, + external: ["./foo"], mode: "transform", runtimeFiles: { "/foo.js": `export const foo = 123`, @@ -292,6 +299,7 @@ describe("bundler", () => { `, }, minifySyntax: true, + external: ["./foo"], mode: "transform", runtimeFiles: { "/foo.js": `console.log('foo')`, @@ -310,6 +318,7 @@ describe("bundler", () => { }, minifySyntax: true, mode: "transform", + external: ["./foo"], runtimeFiles: { "/foo.js": `export const foo = 123`, }, @@ -327,6 +336,7 @@ describe("bundler", () => { }, minifySyntax: true, mode: "transform", + external: ["./foo"], runtimeFiles: { "/foo.js": `export const foo = 123`, }, @@ -355,7 +365,7 @@ describe("bundler", () => { }, dce: true, run: { - stdout: '{"x":1,"z":4}', + stdout: '{"z":4,"x":1}', }, }); itBundled("importstar/ImportExportStarAmbiguousError", { @@ -847,6 +857,9 @@ describe("bundler", () => { run: { stdout: '{"x":123} undefined', }, + bundleWarnings: { + "/entry.js": [`Import "foo" will always be undefined because there is no matching export in "foo.js"`], + }, }); itBundled("importstar/ExportOtherCommonJS", { files: { @@ -897,6 +910,9 @@ describe("bundler", () => { run: { stdout: "undefined", }, + bundleWarnings: { + "/entry.js": [`Import "foo" will always be undefined because there is no matching export in "foo.js"`], + }, }); itBundled("importstar/NamespaceImportMissingCommonJS", { files: { @@ -959,7 +975,7 @@ describe("bundler", () => { "/bar.js": `export const x = 123`, }, bundleErrors: { - "/foo.js": ['ERROR: No matching export in "bar.js" for import "foo"'], + "/foo.js": [`No matching export in "bar.js" for import "foo"`], }, }); itBundled("importstar/NamespaceImportReExportUnusedMissingES6", { @@ -972,7 +988,7 @@ describe("bundler", () => { "/bar.js": `export const x = 123`, }, bundleErrors: { - "/foo.js": ['ERROR: No matching export in "bar.js" for import "foo"'], + "/foo.js": [`No matching export in "bar.js" for import "foo"`], }, }); itBundled("importstar/NamespaceImportReExportStarMissingES6", { @@ -1208,7 +1224,7 @@ describe("bundler", () => { `, }, }); - itBundled("importstar/ImportDefaultNamespaceComboNoDefault", { + const ImportDefaultNamespaceComboNoDefault = itBundled("importstar/ImportDefaultNamespaceComboNoDefault1", { files: { "/entry-default-ns-prop.js": `import def, * as ns from './foo'; console.log(def, ns, ns.default)`, "/entry-default-ns.js": `import def, * as ns from './foo'; console.log(def, ns)`, @@ -1217,20 +1233,40 @@ describe("bundler", () => { "/entry-prop.js": `import * as ns from './foo'; console.log(ns.default)`, "/foo.js": `export let foo = 123`, }, - entryPoints: [ - "/entry-default-ns-prop.js", - "/entry-default-ns.js", - "/entry-default-prop.js", - "/entry-default.js", - "/entry-prop.js", - ], + entryPoints: ["/entry-default-ns-prop.js"], bundleErrors: { "/entry-default-ns-prop.js": ['No matching export in "foo.js" for import "default"'], + }, + }); + itBundled("importstar/ImportDefaultNamespaceComboNoDefault2", { + ...ImportDefaultNamespaceComboNoDefault.options, + entryPoints: ["/entry-default-ns.js"], + bundleErrors: { "/entry-default-ns.js": ['No matching export in "foo.js" for import "default"'], + }, + }); + itBundled("importstar/ImportDefaultNamespaceComboNoDefault3", { + ...ImportDefaultNamespaceComboNoDefault.options, + entryPoints: ["/entry-default-prop.js"], + bundleErrors: { "/entry-default-prop.js": ['No matching export in "foo.js" for import "default"'], + }, + }); + itBundled("importstar/ImportDefaultNamespaceComboNoDefault4", { + ...ImportDefaultNamespaceComboNoDefault.options, + entryPoints: ["/entry-default.js"], + bundleErrors: { "/entry-default.js": ['No matching export in "foo.js" for import "default"'], }, }); + itBundled("importstar/ImportDefaultNamespaceComboNoDefault5", { + ...ImportDefaultNamespaceComboNoDefault.options, + entryPoints: ["/entry-prop.js"], + bundleErrors: undefined, + bundleWarnings: { + "/entry-prop.js": [`Import "default" will always be undefined because there is no matching export in "foo.js"`], + }, + }); itBundled("importstar/ImportNamespaceUndefinedPropertyEmptyFile", { files: { "/entry-nope.js": /* js */ ` @@ -1260,9 +1296,9 @@ describe("bundler", () => { entryPoints: ["/entry-nope.js", "/entry-default.js"], bundleWarnings: { "/entry-nope.js": [ - 'Import "nope" will always be undefined because the file "empty.js" has no exports', - 'Import "nope" will always be undefined because the file "empty.mjs" has no exports', - 'Import "nope" will always be undefined because the file "empty.cjs" has no exports', + `Import "nope" will always be undefined because there is no matching export in "empty.js"`, + `Import "nope" will always be undefined because there is no matching export in "empty.mjs"`, + `Import "nope" will always be undefined because there is no matching export in "empty.cjs"`, ], }, run: [ @@ -1314,6 +1350,21 @@ describe("bundler", () => { stdout: `js\ncjs\n{} undefined {}`, }, ], + bundleWarnings: { + "/foo/no-side-effects.js": [ + `Import "nope" will always be undefined because the file "foo/no-side-effects.js" has no exports`, + ], + "/foo/no-side-effects.mjs": [ + `Import "nope" will always be undefined because the file "foo/no-side-effects.mjs" has no exports`, + ], + "/foo/no-side-effects.cjs": [ + `Import "nope" will always be undefined because the file "foo/no-side-effects.cjs" has no exports`, + ], + "/entry-default.js": [ + `Import "default" will always be undefined because there is no matching export in "foo/no-side-effects.js"`, + `Import "default" will always be undefined because there is no matching export in "foo/no-side-effects.mjs"`, + ], + }, }); itBundled("importstar/ReExportStarEntryPointAndInnerFile", { files: { diff --git a/test/bundler/esbuild/loader.test.ts b/test/bundler/esbuild/loader.test.ts index 1ca741749..54b5a04e5 100644 --- a/test/bundler/esbuild/loader.test.ts +++ b/test/bundler/esbuild/loader.test.ts @@ -102,26 +102,28 @@ describe("bundler", () => { }, }); itBundled("loader/JSXPreserveCapitalLetterMinify", { - // GENERATED files: { "/entry.jsx": /* jsx */ ` import { mustStartWithUpperCaseLetter as XYYYY } from './foo' - console.log(<XYYYY tag-must-start-with-capital-letter />) + // This should be named "Y" due to frequency analysis + console.log(<XYYYY YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY />) `, "/foo.js": `export class mustStartWithUpperCaseLetter {}`, }, + external: ["react"], minifyIdentifiers: true, }); itBundled("loader/JSXPreserveCapitalLetterMinifyNested", { - // GENERATED files: { "/entry.jsx": /* jsx */ ` x = () => { - class XYYYYY {} // This should be named "Y" due to frequency analysis - return <XYYYYY tag-must-start-with-capital-letter /> + class RENAME_ME {} // This should be named "Y" due to frequency analysis + capture(RENAME_ME) + return <RENAME_ME YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY /> } `, }, + external: ["react"], minifyIdentifiers: true, }); itBundled("loader/RequireCustomExtensionString", { diff --git a/test/bundler/esbuild/packagejson.test.ts b/test/bundler/esbuild/packagejson.test.ts index e3e5387b3..7f1a31762 100644 --- a/test/bundler/esbuild/packagejson.test.ts +++ b/test/bundler/esbuild/packagejson.test.ts @@ -7,9 +7,7 @@ var { describe, test, expect } = testForFile(import.meta.path); // For debug, all files are written to $TEMP/bun-bundle-tests/packagejson describe("bundler", () => { - if (!RUN_UNCHECKED_TESTS) return; - itBundled("packagejson/PackageJsonMain", { - // GENERATED + itBundled("packagejson/Main", { files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' @@ -26,9 +24,11 @@ describe("bundler", () => { } `, }, + run: { + stdout: "123", + }, }); - itBundled("packagejson/PackageJsonBadMain", { - // GENERATED + itBundled("packagejson/BadMain", { files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' @@ -45,9 +45,12 @@ describe("bundler", () => { } `, }, + run: { + stdout: "123", + }, }); - itBundled("packagejson/PackageJsonSyntaxErrorComment", { - // GENERATED + itBundled("packagejson/SyntaxErrorComment", { + notImplemented: true, files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' @@ -65,11 +68,12 @@ describe("bundler", () => { } `, }, - /* TODO FIX expectedScanLog: `Users/user/project/node_modules/demo-pkg/package.json: ERROR: JSON does not support comments - `, */ + bundleErrors: { + "/Users/user/project/node_modules/demo-pkg/package.json": ["JSON does not support comments"], + }, }); - itBundled("packagejson/PackageJsonSyntaxErrorTrailingComma", { - // GENERATED + itBundled("packagejson/SyntaxErrorTrailingComma", { + notImplemented: true, files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' @@ -87,10 +91,11 @@ describe("bundler", () => { } `, }, - /* TODO FIX expectedScanLog: `Users/user/project/node_modules/demo-pkg/package.json: ERROR: JSON does not support trailing commas - `, */ + bundleErrors: { + "/Users/user/project/node_modules/demo-pkg/package.json": ["JSON does not support trailing commas"], + }, }); - itBundled("packagejson/PackageJsonModule", { + itBundled("packagejson/Module", { // GENERATED files: { "/Users/user/project/src/entry.js": /* js */ ` @@ -110,13 +115,15 @@ describe("bundler", () => { `, "/Users/user/project/node_modules/demo-pkg/main.esm.js": /* js */ ` export default function() { - return 123 + return 234 } `, }, + run: { + stdout: "234", + }, }); - itBundled("packagejson/PackageJsonBrowserString", { - // GENERATED + itBundled("packagejson/BrowserString", { files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' @@ -133,13 +140,15 @@ describe("bundler", () => { } `, }, + run: { + stdout: "123", + }, }); - itBundled("packagejson/PackageJsonBrowserMapRelativeToRelative", { - // GENERATED + itBundled("packagejson/BrowserMapRelativeToRelative", { files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' - console.log(fn()) + console.log(JSON.stringify(fn())) `, "/Users/user/project/node_modules/demo-pkg/package.json": /* json */ ` { @@ -165,13 +174,15 @@ describe("bundler", () => { "/Users/user/project/node_modules/demo-pkg/lib/util.js": `module.exports = 'util'`, "/Users/user/project/node_modules/demo-pkg/lib/util-browser.js": `module.exports = 'util-browser'`, }, + run: { + stdout: `["main-browser","util-browser"]`, + }, }); - itBundled("packagejson/PackageJsonBrowserMapRelativeToModule", { - // GENERATED + itBundled("packagejson/BrowserMapRelativeToModule", { files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' - console.log(fn()) + console.log(JSON.stringify(fn())) `, "/Users/user/project/node_modules/demo-pkg/package.json": /* json */ ` { @@ -190,13 +201,15 @@ describe("bundler", () => { "/Users/user/project/node_modules/demo-pkg/util.js": `module.exports = 'util'`, "/Users/user/project/node_modules/util-browser/index.js": `module.exports = 'util-browser'`, }, + run: { + stdout: `["main","util-browser"]`, + }, }); - itBundled("packagejson/PackageJsonBrowserMapRelativeDisabled", { - // GENERATED + itBundled("packagejson/BrowserMapRelativeDisabled", { files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' - console.log(fn()) + console.log(JSON.stringify(fn(123))) `, "/Users/user/project/node_modules/demo-pkg/package.json": /* json */ ` { @@ -209,14 +222,16 @@ describe("bundler", () => { "/Users/user/project/node_modules/demo-pkg/main.js": /* js */ ` const util = require('./util-node') module.exports = function(obj) { - return util.inspect(obj) + return [util.inspect, obj] } `, "/Users/user/project/node_modules/demo-pkg/util-node.js": `module.exports = require('util')`, }, + run: { + stdout: `[null,123]`, + }, }); - itBundled("packagejson/PackageJsonBrowserMapModuleToRelative", { - // GENERATED + itBundled("packagejson/BrowserMapModuleToRelative", { files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' @@ -246,9 +261,11 @@ describe("bundler", () => { } `, }, + run: { + stdout: "123", + }, }); - itBundled("packagejson/PackageJsonBrowserMapModuleToModule", { - // GENERATED + itBundled("packagejson/BrowserMapModuleToModule", { files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' @@ -278,9 +295,12 @@ describe("bundler", () => { } `, }, + run: { + stdout: "123", + }, }); - itBundled("packagejson/PackageJsonBrowserMapModuleDisabled", { - // GENERATED + itBundled("packagejson/BrowserMapModuleDisabled", { + notImplemented: true, files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' @@ -295,8 +315,9 @@ describe("bundler", () => { `, "/Users/user/project/node_modules/demo-pkg/index.js": /* js */ ` const fn = require('node-pkg') + console.log(fn) module.exports = function() { - return fn() + return typeof fn === 'function' ? fn() : 123 } `, "/Users/user/project/node_modules/node-pkg/index.js": /* js */ ` @@ -305,9 +326,11 @@ describe("bundler", () => { } `, }, + run: { + stdout: "{}\n123", + }, }); - itBundled("packagejson/PackageJsonBrowserMapNativeModuleDisabled", { - // GENERATED + itBundled("packagejson/BrowserMapNativeModuleDisabled", { files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' @@ -323,13 +346,15 @@ describe("bundler", () => { "/Users/user/project/node_modules/demo-pkg/index.js": /* js */ ` const fs = require('fs') module.exports = function() { - return fs.readFile() + return fs.readFile === undefined } `, }, + run: { + stdout: "true", + }, }); - itBundled("packagejson/PackageJsonBrowserMapAvoidMissing", { - // GENERATED + itBundled("packagejson/BrowserMapAvoidMissing", { files: { "/Users/user/project/src/entry.js": `import 'component-classes'`, "/Users/user/project/node_modules/component-classes/package.json": /* json */ ` @@ -343,18 +368,27 @@ describe("bundler", () => { try { var index = require('indexof'); } catch (err) { + console.log('catch') var index = require('component-indexof'); } + console.log(index()) `, "/Users/user/project/node_modules/component-indexof/index.js": /* js */ ` module.exports = function() { return 234 } `, + "/Users/user/project/node_modules/indexof/index.js": /* js */ ` + module.exports = function() { + return 123 + } + `, + }, + run: { + stdout: "234", }, }); - itBundled("packagejson/PackageJsonBrowserOverModuleBrowser", { - // GENERATED + itBundled("packagejson/BrowserOverModuleBrowser", { files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' @@ -374,19 +408,21 @@ describe("bundler", () => { `, "/Users/user/project/node_modules/demo-pkg/main.esm.js": /* js */ ` export default function() { - return 123 + return 234 } `, "/Users/user/project/node_modules/demo-pkg/main.browser.js": /* js */ ` module.exports = function() { - return 123 + return 345 } `, }, platform: "browser", + run: { + stdout: "345", + }, }); - itBundled("packagejson/PackageJsonBrowserOverMainNode", { - // GENERATED + itBundled("packagejson/BrowserOverMainNode", { files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' @@ -406,19 +442,21 @@ describe("bundler", () => { `, "/Users/user/project/node_modules/demo-pkg/main.esm.js": /* js */ ` export default function() { - return 123 + return 234 } `, "/Users/user/project/node_modules/demo-pkg/main.browser.js": /* js */ ` module.exports = function() { - return 123 + return 345 } `, }, platform: "node", + run: { + stdout: "123", + }, }); - itBundled("packagejson/PackageJsonBrowserWithModuleBrowser", { - // GENERATED + itBundled("packagejson/BrowserWithModuleBrowser", { files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' @@ -441,24 +479,26 @@ describe("bundler", () => { `, "/Users/user/project/node_modules/demo-pkg/main.esm.js": /* js */ ` export default function() { - return 123 + return 234 } `, "/Users/user/project/node_modules/demo-pkg/main.browser.js": /* js */ ` module.exports = function() { - return 123 + return 345 } `, "/Users/user/project/node_modules/demo-pkg/main.browser.esm.js": /* js */ ` export default function() { - return 123 + return 456 } `, }, platform: "browser", + run: { + stdout: "456", + }, }); - itBundled("packagejson/PackageJsonBrowserWithMainNode", { - // GENERATED + itBundled("packagejson/BrowserWithMainNode", { files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' @@ -481,30 +521,33 @@ describe("bundler", () => { `, "/Users/user/project/node_modules/demo-pkg/main.esm.js": /* js */ ` export default function() { - return 123 + return 234 } `, "/Users/user/project/node_modules/demo-pkg/main.browser.js": /* js */ ` module.exports = function() { - return 123 + return 345 } `, "/Users/user/project/node_modules/demo-pkg/main.browser.esm.js": /* js */ ` export default function() { - return 123 + return 456 } `, }, platform: "node", + run: { + stdout: "123", + }, }); - itBundled("packagejson/PackageJsonBrowserNodeModulesNoExt", { - // GENERATED + itBundled("packagejson/BrowserNodeModulesNoExt", { + notImplemented: true, files: { "/Users/user/project/src/entry.js": /* js */ ` - import {browser as a} from 'demo-pkg/no-ext' - import {node as b} from 'demo-pkg/no-ext.js' - import {browser as c} from 'demo-pkg/ext' - import {browser as d} from 'demo-pkg/ext.js' + import {value as a} from 'demo-pkg/no-ext' + import {value as b} from 'demo-pkg/no-ext.js' + import {value as c} from 'demo-pkg/ext' + import {value as d} from 'demo-pkg/ext.js' console.log(a) console.log(b) console.log(c) @@ -518,20 +561,28 @@ describe("bundler", () => { } } `, - "/Users/user/project/node_modules/demo-pkg/no-ext.js": `export let node = 'node'`, - "/Users/user/project/node_modules/demo-pkg/no-ext-browser.js": `export let browser = 'browser'`, - "/Users/user/project/node_modules/demo-pkg/ext.js": `export let node = 'node'`, - "/Users/user/project/node_modules/demo-pkg/ext-browser.js": `export let browser = 'browser'`, + "/Users/user/project/node_modules/demo-pkg/no-ext.js": `export let value = 'node'`, + "/Users/user/project/node_modules/demo-pkg/no-ext-browser.js": `export let value = 'browser'`, + "/Users/user/project/node_modules/demo-pkg/ext.js": `export let value = 'node'`, + "/Users/user/project/node_modules/demo-pkg/ext-browser.js": `export let value = 'browser'`, + }, + run: { + stdout: ` + browser + node + browser + browser + `, }, }); - itBundled("packagejson/PackageJsonBrowserNodeModulesIndexNoExt", { - // GENERATED + itBundled("packagejson/BrowserNodeModulesIndexNoExt", { + notImplemented: true, files: { "/Users/user/project/src/entry.js": /* js */ ` - import {browser as a} from 'demo-pkg/no-ext' - import {node as b} from 'demo-pkg/no-ext/index.js' - import {browser as c} from 'demo-pkg/ext' - import {browser as d} from 'demo-pkg/ext/index.js' + import {value as a} from 'demo-pkg/no-ext' + import {value as b} from 'demo-pkg/no-ext/index.js' + import {value as c} from 'demo-pkg/ext' + import {value as d} from 'demo-pkg/ext/index.js' console.log(a) console.log(b) console.log(c) @@ -545,20 +596,27 @@ describe("bundler", () => { } } `, - "/Users/user/project/node_modules/demo-pkg/no-ext/index.js": `export let node = 'node'`, - "/Users/user/project/node_modules/demo-pkg/no-ext-browser/index.js": `export let browser = 'browser'`, - "/Users/user/project/node_modules/demo-pkg/ext/index.js": `export let node = 'node'`, - "/Users/user/project/node_modules/demo-pkg/ext-browser/index.js": `export let browser = 'browser'`, + "/Users/user/project/node_modules/demo-pkg/no-ext/index.js": `export let value = 'node'`, + "/Users/user/project/node_modules/demo-pkg/no-ext-browser/index.js": `export let value = 'browser'`, + "/Users/user/project/node_modules/demo-pkg/ext/index.js": `export let value = 'node'`, + "/Users/user/project/node_modules/demo-pkg/ext-browser/index.js": `export let value = 'browser'`, + }, + run: { + stdout: ` + browser + node + browser + browser + `, }, }); - itBundled("packagejson/PackageJsonBrowserNoExt", { - // GENERATED + itBundled("packagejson/BrowserNoExt", { files: { "/Users/user/project/src/entry.js": /* js */ ` - import {browser as a} from './demo-pkg/no-ext' - import {node as b} from './demo-pkg/no-ext.js' - import {browser as c} from './demo-pkg/ext' - import {browser as d} from './demo-pkg/ext.js' + import {value as a} from './demo-pkg/no-ext' + import {value as b} from './demo-pkg/no-ext.js' + import {value as c} from './demo-pkg/ext' + import {value as d} from './demo-pkg/ext.js' console.log(a) console.log(b) console.log(c) @@ -572,20 +630,27 @@ describe("bundler", () => { } } `, - "/Users/user/project/src/demo-pkg/no-ext.js": `export let node = 'node'`, - "/Users/user/project/src/demo-pkg/no-ext-browser.js": `export let browser = 'browser'`, - "/Users/user/project/src/demo-pkg/ext.js": `export let node = 'node'`, - "/Users/user/project/src/demo-pkg/ext-browser.js": `export let browser = 'browser'`, + "/Users/user/project/src/demo-pkg/no-ext.js": `export let value = 'node'`, + "/Users/user/project/src/demo-pkg/no-ext-browser.js": `export let value = 'browser'`, + "/Users/user/project/src/demo-pkg/ext.js": `export let value = 'node'`, + "/Users/user/project/src/demo-pkg/ext-browser.js": `export let value = 'browser'`, + }, + run: { + stdout: ` + browser + node + browser + browser + `, }, }); - itBundled("packagejson/PackageJsonBrowserIndexNoExt", { - // GENERATED + itBundled("packagejson/BrowserIndexNoExt", { files: { "/Users/user/project/src/entry.js": /* js */ ` - import {browser as a} from './demo-pkg/no-ext' - import {node as b} from './demo-pkg/no-ext/index.js' - import {browser as c} from './demo-pkg/ext' - import {browser as d} from './demo-pkg/ext/index.js' + import {value as a} from './demo-pkg/no-ext' + import {value as b} from './demo-pkg/no-ext/index.js' + import {value as c} from './demo-pkg/ext' + import {value as d} from './demo-pkg/ext/index.js' console.log(a) console.log(b) console.log(c) @@ -599,30 +664,41 @@ describe("bundler", () => { } } `, - "/Users/user/project/src/demo-pkg/no-ext/index.js": `export let node = 'node'`, - "/Users/user/project/src/demo-pkg/no-ext-browser/index.js": `export let browser = 'browser'`, - "/Users/user/project/src/demo-pkg/ext/index.js": `export let node = 'node'`, - "/Users/user/project/src/demo-pkg/ext-browser/index.js": `export let browser = 'browser'`, + "/Users/user/project/src/demo-pkg/no-ext/index.js": `export let value = 'node'`, + "/Users/user/project/src/demo-pkg/no-ext-browser/index.js": `export let value = 'browser'`, + "/Users/user/project/src/demo-pkg/ext/index.js": `export let value = 'node'`, + "/Users/user/project/src/demo-pkg/ext-browser/index.js": `export let value = 'browser'`, + }, + run: { + stdout: ` + browser + node + browser + browser + `, }, }); - itBundled("packagejson/PackageJsonBrowserESBuildIssue2002A", { - // GENERATED + itBundled("packagejson/BrowserESBuildIssue2002A", { + notImplemented: true, files: { "/Users/user/project/src/entry.js": `require('pkg/sub')`, "/Users/user/project/src/node_modules/pkg/package.json": /* json */ ` { - "browser": { - "./sub": "./sub/foo.js" + "browser": { + "./sub": "./sub/foo.js" + } } - } `, "/Users/user/project/src/node_modules/pkg/sub/foo.js": `require('sub')`, "/Users/user/project/src/node_modules/sub/package.json": `{ "main": "./bar" }`, - "/Users/user/project/src/node_modules/sub/bar.js": `works()`, + "/Users/user/project/src/node_modules/sub/bar.js": `console.log('it works')`, + }, + run: { + stdout: "it works", }, }); - itBundled("packagejson/PackageJsonBrowserESBuildIssue2002B", { - // GENERATED + itBundled("packagejson/BrowserESBuildIssue2002B", { + notImplemented: true, files: { "/Users/user/project/src/entry.js": `require('pkg/sub')`, "/Users/user/project/src/node_modules/pkg/package.json": /* json */ ` @@ -634,11 +710,14 @@ describe("bundler", () => { } `, "/Users/user/project/src/node_modules/pkg/sub/foo.js": `require('sub')`, - "/Users/user/project/src/node_modules/pkg/sub/bar.js": `works()`, + "/Users/user/project/src/node_modules/pkg/sub/bar.js": `console.log('it works')`, + }, + run: { + stdout: "it works", }, }); - itBundled("packagejson/PackageJsonBrowserESBuildIssue2002C", { - // GENERATED + itBundled("packagejson/BrowserESBuildIssue2002C", { + notImplemented: true, files: { "/Users/user/project/src/entry.js": `require('pkg/sub')`, "/Users/user/project/src/node_modules/pkg/package.json": /* json */ ` @@ -650,11 +729,13 @@ describe("bundler", () => { } `, "/Users/user/project/src/node_modules/pkg/sub/foo.js": `require('sub')`, - "/Users/user/project/src/node_modules/sub/index.js": `works()`, + "/Users/user/project/src/node_modules/sub/index.js": `console.log('it works')`, + }, + run: { + stdout: "it works", }, }); - itBundled("packagejson/PackageJsonDualPackageHazardImportOnly", { - // GENERATED + itBundled("packagejson/DualPackageHazardImportOnly", { files: { "/Users/user/project/src/entry.js": /* js */ ` import value from 'demo-pkg' @@ -669,9 +750,11 @@ describe("bundler", () => { "/Users/user/project/node_modules/demo-pkg/main.js": `module.exports = 'main'`, "/Users/user/project/node_modules/demo-pkg/module.js": `export default 'module'`, }, + run: { + stdout: "module", + }, }); - itBundled("packagejson/PackageJsonDualPackageHazardRequireOnly", { - // GENERATED + itBundled("packagejson/DualPackageHazardRequireOnly", { files: { "/Users/user/project/src/entry.js": `console.log(require('demo-pkg'))`, "/Users/user/project/node_modules/demo-pkg/package.json": /* json */ ` @@ -683,9 +766,12 @@ describe("bundler", () => { "/Users/user/project/node_modules/demo-pkg/main.js": `module.exports = 'main'`, "/Users/user/project/node_modules/demo-pkg/module.js": `export default 'module'`, }, + run: { + stdout: "main", + }, }); - itBundled("packagejson/PackageJsonDualPackageHazardImportAndRequireSameFile", { - // GENERATED + itBundled("packagejson/DualPackageHazardImportAndRequireSameFile", { + notImplemented: true, files: { "/Users/user/project/src/entry.js": /* js */ ` import value from 'demo-pkg' @@ -700,9 +786,11 @@ describe("bundler", () => { "/Users/user/project/node_modules/demo-pkg/main.js": `module.exports = 'main'`, "/Users/user/project/node_modules/demo-pkg/module.js": `export default 'module'`, }, + run: { + stdout: "main main", + }, }); - itBundled("packagejson/PackageJsonDualPackageHazardImportAndRequireSeparateFiles", { - // GENERATED + itBundled("packagejson/DualPackageHazardImportAndRequireSeparateFiles", { files: { "/Users/user/project/src/entry.js": /* js */ ` import './test-main' @@ -722,15 +810,17 @@ describe("bundler", () => { "/Users/user/project/node_modules/demo-pkg/main.js": `module.exports = 'main'`, "/Users/user/project/node_modules/demo-pkg/module.js": `export default 'module'`, }, + run: { + stdout: "main\nmain", + }, }); - itBundled("packagejson/PackageJsonDualPackageHazardImportAndRequireForceModuleBeforeMain", { - // GENERATED + itBundled("packagejson/DualPackageHazardImportAndRequireForceModuleBeforeMain", { files: { "/Users/user/project/src/entry.js": /* js */ ` import './test-main' import './test-module' `, - "/Users/user/project/src/test-main.js": `console.log(require('demo-pkg'))`, + "/Users/user/project/src/test-main.js": `console.log(require('demo-pkg').default)`, "/Users/user/project/src/test-module.js": /* js */ ` import value from 'demo-pkg' console.log(value) @@ -745,9 +835,11 @@ describe("bundler", () => { "/Users/user/project/node_modules/demo-pkg/module.js": `export default 'module'`, }, mainFields: ["module", "main"], + run: { + stdout: "module\nmodule", + }, }); - itBundled("packagejson/PackageJsonDualPackageHazardImportAndRequireImplicitMain", { - // GENERATED + itBundled("packagejson/DualPackageHazardImportAndRequireImplicitMain", { files: { "/Users/user/project/src/entry.js": /* js */ ` import './test-index' @@ -766,15 +858,17 @@ describe("bundler", () => { "/Users/user/project/node_modules/demo-pkg/index.js": `module.exports = 'index'`, "/Users/user/project/node_modules/demo-pkg/module.js": `export default 'module'`, }, + run: { + stdout: "index\nindex", + }, }); - itBundled("packagejson/PackageJsonDualPackageHazardImportAndRequireImplicitMainForceModuleBeforeMain", { - // GENERATED + itBundled("packagejson/DualPackageHazardImportAndRequireImplicitMainForceModuleBeforeMain", { files: { "/Users/user/project/src/entry.js": /* js */ ` import './test-index' import './test-module' `, - "/Users/user/project/src/test-index.js": `console.log(require('demo-pkg'))`, + "/Users/user/project/src/test-index.js": `console.log(require('demo-pkg').default)`, "/Users/user/project/src/test-module.js": /* js */ ` import value from 'demo-pkg' console.log(value) @@ -788,9 +882,12 @@ describe("bundler", () => { "/Users/user/project/node_modules/demo-pkg/module.js": `export default 'module'`, }, mainFields: ["module", "main"], + run: { + stdout: "module\nmodule", + }, }); - itBundled("packagejson/PackageJsonDualPackageHazardImportAndRequireBrowser", { - // GENERATED + itBundled("packagejson/DualPackageHazardImportAndRequireBrowser", { + notImplemented: true, files: { "/Users/user/project/src/entry.js": /* js */ ` import './test-main' @@ -816,9 +913,11 @@ describe("bundler", () => { "/Users/user/project/node_modules/demo-pkg/main.browser.js": `module.exports = 'browser main'`, "/Users/user/project/node_modules/demo-pkg/module.browser.js": `export default 'browser module'`, }, + run: { + stdout: "browser main\nbrowser main", + }, }); - itBundled("packagejson/PackageJsonMainFieldsA", { - // GENERATED + itBundled("packagejson/MainFieldsA", { files: { "/Users/user/project/src/entry.js": /* js */ ` import value from 'demo-pkg' @@ -834,9 +933,11 @@ describe("bundler", () => { "/Users/user/project/node_modules/demo-pkg/b.js": `export default 'b'`, }, mainFields: ["a", "b"], + run: { + stdout: "a", + }, }); - itBundled("packagejson/PackageJsonMainFieldsB", { - // GENERATED + itBundled("packagejson/MainFieldsB", { files: { "/Users/user/project/src/entry.js": /* js */ ` import value from 'demo-pkg' @@ -852,9 +953,12 @@ describe("bundler", () => { "/Users/user/project/node_modules/demo-pkg/b.js": `export default 'b'`, }, mainFields: ["b", "a"], + run: { + stdout: "b", + }, }); - itBundled("packagejson/PackageJsonNeutralNoDefaultMainFields", { - // GENERATED + itBundled("packagejson/NeutralNoDefaultMainFields", { + notImplemented: true, files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' @@ -883,8 +987,7 @@ describe("bundler", () => { NOTE: You can mark the path "demo-pkg" as external to exclude it from the bundle, which will remove this error. `, */ }); - itBundled("packagejson/PackageJsonNeutralExplicitMainFields", { - // GENERATED + itBundled("packagejson/NeutralExplicitMainFields", { files: { "/Users/user/project/src/entry.js": /* js */ ` import fn from 'demo-pkg' @@ -901,12 +1004,19 @@ describe("bundler", () => { return 123 } `, + "/Users/user/project/node_modules/demo-pkg/main.esm.js": /* js */ ` + export default function() { + return 234 + } + `, }, platform: "neutral", mainFields: ["hello"], + run: { + stdout: "123", + }, }); - itBundled("packagejson/PackageJsonExportsErrorInvalidModuleSpecifier", { - // GENERATED + itBundled("packagejson/ExportsErrorInvalidModuleSpecifier", { files: { "/Users/user/project/src/entry.js": /* js */ ` import 'pkg1' @@ -924,25 +1034,17 @@ describe("bundler", () => { "/Users/user/project/node_modules/pkg6/package.json": `{ "exports": { ".": "./%31.js" } }`, "/Users/user/project/node_modules/pkg6/1.js": `console.log(1)`, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1" - Users/user/project/node_modules/pkg1/package.json: NOTE: The module specifier "./%%" is invalid: - NOTE: You can mark the path "pkg1" as external to exclude it from the bundle, which will remove this error. - Users/user/project/src/entry.js: ERROR: Could not resolve "pkg2" - Users/user/project/node_modules/pkg2/package.json: NOTE: The module specifier "./%2f" is invalid: - NOTE: You can mark the path "pkg2" as external to exclude it from the bundle, which will remove this error. - Users/user/project/src/entry.js: ERROR: Could not resolve "pkg3" - Users/user/project/node_modules/pkg3/package.json: NOTE: The module specifier "./%2F" is invalid: - NOTE: You can mark the path "pkg3" as external to exclude it from the bundle, which will remove this error. - Users/user/project/src/entry.js: ERROR: Could not resolve "pkg4" - Users/user/project/node_modules/pkg4/package.json: NOTE: The module specifier "./%5c" is invalid: - NOTE: You can mark the path "pkg4" as external to exclude it from the bundle, which will remove this error. - Users/user/project/src/entry.js: ERROR: Could not resolve "pkg5" - Users/user/project/node_modules/pkg5/package.json: NOTE: The module specifier "./%5C" is invalid: - NOTE: You can mark the path "pkg5" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [ + `Could not resolve: "pkg1". Maybe you need to "bun install"?`, + `Could not resolve: "pkg2". Maybe you need to "bun install"?`, + `Could not resolve: "pkg3". Maybe you need to "bun install"?`, + `Could not resolve: "pkg4". Maybe you need to "bun install"?`, + `Could not resolve: "pkg5". Maybe you need to "bun install"?`, + ], + }, }); - itBundled("packagejson/PackageJsonExportsErrorInvalidPackageConfiguration", { - // GENERATED + itBundled("packagejson/ExportsErrorInvalidPackageConfiguration", { files: { "/Users/user/project/src/entry.js": /* js */ ` import 'pkg1' @@ -951,18 +1053,14 @@ describe("bundler", () => { "/Users/user/project/node_modules/pkg1/package.json": `{ "exports": { ".": false } }`, "/Users/user/project/node_modules/pkg2/package.json": `{ "exports": { "./foo": false } }`, }, - /* TODO FIX expectedScanLog: `Users/user/project/node_modules/pkg1/package.json: WARNING: This value must be a string, an object, an array, or null - Users/user/project/node_modules/pkg2/package.json: WARNING: This value must be a string, an object, an array, or null - Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1" - Users/user/project/node_modules/pkg1/package.json: NOTE: The package configuration has an invalid value here: - NOTE: You can mark the path "pkg1" as external to exclude it from the bundle, which will remove this error. - Users/user/project/src/entry.js: ERROR: Could not resolve "pkg2/foo" - Users/user/project/node_modules/pkg2/package.json: NOTE: The package configuration has an invalid value here: - NOTE: You can mark the path "pkg2/foo" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [ + `Could not resolve: "pkg1". Maybe you need to "bun install"?`, + `Could not resolve: "pkg2/foo". Maybe you need to "bun install"?`, + ], + }, }); - itBundled("packagejson/PackageJsonExportsErrorInvalidPackageTarget", { - // GENERATED + itBundled("packagejson/ExportsErrorInvalidPackageTarget", { files: { "/Users/user/project/src/entry.js": /* js */ ` import 'pkg1' @@ -973,41 +1071,33 @@ describe("bundler", () => { "/Users/user/project/node_modules/pkg2/package.json": `{ "exports": { ".": "./../pkg3" } }`, "/Users/user/project/node_modules/pkg3/package.json": `{ "exports": { ".": "./node_modules/pkg" } }`, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1" - Users/user/project/node_modules/pkg1/package.json: NOTE: The package target "invalid" is invalid because it doesn't start with "./": - NOTE: You can mark the path "pkg1" as external to exclude it from the bundle, which will remove this error. - Users/user/project/src/entry.js: ERROR: Could not resolve "pkg2" - Users/user/project/node_modules/pkg2/package.json: NOTE: The package target "./../pkg3" is invalid because it contains invalid segment "..": - NOTE: You can mark the path "pkg2" as external to exclude it from the bundle, which will remove this error. - Users/user/project/src/entry.js: ERROR: Could not resolve "pkg3" - Users/user/project/node_modules/pkg3/package.json: NOTE: The package target "./node_modules/pkg" is invalid because it contains invalid segment "node_modules": - NOTE: You can mark the path "pkg3" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [ + `Could not resolve: "pkg1". Maybe you need to "bun install"?`, + `Could not resolve: "pkg2". Maybe you need to "bun install"?`, + `Could not resolve: "pkg3". Maybe you need to "bun install"?`, + ], + }, }); - itBundled("packagejson/PackageJsonExportsErrorPackagePathNotExported", { - // GENERATED + itBundled("packagejson/ExportsErrorPackagePathNotExported", { files: { "/Users/user/project/src/entry.js": `import 'pkg1/foo'`, "/Users/user/project/node_modules/pkg1/package.json": `{ "exports": { ".": {} } }`, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1/foo" - Users/user/project/node_modules/pkg1/package.json: NOTE: The path "./foo" is not exported by package "pkg1": - NOTE: You can mark the path "pkg1/foo" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [`Could not resolve: "pkg1/foo". Maybe you need to "bun install"?`], + }, }); - itBundled("packagejson/PackageJsonExportsErrorModuleNotFound", { - // GENERATED + itBundled("packagejson/ExportsErrorModuleNotFound", { files: { "/Users/user/project/src/entry.js": `import 'pkg1'`, "/Users/user/project/node_modules/pkg1/package.json": `{ "exports": { ".": "./foo.js" } }`, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1" - Users/user/project/node_modules/pkg1/package.json: NOTE: The module "./foo.js" was not found on the file system: - NOTE: You can mark the path "pkg1" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [`Could not resolve: "pkg1". Maybe you need to "bun install"?`], + }, }); - itBundled("packagejson/PackageJsonExportsErrorUnsupportedDirectoryImport", { - // GENERATED + itBundled("packagejson/ExportsErrorUnsupportedDirectoryImport", { files: { "/Users/user/project/src/entry.js": /* js */ ` import 'pkg1' @@ -1017,17 +1107,14 @@ describe("bundler", () => { "/Users/user/project/node_modules/pkg2/package.json": `{ "exports": { ".": "./foo" } }`, "/Users/user/project/node_modules/pkg2/foo/bar.js": `console.log(bar)`, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1" - Users/user/project/node_modules/pkg1/package.json: NOTE: The module "./foo" was not found on the file system: - NOTE: You can mark the path "pkg1" as external to exclude it from the bundle, which will remove this error. - Users/user/project/src/entry.js: ERROR: Could not resolve "pkg2" - Users/user/project/node_modules/pkg2/package.json: NOTE: Importing the directory "./foo" is forbidden by this package: - Users/user/project/node_modules/pkg2/package.json: NOTE: The presence of "exports" here makes importing a directory forbidden: - NOTE: You can mark the path "pkg2" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [ + `Could not resolve: "pkg1". Maybe you need to "bun install"?`, + `Could not resolve: "pkg2". Maybe you need to "bun install"?`, + ], + }, }); - itBundled("packagejson/PackageJsonExportsRequireOverImport", { - // GENERATED + itBundled("packagejson/ExportsRequireOverImport", { files: { "/Users/user/project/src/entry.js": `require('pkg')`, "/Users/user/project/node_modules/pkg/package.json": /* json */ ` @@ -1042,9 +1129,11 @@ describe("bundler", () => { "/Users/user/project/node_modules/pkg/import.js": `console.log('FAILURE')`, "/Users/user/project/node_modules/pkg/require.js": `console.log('SUCCESS')`, }, + run: { + stdout: "SUCCESS", + }, }); - itBundled("packagejson/PackageJsonExportsImportOverRequire", { - // GENERATED + itBundled("packagejson/ExportsImportOverRequire", { files: { "/Users/user/project/src/entry.js": `import 'pkg'`, "/Users/user/project/node_modules/pkg/package.json": /* json */ ` @@ -1059,9 +1148,11 @@ describe("bundler", () => { "/Users/user/project/node_modules/pkg/require.js": `console.log('FAILURE')`, "/Users/user/project/node_modules/pkg/import.js": `console.log('SUCCESS')`, }, + run: { + stdout: "SUCCESS", + }, }); - itBundled("packagejson/PackageJsonExportsDefaultOverImportAndRequire", { - // GENERATED + itBundled("packagejson/ExportsDefaultOverImportAndRequire", { files: { "/Users/user/project/src/entry.js": `import 'pkg'`, "/Users/user/project/node_modules/pkg/package.json": /* json */ ` @@ -1077,9 +1168,12 @@ describe("bundler", () => { "/Users/user/project/node_modules/pkg/import.js": `console.log('FAILURE')`, "/Users/user/project/node_modules/pkg/default.js": `console.log('SUCCESS')`, }, + run: { + stdout: "SUCCESS", + }, }); - itBundled("packagejson/PackageJsonExportsEntryPointImportOverRequire", { - // GENERATED + itBundled("packagejson/ExportsEntryPointImportOverRequire", { + notImplemented: true, files: { "/node_modules/pkg/package.json": /* json */ ` { @@ -1097,9 +1191,11 @@ describe("bundler", () => { "/node_modules/pkg/main.js": `console.log('FAILURE')`, }, entryPoints: ["pkg"], + run: { + stdout: "SUCCESS", + }, }); - itBundled("packagejson/PackageJsonExportsEntryPointRequireOnly", { - // GENERATED + itBundled("packagejson/ExportsEntryPointRequireOnly", { files: { "/node_modules/pkg/package.json": /* json */ ` { @@ -1114,14 +1210,12 @@ describe("bundler", () => { "/node_modules/pkg/module.js": `console.log('FAILURE')`, "/node_modules/pkg/main.js": `console.log('FAILURE')`, }, - entryPoints: ["pkg"], - /* TODO FIX expectedScanLog: `ERROR: Could not resolve "pkg" - node_modules/pkg/package.json: NOTE: The path "." is not currently exported by package "pkg": - node_modules/pkg/package.json: NOTE: None of the conditions provided ("require") match any of the currently active conditions ("browser", "default", "import"): - `, */ + entryPointsRaw: ["pkg"], + bundleErrors: { + "<bun>": [`ModuleNotFound resolving "pkg" (entry point)`], + }, }); - itBundled("packagejson/PackageJsonExportsEntryPointModuleOverMain", { - // GENERATED + itBundled("packagejson/ExportsEntryPointModuleOverMain", { files: { "/node_modules/pkg/package.json": /* json */ ` { @@ -1132,10 +1226,14 @@ describe("bundler", () => { "/node_modules/pkg/module.js": `console.log('SUCCESS')`, "/node_modules/pkg/main.js": `console.log('FAILURE')`, }, - entryPoints: ["pkg"], + entryPointsRaw: ["pkg"], + outfile: "out.js", + run: { + file: "out.js", + stdout: "SUCCESS", + }, }); - itBundled("packagejson/PackageJsonExportsEntryPointMainOnly", { - // GENERATED + itBundled("packagejson/ExportsEntryPointMainOnly", { files: { "/node_modules/pkg/package.json": /* json */ ` { @@ -1144,10 +1242,14 @@ describe("bundler", () => { `, "/node_modules/pkg/main.js": `console.log('SUCCESS')`, }, - entryPoints: ["pkg"], + entryPointsRaw: ["pkg"], + outfile: "out.js", + run: { + file: "out.js", + stdout: "SUCCESS", + }, }); - itBundled("packagejson/PackageJsonExportsBrowser", { - // GENERATED + itBundled("packagejson/ExportsBrowser", { files: { "/Users/user/project/src/entry.js": `import 'pkg'`, "/Users/user/project/node_modules/pkg/package.json": /* json */ ` @@ -1162,10 +1264,14 @@ describe("bundler", () => { "/Users/user/project/node_modules/pkg/node.js": `console.log('FAILURE')`, "/Users/user/project/node_modules/pkg/browser.js": `console.log('SUCCESS')`, }, + platform: "browser", outfile: "/Users/user/project/out.js", + run: { + stdout: "SUCCESS", + }, }); - itBundled("packagejson/PackageJsonExportsNode", { - // GENERATED + itBundled("packagejson/ExportsNode", { + notImplemented: true, files: { "/Users/user/project/src/entry.js": `import 'pkg'`, "/Users/user/project/node_modules/pkg/package.json": /* json */ ` @@ -1180,10 +1286,13 @@ describe("bundler", () => { "/Users/user/project/node_modules/pkg/browser.js": `console.log('FAILURE')`, "/Users/user/project/node_modules/pkg/node.js": `console.log('SUCCESS')`, }, + platform: "node", outfile: "/Users/user/project/out.js", + run: { + stdout: "SUCCESS", + }, }); - itBundled("packagejson/PackageJsonExportsNeutral", { - // GENERATED + itBundled("packagejson/ExportsNeutral", { files: { "/Users/user/project/src/entry.js": `import 'pkg'`, "/Users/user/project/node_modules/pkg/package.json": /* json */ ` @@ -1200,9 +1309,12 @@ describe("bundler", () => { "/Users/user/project/node_modules/pkg/default.js": `console.log('SUCCESS')`, }, outfile: "/Users/user/project/out.js", + platform: "neutral", + run: { + stdout: "SUCCESS", + }, }); - itBundled("packagejson/PackageJsonExportsOrderIndependent", { - // GENERATED + itBundled("packagejson/ExportsOrderIndependent", { files: { "/Users/user/project/src/entry.js": /* js */ ` import 'pkg1/foo/bar.js' @@ -1229,9 +1341,11 @@ describe("bundler", () => { "/Users/user/project/node_modules/pkg2/1/bar.js": `console.log('SUCCESS')`, "/Users/user/project/node_modules/pkg2/2/foo/bar.js": `console.log('FAILURE')`, }, + run: { + stdout: "SUCCESS\nSUCCESS", + }, }); - itBundled("packagejson/PackageJsonExportsWildcard", { - // GENERATED + itBundled("packagejson/ExportsWildcard", { files: { "/Users/user/project/src/entry.js": /* js */ ` import 'pkg1/foo' @@ -1247,20 +1361,20 @@ describe("bundler", () => { "/Users/user/project/node_modules/pkg1/file.js": `console.log('SUCCESS')`, "/Users/user/project/node_modules/pkg1/file2.js": `console.log('SUCCESS')`, }, + run: { + stdout: "SUCCESS\nSUCCESS", + }, }); - itBundled("packagejson/PackageJsonExportsErrorMissingTrailingSlash", { - // GENERATED + itBundled("packagejson/ExportsErrorMissingTrailingSlash", { files: { "/Users/user/project/src/entry.js": `import 'pkg1/foo/bar'`, "/Users/user/project/node_modules/pkg1/package.json": `{ "exports": { "./foo/": "./test" } }`, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1/foo/bar" - Users/user/project/node_modules/pkg1/package.json: NOTE: The module specifier "./test" is invalid because it doesn't end in "/": - NOTE: You can mark the path "pkg1/foo/bar" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [`Could not resolve: "pkg1/foo/bar". Maybe you need to "bun install"?`], + }, }); - itBundled("packagejson/PackageJsonExportsCustomConditions", { - // GENERATED + itBundled("packagejson/ExportsCustomConditions", { files: { "/Users/user/project/src/entry.js": `import 'pkg1'`, "/Users/user/project/node_modules/pkg1/package.json": /* json */ ` @@ -1275,9 +1389,11 @@ describe("bundler", () => { "/Users/user/project/node_modules/pkg1/custom2.js": `console.log('SUCCESS')`, }, outfile: "/Users/user/project/out.js", + bundleErrors: { + "/Users/user/project/src/entry.js": [`Could not resolve: "pkg1". Maybe you need to "bun install"?`], + }, }); - itBundled("packagejson/PackageJsonExportsNotExactMissingExtension", { - // GENERATED + itBundled("packagejson/ExportsNotExactMissingExtension", { files: { "/Users/user/project/src/entry.js": `import 'pkg1/foo/bar'`, "/Users/user/project/node_modules/pkg1/package.json": /* json */ ` @@ -1289,9 +1405,11 @@ describe("bundler", () => { `, "/Users/user/project/node_modules/pkg1/dir/bar.js": `console.log('SUCCESS')`, }, + run: { + stdout: "SUCCESS", + }, }); - itBundled("packagejson/PackageJsonExportsNotExactMissingExtensionPattern", { - // GENERATED + itBundled("packagejson/ExportsNotExactMissingExtensionPattern", { files: { "/Users/user/project/src/entry.js": `import 'pkg1/foo/bar'`, "/Users/user/project/node_modules/pkg1/package.json": /* json */ ` @@ -1303,14 +1421,11 @@ describe("bundler", () => { `, "/Users/user/project/node_modules/pkg1/dir/bar.js": `console.log('SUCCESS')`, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1/foo/bar" - Users/user/project/node_modules/pkg1/package.json: NOTE: The module "./dir/bar" was not found on the file system: - Users/user/project/src/entry.js: NOTE: Import from "pkg1/foo/bar.js" to get the file "Users/user/project/node_modules/pkg1/dir/bar.js": - NOTE: You can mark the path "pkg1/foo/bar" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [`Could not resolve: "pkg1/foo/bar". Maybe you need to "bun install"?`], + }, }); - itBundled("packagejson/PackageJsonExportsExactMissingExtension", { - // GENERATED + itBundled("packagejson/ExportsExactMissingExtension", { files: { "/Users/user/project/src/entry.js": `import 'pkg1/foo/bar'`, "/Users/user/project/node_modules/pkg1/package.json": /* json */ ` @@ -1322,12 +1437,11 @@ describe("bundler", () => { `, "/Users/user/project/node_modules/pkg1/dir/bar.js": `console.log('SUCCESS')`, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1/foo/bar" - Users/user/project/node_modules/pkg1/package.json: NOTE: The module "./dir/bar" was not found on the file system: - NOTE: You can mark the path "pkg1/foo/bar" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [`Could not resolve: "pkg1/foo/bar". Maybe you need to "bun install"?`], + }, }); - itBundled("packagejson/PackageJsonExportsNoConditionsMatch", { + itBundled("packagejson/ExportsNoConditionsMatch", { // GENERATED files: { "/Users/user/project/src/entry.js": /* js */ ` @@ -1348,20 +1462,15 @@ describe("bundler", () => { `, "/Users/user/project/node_modules/pkg1/foo.js": `console.log('FAILURE')`, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1" - Users/user/project/node_modules/pkg1/package.json: NOTE: The path "." is not currently exported by package "pkg1": - Users/user/project/node_modules/pkg1/package.json: NOTE: None of the conditions provided ("what") match any of the currently active conditions ("browser", "default", "import"): - Users/user/project/node_modules/pkg1/package.json: NOTE: Consider enabling the "what" condition if this package expects it to be enabled. You can use 'Conditions: []string{"what"}' to do that: - NOTE: You can mark the path "pkg1" as external to exclude it from the bundle, which will remove this error. - Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1/foo.js" - Users/user/project/node_modules/pkg1/package.json: NOTE: The path "./foo.js" is not currently exported by package "pkg1": - Users/user/project/node_modules/pkg1/package.json: NOTE: None of the conditions provided ("what") match any of the currently active conditions ("browser", "default", "import"): - Users/user/project/node_modules/pkg1/package.json: NOTE: Consider enabling the "what" condition if this package expects it to be enabled. You can use 'Conditions: []string{"what"}' to do that: - NOTE: You can mark the path "pkg1/foo.js" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [ + `Could not resolve: "pkg1". Maybe you need to "bun install"?`, + `Could not resolve: "pkg1/foo.js". Maybe you need to "bun install"?`, + ], + }, }); - itBundled("packagejson/PackageJsonExportsMustUseRequire", { - // GENERATED + itBundled("packagejson/ExportsMustUseRequire", { + notImplemented: true, files: { "/Users/user/project/src/entry.js": /* js */ ` import 'pkg1' @@ -1381,20 +1490,8 @@ describe("bundler", () => { `, "/Users/user/project/node_modules/pkg1/foo.js": `console.log('FAILURE')`, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1" - Users/user/project/node_modules/pkg1/package.json: NOTE: The path "." is not currently exported by package "pkg1": - Users/user/project/node_modules/pkg1/package.json: NOTE: None of the conditions provided ("require") match any of the currently active conditions ("browser", "default", "import"): - Users/user/project/src/entry.js: NOTE: Consider using a "require()" call to import this file, which will work because the "require" condition is supported by this package: - NOTE: You can mark the path "pkg1" as external to exclude it from the bundle, which will remove this error. - Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1/foo.js" - Users/user/project/node_modules/pkg1/package.json: NOTE: The path "./foo.js" is not currently exported by package "pkg1": - Users/user/project/node_modules/pkg1/package.json: NOTE: None of the conditions provided ("require") match any of the currently active conditions ("browser", "default", "import"): - Users/user/project/src/entry.js: NOTE: Consider using a "require()" call to import this file, which will work because the "require" condition is supported by this package: - NOTE: You can mark the path "pkg1/foo.js" as external to exclude it from the bundle, which will remove this error. - `, */ }); - itBundled("packagejson/PackageJsonExportsMustUseImport", { - // GENERATED + itBundled("packagejson/ExportsMustUseImport", { files: { "/Users/user/project/src/entry.js": /* js */ ` require('pkg1') @@ -1414,20 +1511,14 @@ describe("bundler", () => { `, "/Users/user/project/node_modules/pkg1/foo.js": `console.log('FAILURE')`, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1" - Users/user/project/node_modules/pkg1/package.json: NOTE: The path "." is not currently exported by package "pkg1": - Users/user/project/node_modules/pkg1/package.json: NOTE: None of the conditions provided ("import") match any of the currently active conditions ("browser", "default", "require"): - Users/user/project/src/entry.js: NOTE: Consider using an "import" statement to import this file, which will work because the "import" condition is supported by this package: - NOTE: You can mark the path "pkg1" as external to exclude it from the bundle, which will remove this error. You can also surround this "require" call with a try/catch block to handle this failure at run-time instead of bundle-time. - Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1/foo.js" - Users/user/project/node_modules/pkg1/package.json: NOTE: The path "./foo.js" is not currently exported by package "pkg1": - Users/user/project/node_modules/pkg1/package.json: NOTE: None of the conditions provided ("import") match any of the currently active conditions ("browser", "default", "require"): - Users/user/project/src/entry.js: NOTE: Consider using an "import" statement to import this file, which will work because the "import" condition is supported by this package: - NOTE: You can mark the path "pkg1/foo.js" as external to exclude it from the bundle, which will remove this error. You can also surround this "require" call with a try/catch block to handle this failure at run-time instead of bundle-time. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [ + `Could not resolve: "pkg1". Maybe you need to "bun install"?`, + `Could not resolve: "pkg1/foo.js". Maybe you need to "bun install"?`, + ], + }, }); - itBundled("packagejson/PackageJsonExportsReverseLookup", { - // GENERATED + itBundled("packagejson/ExportsReverseLookup", { files: { "/Users/user/project/src/entry.js": /* js */ ` require('pkg/path/to/real/file') @@ -1448,20 +1539,14 @@ describe("bundler", () => { "/Users/user/project/node_modules/pkg/path/to/real/file.js": ``, "/Users/user/project/node_modules/pkg/path/to/other/file.js": ``, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "pkg/path/to/real/file" - Users/user/project/node_modules/pkg/package.json: NOTE: The path "./path/to/real/file" is not exported by package "pkg": - Users/user/project/node_modules/pkg/package.json: NOTE: The file "./path/to/real/file.js" is exported at path "./lib/teal/file": - Users/user/project/src/entry.js: NOTE: Import from "pkg/lib/teal/file" to get the file "Users/user/project/node_modules/pkg/path/to/real/file.js": - NOTE: You can mark the path "pkg/path/to/real/file" as external to exclude it from the bundle, which will remove this error. You can also surround this "require" call with a try/catch block to handle this failure at run-time instead of bundle-time. - Users/user/project/src/entry.js: ERROR: Could not resolve "pkg/path/to/other/file" - Users/user/project/node_modules/pkg/package.json: NOTE: The path "./path/to/other/file" is not exported by package "pkg": - Users/user/project/node_modules/pkg/package.json: NOTE: The file "./path/to/other/file.js" is exported at path "./extra/other/file.js": - Users/user/project/src/entry.js: NOTE: Import from "pkg/extra/other/file.js" to get the file "Users/user/project/node_modules/pkg/path/to/other/file.js": - NOTE: You can mark the path "pkg/path/to/other/file" as external to exclude it from the bundle, which will remove this error. You can also surround this "require" call with a try/catch block to handle this failure at run-time instead of bundle-time. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [ + `Could not resolve: "pkg/path/to/real/file". Maybe you need to "bun install"?`, + `Could not resolve: "pkg/path/to/other/file". Maybe you need to "bun install"?`, + ], + }, }); - itBundled("packagejson/PackageJsonExportsPatternTrailers", { - // GENERATED + itBundled("packagejson/ExportsPatternTrailers", { files: { "/Users/user/project/src/entry.js": /* js */ ` import 'pkg/path/foo.js/bar.js' @@ -1487,9 +1572,11 @@ describe("bundler", () => { "/Users/user/project/node_modules/pkg2/public/abc.js": `console.log('abc')`, "/Users/user/project/node_modules/pkg2/public/xyz.js": `console.log('xyz')`, }, + run: { + stdout: `works\nabc\nxyz`, + }, }); - itBundled("packagejson/PackageJsonExportsAlternatives", { - // GENERATED + itBundled("packagejson/ExportsAlternatives", { files: { "/Users/user/project/src/entry.js": /* js */ ` import redApple from 'pkg/apples/red.js' @@ -1511,16 +1598,14 @@ describe("bundler", () => { "/Users/user/project/node_modules/pkg/good-books/green-book.js": `export default '📗'`, "/Users/user/project/node_modules/pkg/bad-books/red-book.js": `export default '📕'`, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "pkg/apples/red.js" - Users/user/project/node_modules/pkg/package.json: NOTE: The module "./good-apples/red.js" was not found on the file system: - NOTE: You can mark the path "pkg/apples/red.js" as external to exclude it from the bundle, which will remove this error. - Users/user/project/src/entry.js: ERROR: Could not resolve "pkg/books/red" - Users/user/project/node_modules/pkg/package.json: NOTE: The module "./good-books/red-book.js" was not found on the file system: - NOTE: You can mark the path "pkg/books/red" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [ + `Could not resolve: "pkg/apples/red.js". Maybe you need to "bun install"?`, + `Could not resolve: "pkg/books/red". Maybe you need to "bun install"?`, + ], + }, }); - itBundled("packagejson/PackageJsonImports", { - // GENERATED + itBundled("packagejson/Imports", { files: { "/Users/user/project/src/foo/entry.js": /* js */ ` import '#top-level' @@ -1543,9 +1628,11 @@ describe("bundler", () => { "/Users/user/project/src/some-star/c.js": `console.log('c.js')`, "/Users/user/project/src/some-slash/d.js": `console.log('d.js')`, }, + run: { + stdout: `a.js\nb.js\nc.js\nd.js`, + }, }); - itBundled("packagejson/PackageJsonImportsRemapToOtherPackage", { - // GENERATED + itBundled("packagejson/ImportsRemapToOtherPackage", { files: { "/Users/user/project/src/entry.js": /* js */ ` import '#top-level' @@ -1568,9 +1655,11 @@ describe("bundler", () => { "/Users/user/project/src/node_modules/pkg/some-star/c.js": `console.log('c.js')`, "/Users/user/project/src/node_modules/pkg/some-slash/d.js": `console.log('d.js')`, }, + run: { + stdout: `a.js\nb.js\nc.js\nd.js`, + }, }); - itBundled("packagejson/PackageJsonImportsErrorMissingRemappedPackage", { - // GENERATED + itBundled("packagejson/ImportsErrorMissingRemappedPackage", { files: { "/Users/user/project/src/entry.js": `import '#foo'`, "/Users/user/project/src/package.json": /* json */ ` @@ -1581,13 +1670,11 @@ describe("bundler", () => { } `, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "#foo" - Users/user/project/src/package.json: NOTE: The remapped path "bar" could not be resolved: - NOTE: You can mark the path "#foo" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [`Could not resolve: "#foo". Maybe you need to "bun install"?`], + }, }); - itBundled("packagejson/PackageJsonImportsInvalidPackageConfiguration", { - // GENERATED + itBundled("packagejson/ImportsInvalidPackageConfiguration", { files: { "/Users/user/project/src/entry.js": `import '#foo'`, "/Users/user/project/src/package.json": /* json */ ` @@ -1596,14 +1683,11 @@ describe("bundler", () => { } `, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "#foo" - Users/user/project/src/package.json: NOTE: The package configuration has an invalid value here: - NOTE: You can mark the path "#foo" as external to exclude it from the bundle, which will remove this error. - Users/user/project/src/package.json: WARNING: The value for "imports" must be an object - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [`Could not resolve: "#foo". Maybe you need to "bun install"?`], + }, }); - itBundled("packagejson/PackageJsonImportsErrorEqualsHash", { - // GENERATED + itBundled("packagejson/ImportsErrorEqualsHash", { files: { "/Users/user/project/src/entry.js": `import '#'`, "/Users/user/project/src/package.json": /* json */ ` @@ -1612,13 +1696,11 @@ describe("bundler", () => { } `, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "#" - Users/user/project/src/package.json: NOTE: This "imports" map was ignored because the module specifier "#" is invalid: - NOTE: You can mark the path "#" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [`Could not resolve: "#". Maybe you need to "bun install"?`], + }, }); - itBundled("packagejson/PackageJsonImportsErrorStartsWithHashSlash", { - // GENERATED + itBundled("packagejson/ImportsErrorStartsWithHashSlash", { files: { "/Users/user/project/src/entry.js": `import '#/foo'`, "/Users/user/project/src/package.json": /* json */ ` @@ -1627,13 +1709,11 @@ describe("bundler", () => { } `, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "#/foo" - Users/user/project/src/package.json: NOTE: This "imports" map was ignored because the module specifier "#/foo" is invalid: - NOTE: You can mark the path "#/foo" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [`Could not resolve: "#/foo". Maybe you need to "bun install"?`], + }, }); - itBundled("packagejson/PackageJsonMainFieldsErrorMessageDefault", { - // GENERATED + itBundled("packagejson/MainFieldsErrorMessageDefault", { files: { "/Users/user/project/src/entry.js": `import 'foo'`, "/Users/user/project/node_modules/foo/package.json": /* json */ ` @@ -1642,12 +1722,11 @@ describe("bundler", () => { } `, }, - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "foo" - NOTE: You can mark the path "foo" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [`Could not resolve: "foo". Maybe you need to "bun install"?`], + }, }); - itBundled("packagejson/PackageJsonMainFieldsErrorMessageNotIncluded", { - // GENERATED + itBundled("packagejson/MainFieldsErrorMessageNotIncluded", { files: { "/Users/user/project/src/entry.js": `import 'foo'`, "/Users/user/project/node_modules/foo/package.json": /* json */ ` @@ -1657,13 +1736,11 @@ describe("bundler", () => { `, }, outfile: "/Users/user/project/out.js", - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "foo" - Users/user/project/node_modules/foo/package.json: NOTE: The "main" field here was ignored because the list of main fields to use is currently set to ["some", "fields"]. - NOTE: You can mark the path "foo" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/entry.js": [`Could not resolve: "foo". Maybe you need to "bun install"?`], + }, }); - itBundled("packagejson/PackageJsonMainFieldsErrorMessageEmpty", { - // GENERATED + itBundled("packagejson/MainFieldsErrorMessageEmpty", { files: { "/Users/user/project/src/entry.js": `import 'foo'`, "/Users/user/project/node_modules/foo/package.json": /* json */ ` @@ -1672,14 +1749,13 @@ describe("bundler", () => { } `, }, + bundleErrors: { + "/Users/user/project/src/entry.js": [`Could not resolve: "foo". Maybe you need to "bun install"?`], + }, outfile: "/Users/user/project/out.js", - /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "foo" - Users/user/project/node_modules/foo/package.json: NOTE: The "main" field here was ignored because the list of main fields to use is currently set to []. - NOTE: You can mark the path "foo" as external to exclude it from the bundle, which will remove this error. - `, */ }); - itBundled("packagejson/PackageJsonTypeShouldBeTypes", { - // GENERATED + itBundled("packagejson/TypeShouldBeTypes", { + notImplemented: true, files: { "/Users/user/project/src/index.js": ``, "/Users/user/project/package.json": /* json */ ` @@ -1690,12 +1766,14 @@ describe("bundler", () => { `, }, outfile: "/Users/user/project/out.js", - /* TODO FIX expectedScanLog: `Users/user/project/package.json: WARNING: "./src/index.d.ts" is not a valid value for the "type" field - Users/user/project/package.json: NOTE: TypeScript type declarations use the "types" field, not the "type" field: - `, */ + bundleWarnings: { + "/Users/user/project/package.json": [ + `"./src/index.d.ts" is not a valid value for "type" field (must be either "commonjs" or "module")`, + ], + }, }); - itBundled("packagejson/PackageJsonImportSelfUsingRequire", { - // GENERATED + itBundled("packagejson/ImportSelfUsingRequire", { + notImplemented: true, files: { "/Users/user/project/src/index.js": /* js */ ` module.exports = 'index' @@ -1704,8 +1782,8 @@ describe("bundler", () => { require("xyz/bar"), ) `, - "/Users/user/project/src/foo-import.js": `export default 'foo'`, - "/Users/user/project/src/foo-require.js": `module.exports = 'foo'`, + "/Users/user/project/src/foo-import.js": `export default 'foo-import'`, + "/Users/user/project/src/foo-require.js": `module.exports = 'foo-require'`, "/Users/user/project/package.json": /* json */ ` { "name": "xyz", @@ -1720,9 +1798,12 @@ describe("bundler", () => { `, }, outfile: "/Users/user/project/out.js", + run: { + stdout: `index foo-require`, + }, }); - itBundled("packagejson/PackageJsonImportSelfUsingImport", { - // GENERATED + itBundled("packagejson/ImportSelfUsingImport", { + notImplemented: true, files: { "/Users/user/project/src/index.js": /* js */ ` import xyz from "xyz" @@ -1730,8 +1811,8 @@ describe("bundler", () => { export default 'index' console.log(xyz, foo) `, - "/Users/user/project/src/foo-import.js": `export default 'foo'`, - "/Users/user/project/src/foo-require.js": `module.exports = 'foo'`, + "/Users/user/project/src/foo-import.js": `export default 'foo-import'`, + "/Users/user/project/src/foo-require.js": `module.exports = 'foo-require'`, "/Users/user/project/package.json": /* json */ ` { "name": "xyz", @@ -1746,9 +1827,12 @@ describe("bundler", () => { `, }, outfile: "/Users/user/project/out.js", + run: { + stdout: `index foo-import`, + }, }); - itBundled("packagejson/PackageJsonImportSelfUsingRequireScoped", { - // GENERATED + itBundled("packagejson/ImportSelfUsingRequireScoped", { + notImplemented: true, files: { "/Users/user/project/src/index.js": /* js */ ` module.exports = 'index' @@ -1757,8 +1841,8 @@ describe("bundler", () => { require("@some-scope/xyz/bar"), ) `, - "/Users/user/project/src/foo-import.js": `export default 'foo'`, - "/Users/user/project/src/foo-require.js": `module.exports = 'foo'`, + "/Users/user/project/src/foo-import.js": `export default 'foo-import'`, + "/Users/user/project/src/foo-require.js": `module.exports = 'foo-require'`, "/Users/user/project/package.json": /* json */ ` { "name": "@some-scope/xyz", @@ -1773,9 +1857,12 @@ describe("bundler", () => { `, }, outfile: "/Users/user/project/out.js", + run: { + stdout: `index foo-require`, + }, }); - itBundled("packagejson/PackageJsonImportSelfUsingImportScoped", { - // GENERATED + itBundled("packagejson/ImportSelfUsingImportScoped", { + notImplemented: true, files: { "/Users/user/project/src/index.js": /* js */ ` import xyz from "@some-scope/xyz" @@ -1783,8 +1870,8 @@ describe("bundler", () => { export default 'index' console.log(xyz, foo) `, - "/Users/user/project/src/foo-import.js": `export default 'foo'`, - "/Users/user/project/src/foo-require.js": `module.exports = 'foo'`, + "/Users/user/project/src/foo-import.js": `export default 'foo-import'`, + "/Users/user/project/src/foo-require.js": `module.exports = 'foo-require'`, "/Users/user/project/package.json": /* json */ ` { "name": "@some-scope/xyz", @@ -1799,9 +1886,11 @@ describe("bundler", () => { `, }, outfile: "/Users/user/project/out.js", + run: { + stdout: `index foo-import`, + }, }); - itBundled("packagejson/PackageJsonImportSelfUsingRequireFailure", { - // GENERATED + itBundled("packagejson/ImportSelfUsingRequireFailure", { files: { "/Users/user/project/src/index.js": `require("xyz/src/foo.js")`, "/Users/user/project/src/foo.js": `module.exports = 'foo'`, @@ -1816,15 +1905,11 @@ describe("bundler", () => { `, }, outfile: "/Users/user/project/out.js", - /* TODO FIX expectedScanLog: `Users/user/project/src/index.js: ERROR: Could not resolve "xyz/src/foo.js" - Users/user/project/package.json: NOTE: The path "./src/foo.js" is not exported by package "xyz": - Users/user/project/package.json: NOTE: The file "./src/foo.js" is exported at path "./bar": - Users/user/project/src/index.js: NOTE: Import from "xyz/bar" to get the file "Users/user/project/src/foo.js": - NOTE: You can mark the path "xyz/src/foo.js" as external to exclude it from the bundle, which will remove this error. You can also surround this "require" call with a try/catch block to handle this failure at run-time instead of bundle-time. - `, */ + bundleErrors: { + "/Users/user/project/src/index.js": [`Could not resolve: "xyz/src/foo.js". Maybe you need to "bun install"?`], + }, }); - itBundled("packagejson/PackageJsonImportSelfUsingImportFailure", { - // GENERATED + itBundled("packagejson/ImportSelfUsingImportFailure", { files: { "/Users/user/project/src/index.js": `import "xyz/src/foo.js"`, "/Users/user/project/src/foo.js": `export default 'foo'`, @@ -1839,26 +1924,17 @@ describe("bundler", () => { `, }, outfile: "/Users/user/project/out.js", - /* TODO FIX expectedScanLog: `Users/user/project/src/index.js: ERROR: Could not resolve "xyz/src/foo.js" - Users/user/project/package.json: NOTE: The path "./src/foo.js" is not exported by package "xyz": - Users/user/project/package.json: NOTE: The file "./src/foo.js" is exported at path "./bar": - Users/user/project/src/index.js: NOTE: Import from "xyz/bar" to get the file "Users/user/project/src/foo.js": - NOTE: You can mark the path "xyz/src/foo.js" as external to exclude it from the bundle, which will remove this error. - `, */ + bundleErrors: { + "/Users/user/project/src/index.js": [`Could not resolve: "xyz/src/foo.js". Maybe you need to "bun install"?`], + }, }); itBundled("packagejson/CommonJSVariableInESMTypeModule", { - // GENERATED files: { "/entry.js": `module.exports = null`, "/package.json": `{ "type": "module" }`, }, - /* TODO FIX expectedScanLog: `entry.js: WARNING: The CommonJS "module" variable is treated as a global variable in an ECMAScript module and may not work as expected - package.json: NOTE: This file is considered to be an ECMAScript module because the enclosing "package.json" file sets the type of this file to "module": - NOTE: Node's package format requires that CommonJS files in a "type": "module" package use the ".cjs" file extension. - `, */ }); - itBundled("packagejson/PackageJsonNodePathsESBuildIssue2752", { - // GENERATED + itBundled("packagejson/NodePathsESBuildIssue2752", { files: { "/src/entry.js": /* js */ ` import "pkg1" @@ -1875,5 +1951,6 @@ describe("bundler", () => { "/tmp/pkg/@scope/pkg4/package.json": `{ "exports": { ".": { "import": "./bat.js" } } }`, "/tmp/pkg/@scope/pkg4/bat.js": `console.log('pkg4')`, }, + nodePaths: ["/usr/lib/pkg", "/lib/pkg", "/var/lib/pkg", "/tmp/pkg"], }); }); diff --git a/test/bundler/esbuild/splitting.test.ts b/test/bundler/esbuild/splitting.test.ts index 1dc2c3d11..361b51ef6 100644 --- a/test/bundler/esbuild/splitting.test.ts +++ b/test/bundler/esbuild/splitting.test.ts @@ -1,4 +1,6 @@ -import { RUN_UNCHECKED_TESTS, itBundled, testForFile } from "../expectBundled"; +import assert from "assert"; +import { readdirSync } from "fs"; +import { itBundled, testForFile } from "../expectBundled"; var { describe, test, expect } = testForFile(import.meta.path); // Tests ported from: @@ -7,7 +9,7 @@ var { describe, test, expect } = testForFile(import.meta.path); // For debug, all files are written to $TEMP/bun-bundle-tests/splitting describe("bundler", () => { - itBundled("splitting/SplittingSharedES6IntoES6", { + itBundled("splitting/SharedES6IntoES6", { files: { "/a.js": /* js */ ` import {foo} from "./shared.js" @@ -21,7 +23,6 @@ describe("bundler", () => { }, entryPoints: ["/a.js", "/b.js"], splitting: true, - format: "esm", run: [ { file: "/out/a.js", stdout: "123" }, { file: "/out/b.js", stdout: "123" }, @@ -31,9 +32,7 @@ describe("bundler", () => { "/out/b.js": "123", }, }); - if (!RUN_UNCHECKED_TESTS) return; - itBundled("splitting/SplittingSharedCommonJSIntoES6", { - // GENERATED + itBundled("splitting/SharedCommonJSIntoES6", { files: { "/a.js": /* js */ ` const {foo} = require("./shared.js") @@ -47,28 +46,46 @@ describe("bundler", () => { }, entryPoints: ["/a.js", "/b.js"], splitting: true, - format: "esm", + run: [ + { file: "/out/a.js", stdout: "123" }, + { file: "/out/b.js", stdout: "123" }, + ], + assertNotPresent: { + "/out/a.js": "123", + "/out/b.js": "123", + }, }); - itBundled("splitting/SplittingDynamicES6IntoES6", { - // GENERATED + itBundled("splitting/DynamicES6IntoES6", { files: { "/entry.js": `import("./foo.js").then(({bar}) => console.log(bar))`, "/foo.js": `export let bar = 123`, }, splitting: true, - format: "esm", + outdir: "/out", + assertNotPresent: { + "/out/entry.js": "123", + }, + run: { + file: "/out/entry.js", + stdout: "123", + }, }); - itBundled("splitting/SplittingDynamicCommonJSIntoES6", { - // GENERATED + itBundled("splitting/DynamicCommonJSIntoES6", { files: { "/entry.js": `import("./foo.js").then(({default: {bar}}) => console.log(bar))`, "/foo.js": `exports.bar = 123`, }, splitting: true, - format: "esm", + outdir: "/out", + assertNotPresent: { + "/out/entry.js": "123", + }, + run: { + file: "/out/entry.js", + stdout: "123", + }, }); - itBundled("splitting/SplittingDynamicAndNotDynamicES6IntoES6", { - // GENERATED + itBundled("splitting/DynamicAndNotDynamicES6IntoES6", { files: { "/entry.js": /* js */ ` import {bar as a} from "./foo.js" @@ -77,10 +94,10 @@ describe("bundler", () => { "/foo.js": `export let bar = 123`, }, splitting: true, - format: "esm", + outdir: "/out", }); - itBundled("splitting/SplittingDynamicAndNotDynamicCommonJSIntoES6", { - // GENERATED + itBundled("splitting/DynamicAndNotDynamicCommonJSIntoES6", { + skipOnEsbuild: true, files: { "/entry.js": /* js */ ` import {bar as a} from "./foo.js" @@ -88,11 +105,14 @@ describe("bundler", () => { `, "/foo.js": `exports.bar = 123`, }, + outdir: "/out", splitting: true, - format: "esm", + run: { + file: "/out/entry.js", + stdout: "123 123", + }, }); - itBundled("splitting/SplittingAssignToLocal", { - // GENERATED + itBundled("splitting/AssignToLocal", { files: { "/a.js": /* js */ ` import {foo, setFoo} from "./shared.js" @@ -104,7 +124,7 @@ describe("bundler", () => { console.log(foo) `, "/shared.js": /* js */ ` - export let foo + export let foo = 456 export function setFoo(value) { foo = value } @@ -112,10 +132,24 @@ describe("bundler", () => { }, entryPoints: ["/a.js", "/b.js"], splitting: true, - format: "esm", + runtimeFiles: { + "/test1.js": /* js */ ` + await import('./out/a.js') + await import('./out/b.js') + `, + "/test2.js": /* js */ ` + await import('./out/b.js') + await import('./out/a.js') + `, + }, + run: [ + { file: "/out/a.js", stdout: "123" }, + { file: "/out/b.js", stdout: "456" }, + { file: "/test1.js", stdout: "123\n123" }, + { file: "/test2.js", stdout: "456\n123" }, + ], }); - itBundled("splitting/SplittingSideEffectsWithoutDependencies", { - // GENERATED + itBundled("splitting/SideEffectsWithoutDependencies", { files: { "/a.js": /* js */ ` import {a} from "./shared.js" @@ -133,10 +167,24 @@ describe("bundler", () => { }, entryPoints: ["/a.js", "/b.js"], splitting: true, - format: "esm", + runtimeFiles: { + "/test1.js": /* js */ ` + await import('./out/a.js') + await import('./out/b.js') + `, + "/test2.js": /* js */ ` + await import('./out/b.js') + await import('./out/a.js') + `, + }, + run: [ + { file: "/out/a.js", stdout: "side effect\n1" }, + { file: "/out/b.js", stdout: "side effect\n2" }, + { file: "/test1.js", stdout: "side effect\n1\n2" }, + { file: "/test2.js", stdout: "side effect\n2\n1" }, + ], }); - itBundled("splitting/SplittingNestedDirectories", { - // GENERATED + itBundled("splitting/NestedDirectories", { files: { "/Users/user/project/src/pages/pageA/page.js": /* js */ ` import x from "../shared.js" @@ -149,11 +197,15 @@ describe("bundler", () => { "/Users/user/project/src/pages/shared.js": `export default 123`, }, entryPoints: ["/Users/user/project/src/pages/pageA/page.js", "/Users/user/project/src/pages/pageB/page.js"], + outputPaths: ["/out/pageA/page.js", "/out/pageB/page.js"], splitting: true, - format: "esm", + + run: [ + { file: "/out/pageA/page.js", stdout: "123" }, + { file: "/out/pageB/page.js", stdout: "-123" }, + ], }); - itBundled("splitting/SplittingCircularReferenceESBuildIssue251", { - // GENERATED + itBundled("splitting/CircularReferenceESBuildIssue251", { files: { "/a.js": /* js */ ` export * from './b.js'; @@ -162,22 +214,37 @@ describe("bundler", () => { "/b.js": /* js */ ` export * from './a.js'; export var q = 6; + + export function foo() { + q = 7; + } `, }, entryPoints: ["/a.js", "/b.js"], splitting: true, - format: "esm", + + runtimeFiles: { + "/test.js": /* js */ ` + import { p, q, foo } from './out/a.js'; + console.log(p, q) + import { p as p2, q as q2, foo as foo2 } from './out/b.js'; + console.log(p2, q2) + console.log(foo === foo2) + foo(); + console.log(q, q2) + `, + }, + run: [{ file: "/test.js", stdout: "5 6\n5 6\ntrue\n7 7" }], }); - itBundled("splitting/SplittingMissingLazyExport", { - // GENERATED + itBundled("splitting/MissingLazyExport", { files: { "/a.js": /* js */ ` import {foo} from './common.js' - console.log(foo()) + console.log(JSON.stringify(foo())) `, "/b.js": /* js */ ` import {bar} from './common.js' - console.log(bar()) + console.log(JSON.stringify(bar())) `, "/common.js": /* js */ ` import * as ns from './empty.js' @@ -191,49 +258,75 @@ describe("bundler", () => { }, entryPoints: ["/a.js", "/b.js"], splitting: true, - format: "esm", - /* TODO FIX expectedCompileLog: `common.js: WARNING: Import "missing" will always be undefined because the file "empty.js" has no exports - `, */ + run: [ + { file: "/out/a.js", stdout: "[{},null]" }, + { file: "/out/b.js", stdout: "[null]" }, + ], + bundleWarnings: { + "/empty.js": [`Import "missing" will always be undefined because the file "empty.js" has no exports`], + }, }); - itBundled("splitting/SplittingReExportESBuildIssue273", { - // GENERATED + itBundled("splitting/ReExportESBuildIssue273", { files: { - "/a.js": `export const a = 1`, + "/a.js": `export const a = { value: 1 }`, "/b.js": `export { a } from './a'`, }, entryPoints: ["/a.js", "/b.js"], splitting: true, - format: "esm", + runtimeFiles: { + "/test.js": /* js */ ` + import { a } from './out/a.js'; + import { a as a2 } from './out/b.js'; + console.log(a === a2, a.value, a2.value) + `, + }, + run: [{ file: "/test.js", stdout: "true 1 1" }], }); - itBundled("splitting/SplittingDynamicImportESBuildIssue272", { - // GENERATED + itBundled("splitting/DynamicImportESBuildIssue272", { files: { "/a.js": `import('./b')`, - "/b.js": `export default 1`, + "/b.js": `export default 1; console.log('imported')`, }, entryPoints: ["/a.js", "/b.js"], splitting: true, - format: "esm", + + run: [{ file: "/out/a.js", stdout: "imported" }], + assertNotPresent: { + "/out/a.js": "imported", + }, }); - itBundled("splitting/SplittingDynamicImportOutsideSourceTreeESBuildIssue264", { - // GENERATED + itBundled("splitting/DynamicImportOutsideSourceTreeESBuildIssue264", { files: { "/Users/user/project/src/entry1.js": `import('package')`, "/Users/user/project/src/entry2.js": `import('package')`, "/Users/user/project/node_modules/package/index.js": `console.log('imported')`, }, + runtimeFiles: { + "/both.js": /* js */ ` + import('./out/entry1.js'); + import('./out/entry2.js'); + `, + }, entryPoints: ["/Users/user/project/src/entry1.js", "/Users/user/project/src/entry2.js"], splitting: true, - format: "esm", + + run: [ + { file: "/out/entry1.js", stdout: "imported" }, + { file: "/out/entry2.js", stdout: "imported" }, + { file: "/both.js", stdout: "imported" }, + ], }); - itBundled("splitting/SplittingCrossChunkAssignmentDependencies", { - // GENERATED + itBundled("splitting/CrossChunkAssignmentDependencies", { files: { "/a.js": /* js */ ` import {setValue} from './shared' setValue(123) `, - "/b.js": `import './shared'`, + "/b.js": `import './shared'; console.log('b')`, + "/c.js": /* js */ ` + import * as shared from './shared' + globalThis.shared = shared; + `, "/shared.js": /* js */ ` var observer; var value; @@ -244,59 +337,136 @@ describe("bundler", () => { return value; } export function setValue(next) { + console.log('setValue', next) value = next; if (observer) observer(); } - sideEffects(getValue); + console.log("side effects!", getValue); `, }, - entryPoints: ["/a.js", "/b.js"], + entryPoints: ["/a.js", "/b.js", "/c.js"], splitting: true, - format: "esm", + runtimeFiles: { + "/test.js": /* js */ ` + import './out/c.js'; + const { getValue, setObserver } = globalThis.shared; + function observer() { + console.log('observer', getValue()); + } + setObserver(observer); + import('./out/a.js'); + import('./out/b.js'); + `, + }, + run: [ + { file: "/out/a.js", stdout: "side effects! [Function]\nsetValue 123" }, + { file: "/out/b.js", stdout: "side effects! [Function]\nb" }, + { file: "/test.js", stdout: "side effects! [Function]\nsetValue 123\nobserver 123\nb" }, + ], }); - itBundled("splitting/SplittingCrossChunkAssignmentDependenciesRecursive", { - // GENERATED + itBundled("splitting/CrossChunkAssignmentDependenciesRecursive", { files: { "/a.js": /* js */ ` import { setX } from './x' - setX() + globalThis.a = { setX }; `, "/b.js": /* js */ ` import { setZ } from './z' - setZ() + globalThis.b = { setZ }; `, "/c.js": /* js */ ` import { setX2 } from './x' import { setY2 } from './y' import { setZ2 } from './z' - setX2(); - setY2(); - setZ2(); + globalThis.c = { setX2, setY2, setZ2 }; `, "/x.js": /* js */ ` let _x export function setX(v) { _x = v } export function setX2(v) { _x = v } + globalThis.x = { setX, setX2 }; `, "/y.js": /* js */ ` import { setX } from './x' let _y export function setY(v) { _y = v } export function setY2(v) { setX(v); _y = v } + globalThis.y = { setY, setY2 }; `, "/z.js": /* js */ ` import { setY } from './y' let _z export function setZ(v) { _z = v } export function setZ2(v) { setY(v); _z = v } + globalThis.z = { setZ, setZ2, setY }; `, }, entryPoints: ["/a.js", "/b.js", "/c.js"], splitting: true, - format: "esm", + + runtimeFiles: { + "/test_all.js": /* js */ ` + import './out/a.js'; + import './out/b.js'; + import './out/c.js'; + try { + a; b; c; x; y; z; // throw if not defined + } catch (error) { + throw new Error('chunks were not emitted right.') + } + import assert from 'assert'; + assert(a.setX === x.setX, 'a.setX'); + assert(b.setZ === z.setZ, 'b.setZ'); + assert(c.setX2 === x.setX2, 'c.setX2'); + assert(c.setY2 === y.setY2, 'c.setY2'); + assert(c.setZ2 === z.setZ2, 'c.setZ2'); + assert(z.setY === y.setY, 'z.setY'); + `, + "/test_a_only.js": /* js */ ` + import './out/a.js'; + try { + a; x; // throw if not defined + } catch (error) { + throw new Error('chunks were not emitted right.') + } + import assert from 'assert'; + assert(a.setX === x.setX, 'a.setX'); + assert(globalThis.b === undefined, 'b should not be loaded'); + assert(globalThis.c === undefined, 'c should not be loaded'); + assert(globalThis.y === undefined, 'y should not be loaded'); + assert(globalThis.z === undefined, 'z should not be loaded'); + `, + "/test_b_only.js": /* js */ ` + import './out/b.js'; + try { + b; x; y; z; // throw if not defined + } catch (error) { + throw new Error('chunks were not emitted right.') + } + import assert from 'assert'; + assert(globalThis.a === undefined, 'a should not be loaded'); + assert(globalThis.c === undefined, 'c should not be loaded'); + `, + "/test_c_only.js": /* js */ ` + import './out/c.js'; + try { + c; x; y; z; // throw if not defined + } catch (error) { + throw new Error('chunks were not emitted right.') + } + import assert from 'assert'; + assert(globalThis.a === undefined, 'a should not be loaded'); + assert(globalThis.b === undefined, 'b should not be loaded'); + `, + }, + run: [ + { file: "/test_all.js" }, + { file: "/test_a_only.js" }, + { file: "/test_b_only.js" }, + { file: "/test_c_only.js" }, + ], }); - itBundled("splitting/SplittingDuplicateChunkCollision", { - // GENERATED + itBundled("splitting/DuplicateChunkCollision", { files: { "/a.js": `import "./ab"`, "/b.js": `import "./ab"`, @@ -308,10 +478,12 @@ describe("bundler", () => { entryPoints: ["/a.js", "/b.js", "/c.js", "/d.js"], splitting: true, minifyWhitespace: true, - format: "esm", + onAfterBundle(api) { + const files = readdirSync(api.outdir); + expect(files.length).toBe(6); + }, }); - itBundled("splitting/SplittingMinifyIdentifiersCrashESBuildIssue437", { - // GENERATED + itBundled("splitting/MinifyIdentifiersCrashESBuildIssue437", { files: { "/a.js": /* js */ ` import {foo} from "./shared" @@ -327,39 +499,65 @@ describe("bundler", () => { entryPoints: ["/a.js", "/b.js", "/c.js"], splitting: true, minifyIdentifiers: true, - format: "esm", + run: [ + { file: "/out/a.js", stdout: "[Function]" }, + { file: "/out/b.js", stdout: "[Function]" }, + ], }); - itBundled("splitting/SplittingHybridESMAndCJSESBuildIssue617", { - // GENERATED + itBundled("splitting/HybridESMAndCJSESBuildIssue617", { files: { - "/a.js": `export let foo`, + "/a.js": `export let foo = 123`, "/b.js": `export let bar = require('./a')`, }, entryPoints: ["/a.js", "/b.js"], splitting: true, - format: "esm", + assertNotPresent: { + "/out/b.js": `123`, + }, + runtimeFiles: { + "/test.js": /* js */ ` + import { foo } from './out/a.js' + import { bar } from './out/b.js' + console.log(JSON.stringify({ foo, bar })) + `, + }, + run: { + file: "/test.js", + stdout: '{"foo":123,"bar":{"foo":123}}', + }, }); - itBundled("splitting/SplittingPublicPathEntryName", { - // GENERATED + itBundled("splitting/PublicPathEntryName", { files: { "/a.js": `import("./b")`, "/b.js": `console.log('b')`, }, + outdir: "/out", splitting: true, - format: "esm", publicPath: "/www", + onAfterBundle(api) { + const t = new Bun.Transpiler(); + const imports = t.scanImports(api.readFile("/out/a.js")); + expect(imports.length).toBe(1); + expect(imports[0].kind).toBe("dynamic-import"); + assert(imports[0].path.startsWith("/www/"), `Expected path to start with "/www/" but got "${imports[0].path}"`); + }, }); - itBundled("splitting/SplittingChunkPathDirPlaceholderImplicitOutbase", { - // GENERATED + itBundled("splitting/ChunkPathDirPlaceholderImplicitOutbase", { files: { "/project/entry.js": `console.log(import('./output-path/should-contain/this-text/file'))`, "/project/output-path/should-contain/this-text/file.js": `console.log('file.js')`, }, - format: "esm", + outdir: "/out", splitting: true, + chunkNames: "[dir]/[name]-[hash].[ext]", + onAfterBundle(api) { + assert( + readdirSync(api.outdir + "/output-path/should-contain/this-text").length === 1, + "Expected one file in out/output-path/should-contain/this-text/", + ); + }, }); - itBundled("splitting/EdgeCaseESBuildIssue2793WithSplitting", { - // GENERATED + const EdgeCaseESBuildIssue2793WithSplitting = itBundled("splitting/EdgeCaseESBuildIssue2793WithSplitting", { files: { "/src/a.js": `export const A = 42;`, "/src/b.js": `export const B = async () => (await import(".")).A`, @@ -370,21 +568,31 @@ describe("bundler", () => { }, outdir: "/out", entryPoints: ["/src/index.js"], - format: "esm", splitting: true, + platform: "browser", + runtimeFiles: { + "/test.js": /* js */ ` + import { A, B } from './out/index.js' + console.log(A, B() instanceof Promise, await B()) + `, + }, + run: { + file: "/test.js", + stdout: "42 true 42", + }, }); itBundled("splitting/EdgeCaseESBuildIssue2793WithoutSplitting", { - // GENERATED - files: { - "/src/a.js": `export const A = 42;`, - "/src/b.js": `export const B = async () => (await import(".")).A`, - "/src/index.js": /* js */ ` - export * from "./a" - export * from "./b" + ...EdgeCaseESBuildIssue2793WithSplitting.options, + splitting: false, + runtimeFiles: { + "/test.js": /* js */ ` + import { A, B } from './out/index.js' + console.log(A, B() instanceof Promise, await B()) `, }, - entryPoints: ["/src/index.js"], - format: "esm", - outdir: "/out", + run: { + file: "/test.js", + stdout: "42 true 42", + }, }); }); diff --git a/test/bundler/esbuild/ts.test.ts b/test/bundler/esbuild/ts.test.ts index a3ac313a4..9843a1cbe 100644 --- a/test/bundler/esbuild/ts.test.ts +++ b/test/bundler/esbuild/ts.test.ts @@ -5,10 +5,10 @@ var { describe, test, expect } = testForFile(import.meta.path); // Tests ported from: // https://github.com/evanw/esbuild/blob/main/internal/bundler_tests/bundler_ts_test.go -// For debug, all files are written to $TEMP/bun-bundle-tests/ts +// For debug, all files are written to $TEMP/bun-bundle-tests/ describe("bundler", () => { - itBundled("ts/TSDeclareConst", { + itBundled("ts/DeclareConst", { files: { "/entry.ts": /* ts */ ` declare const require: any @@ -27,7 +27,7 @@ describe("bundler", () => { assert(!api.readFile("/out.js").includes("const foo"), 'does not include "const foo"'); }, }); - itBundled("ts/TSDeclareLet", { + itBundled("ts/DeclareLet", { files: { "/entry.ts": /* ts */ ` declare let require: any @@ -45,7 +45,7 @@ describe("bundler", () => { assert(!api.readFile("/out.js").includes("module"), 'does not include "module"'); }, }); - itBundled("ts/TSDeclareVar", { + itBundled("ts/DeclareVar", { files: { "/entry.ts": /* ts */ ` declare var require: any @@ -63,7 +63,7 @@ describe("bundler", () => { assert(!api.readFile("/out.js").includes("module"), 'does not include "module"'); }, }); - itBundled("ts/TSDeclareClass", { + itBundled("ts/DeclareClass", { files: { "/entry.ts": /* ts */ ` declare class require {} @@ -82,7 +82,7 @@ describe("bundler", () => { assert(!api.readFile("/out.js").includes("class"), 'does not include "class"'); }, }); - itBundled("ts/TSDeclareClassFields", { + itBundled("ts/DeclareClassFields", { files: { "/entry.ts": /* ts */ ` import './setup' @@ -101,15 +101,15 @@ describe("bundler", () => { `, "/define-false/index.ts": /* ts */ ` class Foo { - a - declare b - [(() => null, c)] - declare [(() => null, d)] + a = 1 + declare b: number + [(() => null, c)] = 3 + declare [(() => null, d)]: number - static A - static declare B - static [(() => null, C)] - static declare [(() => null, D)] + static A = 5 + static declare B: number + static [(() => null, C)] = 7 + static declare [(() => null, D)]: number } const props = x => JSON.stringify({ ...Object.getOwnPropertyDescriptors(x), length: undefined, prototype: undefined }) console.log('Foo ', props(Foo)) @@ -141,14 +141,14 @@ describe("bundler", () => { }, run: { stdout: ` - Foo {"name":{"value":"Foo","writable":false,"enumerable":false,"configurable":true}} - new Foo {} + Foo {"name":{"value":"Foo","writable":false,"enumerable":false,"configurable":true},"A":{"value":5,"writable":true,"enumerable":true,"configurable":true},"global.C":{"value":7,"writable":true,"enumerable":true,"configurable":true}} + new Foo {"a":{"value":1,"writable":true,"enumerable":true,"configurable":true},"global.c":{"value":3,"writable":true,"enumerable":true,"configurable":true}} Bar {"name":{"value":"Bar","writable":false,"enumerable":false,"configurable":true},"A":{"writable":true,"enumerable":true,"configurable":true},"global.C":{"writable":true,"enumerable":true,"configurable":true}} new Bar {"a":{"writable":true,"enumerable":true,"configurable":true},"global.c":{"writable":true,"enumerable":true,"configurable":true}} `, }, }); - itBundled("ts/TSDeclareFunction", { + itBundled("ts/DeclareFunction", { files: { "/entry.ts": /* ts */ ` declare function require(): void @@ -167,7 +167,7 @@ describe("bundler", () => { assert(!api.readFile("/out.js").includes("function"), 'does not include "function"'); }, }); - itBundled("ts/TSDeclareNamespace", { + itBundled("ts/DeclareNamespace", { files: { "/entry.ts": /* ts */ ` declare namespace require {} @@ -186,7 +186,7 @@ describe("bundler", () => { assert(!api.readFile("/out.js").includes("namespace"), 'does not include "namespace"'); }, }); - itBundled("ts/TSDeclareEnum", { + itBundled("ts/DeclareEnum", { files: { "/entry.ts": /* ts */ ` declare enum require {} @@ -205,7 +205,7 @@ describe("bundler", () => { assert(!api.readFile("/out.js").includes("enum"), 'does not include "enum"'); }, }); - itBundled("ts/TSDeclareConstEnum", { + itBundled("ts/DeclareConstEnum", { files: { "/entry.ts": /* ts */ ` declare const enum require {} @@ -225,7 +225,10 @@ describe("bundler", () => { assert(!api.readFile("/out.js").includes("const"), 'does not include "const"'); }, }); - itBundled("ts/TSConstEnumComments", { + itBundled("ts/ConstEnumComments", { + // When it comes time to implement this inlining, we may decide we do NOT + // want to insert helper comments. + notImplemented: true, files: { "/bar.ts": /* ts */ ` export const enum Foo { @@ -268,7 +271,7 @@ describe("bundler", () => { stdout: `{"should have comments":[1,1],"should not have comments":[2,2]}`, }, }); - itBundled("ts/TSImportEmptyNamespace", { + itBundled("ts/ImportEmptyNamespace", { files: { "/entry.ts": /* ts */ ` import {REMOVE} from './ns.ts' @@ -280,7 +283,7 @@ describe("bundler", () => { dce: true, run: true, }); - itBundled("ts/TSImportMissingES6", { + itBundled("ts/ImportMissingES6", { files: { "/entry.ts": /* ts */ ` import fn, {x as a, y as b} from './foo' @@ -290,24 +293,25 @@ describe("bundler", () => { }, bundleErrors: { "/entry.ts": [ - `No matching export "default" in "foo.js" for import "default"`, - `No matching export "y" in "foo.js" for import "y"`, + `No matching export in "foo.js" for import "default"`, + `No matching export in "foo.js" for import "y"`, ], }, }); - itBundled("ts/TSImportMissingUnusedES6", { + itBundled("ts/ImportMissingUnusedES6", { files: { "/entry.ts": `import fn, {x as a, y as b} from './foo'`, "/foo.js": `export const x = 123`, }, // goal for this test is there is no error. we dont really care about the output }); - itBundled("ts/TSExportMissingES6", { + itBundled("ts/ExportMissingES6", { files: { "/entry.js": /* js */ ` import * as ns from './foo' console.log(JSON.stringify(ns)) `, + // the reason this doesnt error in TS is because `nope` can be a type "/foo.ts": `export {nope} from './bar'`, "/bar.js": `export const yep = 123`, }, @@ -315,7 +319,7 @@ describe("bundler", () => { stdout: `{}`, }, }); - itBundled("ts/TSImportMissingFile", { + itBundled("ts/ImportMissingFile", { files: { "/entry.ts": /* ts */ ` import {Something} from './doesNotExist.ts' @@ -326,7 +330,7 @@ describe("bundler", () => { "/entry.ts": [`Could not resolve: "./doesNotExist.ts"`], }, }); - itBundled("ts/TSImportTypeOnlyFile", { + itBundled("ts/ImportTypeOnlyFile", { files: { "/entry.ts": /* ts */ ` import {SomeType1} from './doesNotExist1.ts' @@ -340,7 +344,7 @@ describe("bundler", () => { stdout: "2", }, }); - itBundled("ts/TSExportEquals", { + itBundled("ts/ExportEquals", { files: { "/a.ts": /* ts */ ` import b from './b.ts' @@ -355,7 +359,7 @@ describe("bundler", () => { stdout: `[123,null]`, }, }); - itBundled("ts/TSExportNamespace", { + itBundled("ts/ExportNamespace", { files: { "/a.ts": /* ts */ ` import {Foo} from './b.ts' @@ -377,33 +381,34 @@ describe("bundler", () => { stdout: `{}\n1\n2`, }, }); - itBundled("ts/TSMinifyEnum", { + itBundled("ts/MinifyEnum", { + notImplemented: true, files: { "/a.ts": `enum Foo { A, B, C = Foo }\ncapture(Foo)`, - "/b.ts": `export enum Foo { X, Y, Z = Foo }`, + // "/b.ts": `export enum Foo { X, Y, Z = Foo }`, }, - entryPoints: ["/a.ts", "/b.ts"], + entryPoints: ["/a.ts"], minifySyntax: true, minifyWhitespace: true, minifyIdentifiers: true, mode: "transform", onAfterBundle(api) { - const a = api.readFile("/out/a.js"); - api.writeFile("/out/a.edited.js", a.replace(/capture\((.*?)\)/, `export const Foo = $1`)); - const b = api.readFile("/out/b.js"); + const a = api.readFile("/out.js"); + api.writeFile("/out.edited.js", a.replace(/capture\((.*?)\)/, `export const Foo = $1`)); + // const b = api.readFile("/out/b.js"); // make sure the minification trick "enum[enum.K=V]=K" is used, but `enum` assert(a.match(/\b[a-zA-Z$]\[[a-zA-Z$]\.A=0]=["']A["']/), "should be using enum minification trick (1)"); assert(a.match(/\b[a-zA-Z$]\[[a-zA-Z$]\.B=1]=["']B["']/), "should be using enum minification trick (2)"); assert(a.match(/\b[a-zA-Z$]\[[a-zA-Z$]\.C=[a-zA-Z$]]=["']C["']/), "should be using enum minification trick (3)"); - assert(b.match(/\b[a-zA-Z$]\[[a-zA-Z$]\.X=0]=["']X["']/), "should be using enum minification trick (4)"); - assert(b.match(/\b[a-zA-Z$]\[[a-zA-Z$]\.Y=1]=["']Y["']/), "should be using enum minification trick (5)"); - assert(b.match(/\b[a-zA-Z$]\[[a-zA-Z$]\.Z=[a-zA-Z$]]=["']Z["']/), "should be using enum minification trick (6)"); + // assert(b.match(/\b[a-zA-Z$]\[[a-zA-Z$]\.X=0]=["']X["']/), "should be using enum minification trick (4)"); + // assert(b.match(/\b[a-zA-Z$]\[[a-zA-Z$]\.Y=1]=["']Y["']/), "should be using enum minification trick (5)"); + // assert(b.match(/\b[a-zA-Z$]\[[a-zA-Z$]\.Z=[a-zA-Z$]]=["']Z["']/), "should be using enum minification trick (6)"); }, runtimeFiles: { "/test.js": /* js */ ` import {Foo as FooA} from './out/a.edited.js' - import {Foo as FooB} from './out/b.js' + // import {Foo as FooB} from './out/b.js' import assert from 'assert'; assert.strictEqual(FooA.A, 0, 'a.ts Foo.A') assert.strictEqual(FooA.B, 1, 'a.ts Foo.B') @@ -411,6 +416,37 @@ describe("bundler", () => { assert.strictEqual(FooA[0], 'A', 'a.ts Foo[0]') assert.strictEqual(FooA[1], 'B', 'a.ts Foo[1]') assert.strictEqual(FooA[FooA], 'C', 'a.ts Foo[Foo]') + // assert.strictEqual(FooB.X, 0, 'b.ts Foo.X') + // assert.strictEqual(FooB.Y, 1, 'b.ts Foo.Y') + // assert.strictEqual(FooB.Z, FooB, 'b.ts Foo.Z') + // assert.strictEqual(FooB[0], 'X', 'b.ts Foo[0]') + // assert.strictEqual(FooB[1], 'Y', 'b.ts Foo[1]') + // assert.strictEqual(FooB[FooB], 'Z', 'b.ts Foo[Foo]') + `, + }, + }); + itBundled("ts/MinifyEnumExported", { + notImplemented: true, + files: { + "/b.ts": `export enum Foo { X, Y, Z = Foo }`, + }, + entryPoints: ["/b.ts"], + minifySyntax: true, + minifyWhitespace: true, + minifyIdentifiers: true, + mode: "transform", + onAfterBundle(api) { + const b = api.readFile("/out.js"); + + // make sure the minification trick "enum[enum.K=V]=K" is used, but `enum` + assert(b.match(/\b[a-zA-Z$]\[[a-zA-Z$]\.X=0]=["']X["']/), "should be using enum minification trick (4)"); + assert(b.match(/\b[a-zA-Z$]\[[a-zA-Z$]\.Y=1]=["']Y["']/), "should be using enum minification trick (5)"); + assert(b.match(/\b[a-zA-Z$]\[[a-zA-Z$]\.Z=[a-zA-Z$]]=["']Z["']/), "should be using enum minification trick (6)"); + }, + runtimeFiles: { + "/test.js": /* js */ ` + import {Foo as FooB} from './out.js' + import assert from 'assert'; assert.strictEqual(FooB.X, 0, 'b.ts Foo.X') assert.strictEqual(FooB.Y, 1, 'b.ts Foo.Y') assert.strictEqual(FooB.Z, FooB, 'b.ts Foo.Z') @@ -420,7 +456,7 @@ describe("bundler", () => { `, }, }); - itBundled("ts/TSMinifyNestedEnum", { + itBundled("ts/MinifyNestedEnum", { files: { "/a.ts": `function foo(arg) { enum Foo { A, B, C = Foo, D = arg } return Foo }\ncapture(foo)`, "/b.ts": `export function foo(arg) { enum Foo { X, Y, Z = Foo, W = arg } return Foo }`, @@ -429,7 +465,6 @@ describe("bundler", () => { minifySyntax: true, minifyWhitespace: true, minifyIdentifiers: true, - mode: "transform", onAfterBundle(api) { const a = api.readFile("/out/a.js"); api.writeFile("/out/a.edited.js", a.replace(/capture\((.*?)\)/, `export const Foo = $1`)); @@ -461,7 +496,7 @@ describe("bundler", () => { `, }, }); - itBundled("ts/TSMinifyNestedEnumNoLogicalAssignment", { + itBundled("ts/MinifyNestedEnumNoLogicalAssignment", { files: { "/a.ts": `function foo(arg) { enum Foo { A, B, C = Foo, D = arg } return Foo }\ncapture(foo)`, "/b.ts": `export function foo(arg) { enum Foo { X, Y, Z = Foo, W = arg } return Foo }`, @@ -481,7 +516,7 @@ describe("bundler", () => { assert(!b.includes("||="), "b should not use logical assignment"); }, }); - itBundled("ts/TSMinifyNestedEnumNoArrow", { + itBundled("ts/MinifyNestedEnumNoArrow", { files: { "/a.ts": `function foo() { enum Foo { A, B, C = Foo } return Foo }`, "/b.ts": `export function foo() { enum Foo { X, Y, Z = Foo } return Foo }`, @@ -502,7 +537,7 @@ describe("bundler", () => { assert(!b.includes("=>"), "b should not use arrow"); }, }); - itBundled("ts/TSMinifyNamespace", { + itBundled("ts/MinifyNamespace", { files: { "/a.ts": /* ts */ ` namespace Foo { @@ -524,7 +559,6 @@ describe("bundler", () => { minifySyntax: true, minifyWhitespace: true, minifyIdentifiers: true, - mode: "transform", onAfterBundle(api) { api.writeFile("/out/a.edited.js", api.readFile("/out/a.js").replace(/capture\((.*?)\)/, `export const Foo = $1`)); }, @@ -540,7 +574,7 @@ describe("bundler", () => { `, }, }); - itBundled("ts/TSMinifyNamespaceNoLogicalAssignment", { + itBundled("ts/MinifyNamespaceNoLogicalAssignment", { files: { "/a.ts": /* ts */ ` namespace Foo { @@ -573,7 +607,7 @@ describe("bundler", () => { assert(!b.includes("||="), "b should not use logical assignment"); }, }); - itBundled("ts/TSMinifyNamespaceNoArrow", { + itBundled("ts/MinifyNamespaceNoArrow", { files: { "/a.ts": /* ts */ ` namespace Foo { @@ -606,7 +640,7 @@ describe("bundler", () => { assert(!b.includes("=>"), "b should not use arrow"); }, }); - itBundled("ts/TSMinifyDerivedClass", { + itBundled("ts/MinifyDerivedClass", { files: { "/entry.ts": /* ts */ ` class Foo extends Bar { @@ -648,7 +682,7 @@ describe("bundler", () => { stdout: "super\n1 2 3", }, }); - itBundled("ts/TSImportVsLocalCollisionAllTypes", { + itBundled("ts/ImportVsLocalCollisionAllTypes", { files: { "/entry.ts": /* ts */ ` import {a, b, c, d, e} from './other.ts' @@ -665,7 +699,7 @@ describe("bundler", () => { stdout: '[null,0,null,5,{"prop":2}]', }, }); - itBundled("ts/TSImportVsLocalCollisionMixed", { + itBundled("ts/ImportVsLocalCollisionMixed", { files: { "/entry.ts": /* ts */ ` import {a, b, c, d, e, real} from './other.ts' @@ -682,7 +716,8 @@ describe("bundler", () => { stdout: '[null,0,null,5,{"prop":2},123]', }, }); - itBundled("ts/TSImportEqualsEliminationTest", { + itBundled("ts/ImportEqualsEliminationTest", { + notImplemented: true, files: { "/entry.ts": /* ts */ ` import a = foo.a @@ -713,7 +748,7 @@ describe("bundler", () => { stdout: "123", }, }); - itBundled("ts/TSImportEqualsTreeShakingFalse", { + itBundled("ts/ImportEqualsTreeShakingFalse", { files: { "/entry.ts": /* ts */ ` import { foo } from 'pkg' @@ -725,8 +760,9 @@ describe("bundler", () => { treeShaking: false, dce: true, mode: "transform", + external: ["pkg"], }); - itBundled("ts/TSImportEqualsTreeShakingTrue", { + itBundled("ts/ImportEqualsTreeShakingTrue", { files: { "/entry.ts": /* ts */ ` import { foo } from 'pkg' @@ -737,9 +773,11 @@ describe("bundler", () => { }, dce: true, treeShaking: true, + external: ["pkg"], mode: "transform", }); - itBundled("ts/TSImportEqualsBundle", { + itBundled("ts/ImportEqualsBundle", { + notImplemented: true, files: { "/entry.ts": /* ts */ ` import { foo } from 'pkg' @@ -749,9 +787,10 @@ describe("bundler", () => { `, }, dce: true, + treeShaking: true, external: ["pkg"], }); - itBundled("ts/TSMinifiedBundleES6", { + itBundled("ts/MinifiedBundleES6", { files: { "/entry.ts": /* ts */ ` import {foo} from './a' @@ -770,7 +809,7 @@ describe("bundler", () => { stdout: "123", }, }); - itBundled("ts/TSMinifiedBundleCommonJS", { + itBundled("ts/MinifiedBundleCommonJS", { files: { "/entry.ts": /* ts */ ` const {foo} = require('./a') @@ -1004,7 +1043,7 @@ describe("bundler", () => { ]); }, }); - itBundled("ts/TSExportDefaultTypeESBuildIssue316", { + itBundled("ts/ExportDefaultTypeESBuildIssue316", { files: { "/entry.ts": /* ts */ ` import dc_def, { bar as dc } from './keep/declare-class' @@ -1139,7 +1178,7 @@ describe("bundler", () => { `, }, }); - itBundled("ts/TSImplicitExtensions", { + itBundled("ts/ImplicitExtensions", { files: { "/entry.ts": /* ts */ ` import './pick-js.js' @@ -1166,7 +1205,7 @@ describe("bundler", () => { stdout: "correct\n".repeat(6), }, }); - itBundled("ts/TSImplicitExtensionsMissing", { + itBundled("ts/ImplicitExtensionsMissing", { files: { "/entry.ts": /* ts */ ` import './mjs.mjs' @@ -1499,7 +1538,7 @@ describe("bundler", () => { file: "/test.js", }, }); - itBundled("ts/TSComputedClassFieldUseDefineFalse", { + itBundled("ts/ComputedClassFieldUseDefineFalse", { files: { "/entry.ts": /* ts */ ` class Foo { @@ -1546,7 +1585,7 @@ describe("bundler", () => { file: "/test.js", }, }); - itBundled("ts/TSComputedClassFieldUseDefineTrue", { + itBundled("ts/ComputedClassFieldUseDefineTrue", { files: { "/entry.ts": /* ts */ ` class Foo { @@ -1593,7 +1632,7 @@ describe("bundler", () => { file: "/test.js", }, }); - itBundled("ts/TSComputedClassFieldUseDefineTrueLower", { + itBundled("ts/ComputedClassFieldUseDefineTrueLower", { files: { "/entry.ts": /* ts */ ` class Foo { @@ -1641,7 +1680,7 @@ describe("bundler", () => { }, unsupportedJSFeatures: ["class-field"], }); - itBundled("ts/TSAbstractClassFieldUseAssign", { + itBundled("ts/AbstractClassFieldUseAssign", { files: { "/entry.ts": /* ts */ ` const keepThis = Symbol('keepThis') @@ -1659,7 +1698,7 @@ describe("bundler", () => { dce: true, useDefineForClassFields: false, }); - itBundled("ts/TSAbstractClassFieldUseDefine", { + itBundled("ts/AbstractClassFieldUseDefine", { files: { "/entry.ts": /* ts */ ` const keepThisToo = Symbol('keepThisToo') @@ -1677,7 +1716,7 @@ describe("bundler", () => { mode: "transform", useDefineForClassFields: true, }); - itBundled("ts/TSImportMTS", { + itBundled("ts/ImportMTS", { files: { "/entry.ts": `import './imported.mjs'`, "/imported.mts": `console.log('works')`, @@ -1686,7 +1725,7 @@ describe("bundler", () => { stdout: "works", }, }); - itBundled("ts/TSImportCTS", { + itBundled("ts/ImportCTS", { files: { "/entry.ts": `require('./required.cjs')`, "/required.cjs": `console.log('works')`, @@ -1695,7 +1734,7 @@ describe("bundler", () => { stdout: "works", }, }); - itBundled("ts/TSSideEffectsFalseWarningTypeDeclarations", { + itBundled("ts/SideEffectsFalseWarningTypeDeclarations", { files: { "/entry.ts": /* ts */ ` import "some-js" @@ -1719,7 +1758,7 @@ describe("bundler", () => { expect(api.readFile("/out.js").trim()).toBe(""); }, }); - itBundled("ts/TSSiblingNamespace", { + itBundled("ts/SiblingNamespace", { files: { "/let.ts": /* ts */ ` export namespace x { export let y = 123 } @@ -1760,8 +1799,7 @@ describe("bundler", () => { `, }, }); - if (!RUN_UNCHECKED_TESTS) return; - itBundled("ts/TSSiblingEnum", { + itBundled("ts/SiblingEnum", { // GENERATED files: { "/number.ts": /* ts */ ` @@ -1837,7 +1875,7 @@ describe("bundler", () => { ], mode: "passthrough", }); - itBundled("ts/TSEnumTreeShaking", { + itBundled("ts/EnumTreeShaking", { // GENERATED files: { "/simple-member.ts": /* ts */ ` @@ -1888,7 +1926,7 @@ describe("bundler", () => { "/namespace-after.ts", ], }); - itBundled("ts/TSEnumJSX", { + itBundled("ts/EnumJSX", { // GENERATED files: { "/element.tsx": /* tsx */ ` @@ -1911,14 +1949,14 @@ describe("bundler", () => { entryPoints: ["/element.tsx", "/fragment.tsx", "/nested-element.tsx", "/nested-fragment.tsx"], mode: "passthrough", }); - itBundled("ts/TSEnumDefine", { + itBundled("ts/EnumDefine", { // GENERATED files: { "/entry.ts": `enum a { b = 123, c = d }`, }, mode: "passthrough", }); - itBundled("ts/TSEnumSameModuleInliningAccess", { + itBundled("ts/EnumSameModuleInliningAccess", { // GENERATED files: { "/entry.ts": /* ts */ ` @@ -1937,7 +1975,7 @@ describe("bundler", () => { `, }, }); - itBundled("ts/TSEnumCrossModuleInliningAccess", { + itBundled("ts/EnumCrossModuleInliningAccess", { // GENERATED files: { "/entry.ts": /* ts */ ` @@ -1959,7 +1997,7 @@ describe("bundler", () => { `, }, }); - itBundled("ts/TSEnumCrossModuleInliningDefinitions", { + itBundled("ts/EnumCrossModuleInliningDefinitions", { // GENERATED files: { "/entry.ts": /* ts */ ` @@ -1981,7 +2019,7 @@ describe("bundler", () => { `, }, }); - itBundled("ts/TSEnumCrossModuleInliningReExport", { + itBundled("ts/EnumCrossModuleInliningReExport", { // GENERATED files: { "/entry.js": /* js */ ` @@ -2003,7 +2041,7 @@ describe("bundler", () => { `, }, }); - itBundled("ts/TSEnumCrossModuleTreeShaking", { + itBundled("ts/EnumCrossModuleTreeShaking", { // GENERATED files: { "/entry.ts": /* ts */ ` @@ -2048,7 +2086,7 @@ describe("bundler", () => { `, }, }); - itBundled("ts/TSEnumExportClause", { + itBundled("ts/EnumExportClause", { // GENERATED files: { "/entry.ts": /* ts */ ` @@ -2075,7 +2113,7 @@ describe("bundler", () => { `, }, }); - itBundled("ts/TSThisIsUndefinedWarning", { + itBundled("ts/ThisIsUndefinedWarning", { // GENERATED files: { "/warning1.ts": `export var foo = this`, @@ -2093,7 +2131,7 @@ describe("bundler", () => { warning3.ts: NOTE: This file is considered to be an ECMAScript module because of the "export" keyword here: `, */ }); - itBundled("ts/TSCommonJSVariableInESMTypeModule", { + itBundled("ts/CommonJSVariableInESMTypeModule", { // GENERATED files: { "/entry.ts": `module.exports = null`, @@ -2182,7 +2220,7 @@ describe("bundler", () => { }, entryPoints: ["/supported.ts", "/not-supported.ts"], }); - itBundled("ts/TSEnumUseBeforeDeclare", { + itBundled("ts/EnumUseBeforeDeclare", { // GENERATED files: { "/entry.ts": /* ts */ ` diff --git a/test/bundler/expectBundled.ts b/test/bundler/expectBundled.ts index 94d476a0c..2dda32cb0 100644 --- a/test/bundler/expectBundled.ts +++ b/test/bundler/expectBundled.ts @@ -30,9 +30,11 @@ const ESBUILD = process.env.BUN_BUNDLER_TEST_USE_ESBUILD; const DEBUG = process.env.BUN_BUNDLER_TEST_DEBUG; /** Set this to the id of a bundle test to run just that test */ const FILTER = process.env.BUN_BUNDLER_TEST_FILTER; +/** Set this to hide skips */ +const HIDE_SKIP = process.env.BUN_BUNDLER_TEST_HIDE_SKIP; /** Path to the bun. TODO: Once bundler is merged, we should remove the `bun-debug` fallback. */ const BUN_EXE = (process.env.BUN_EXE && Bun.which(process.env.BUN_EXE)) ?? Bun.which("bun-debug") ?? bunExe(); -export const RUN_UNCHECKED_TESTS = true; +export const RUN_UNCHECKED_TESTS = false; const outBaseTemplate = path.join(tmpdir(), "bun-build-tests", `${ESBUILD ? "esbuild" : "bun"}-`); if (!existsSync(path.dirname(outBaseTemplate))) mkdirSync(path.dirname(outBaseTemplate), { recursive: true }); @@ -73,6 +75,8 @@ export interface BundlerTestInput { define?: Record<string, string | number>; /** Default is "[name].[ext]" */ entryNames?: string; + /** Default is "[name]-[hash].[ext]" */ + chunkNames?: string; extensionOrder?: string[]; /** Replaces "{{root}}" with the file root */ external?: string[]; @@ -114,6 +118,10 @@ export interface BundlerTestInput { useDefineForClassFields?: boolean; sourceMap?: boolean | "inline" | "external"; + // pass subprocess.env + env?: Record<string, any>; + nodePaths?: string[]; + // assertion options /** @@ -138,6 +146,13 @@ export interface BundlerTestInput { */ dce?: boolean; /** + * Shorthand for testing CJS->ESM cases. + * Checks source code for the commonjs helper. + * + * Set to true means all cjs files should be converted. You can pass `exclude` to expect them to stay commonjs. + */ + cjs2esm?: boolean | { exclude: string[] }; + /** * Override the number of keep markers, which is auto detected by default. * Does nothing if dce is false. */ @@ -233,12 +248,14 @@ export function expectBundled( bundleErrors, bundleWarnings, capture, + chunkNames, dce, dceKeepMarkerCount, define, entryNames, entryPoints, entryPointsRaw, + env, external, files, format, @@ -261,6 +278,7 @@ export function expectBundled( outfile, outputPaths, platform, + publicPath, run, runtimeFiles, skipOnEsbuild, @@ -273,10 +291,6 @@ export function expectBundled( ...unknownProps } = opts; - if (!ESBUILD && platform === "neutral") { - platform = "browser"; - } - // TODO: Remove this check once all options have been implemented if (Object.keys(unknownProps).length > 0) { throw new Error("expectBundled recieved unexpected options: " + Object.keys(unknownProps).join(", ")); @@ -337,6 +351,12 @@ export function expectBundled( if (!ESBUILD && inject) { throw new Error("inject not implemented in bun build"); } + if (!ESBUILD && publicPath) { + throw new Error("publicPath not implemented in bun build"); + } + if (!ESBUILD && chunkNames) { + throw new Error("chunkNames is not implemented in bun build"); + } if (ESBUILD && skipOnEsbuild) { return testRef(id, opts); } @@ -362,8 +382,13 @@ export function expectBundled( : entryPaths.map(file => path.join(outdir!, path.basename(file))) ).map(x => x.replace(/\.ts$/, ".js")); + if (mode === "transform" && !outfile) { + throw new Error("transform mode requires one single outfile"); + } + if (outdir) { entryNames ??= "[name].[ext]"; + chunkNames ??= "[name]-[hash].[ext]"; } // Option validation @@ -410,7 +435,7 @@ export function expectBundled( "build", ...entryPaths, ...(entryPointsRaw ?? []), - outfile ? `--outfile=${outfile}` : `--outdir=${outdir}`, + mode === "bundle" ? [outfile ? `--outfile=${outfile}` : `--outdir=${outdir}`] : [], define && Object.entries(define).map(([k, v]) => ["--define", `${k}=${v}`]), `--platform=${platform}`, external && external.map(x => ["--external", x]), @@ -426,6 +451,7 @@ export function expectBundled( // metafile && `--metafile=${metafile}`, // sourceMap && `--sourcemap${sourceMap !== true ? `=${sourceMap}` : ""}`, entryNames && entryNames !== "[name].[ext]" && [`--entry-names`, entryNames], + // chunkNames && chunkNames !== "[name]-[hash].[ext]" && [`--chunk-names`, chunkNames], // `--format=${format}`, // legalComments && `--legal-comments=${legalComments}`, splitting && `--splitting`, @@ -434,6 +460,7 @@ export function expectBundled( // keepNames && `--keep-names`, // mainFields && `--main-fields=${mainFields}`, // loader && Object.entries(loader).map(([k, v]) => ["--loader", `${k}=${v}`]), + // publicPath && `--public-path=${publicPath}`, mode === "transform" && "--transform", ] : [ @@ -454,6 +481,7 @@ export function expectBundled( jsx.fragment && `--jsx-fragment=${jsx.fragment}`, jsx.development && `--jsx-dev`, entryNames && entryNames !== "[name].[ext]" && `--entry-names=${entryNames.replace(/\.\[ext]$/, "")}`, + chunkNames && chunkNames !== "[name]-[hash].[ext]" && `--chunk-names=${chunkNames.replace(/\.\[ext]$/, "")}`, metafile && `--metafile=${metafile}`, sourceMap && `--sourcemap${sourceMap !== true ? `=${sourceMap}` : ""}`, banner && `--banner:js=${banner}`, @@ -464,6 +492,7 @@ export function expectBundled( keepNames && `--keep-names`, mainFields && `--main-fields=${mainFields.join(",")}`, loader && Object.entries(loader).map(([k, v]) => `--loader:${k}=${v}`), + publicPath && `--public-path=${publicPath}`, [...(unsupportedJSFeatures ?? []), ...(unsupportedCSSFeatures ?? [])].map(x => `--supported:${x}=false`), ...entryPaths, ...(entryPointsRaw ?? []), @@ -508,11 +537,19 @@ export function expectBundled( ); } + const bundlerEnv = { ...bunEnv, ...env }; + // remove undefined keys instead of passing "undefined" + for (const key in bundlerEnv) { + if (bundlerEnv[key] === undefined) { + delete bundlerEnv[key]; + } + } + const { stdout, stderr, success } = Bun.spawnSync({ cmd, cwd: root, stdio: ["ignore", "pipe", "pipe"], - env: bunEnv, + env: bundlerEnv, }); // Check for errors @@ -607,6 +644,11 @@ export function expectBundled( throw new Error("Errors were expected while bundling:\n" + expectedErrors.map(formatError).join("\n")); } + if (mode === "transform" && !ESBUILD) { + mkdirSync(path.dirname(outfile!), { recursive: true }); + Bun.write(outfile!, stdout); + } + // Check for warnings let warningReference: Record<string, { file: string; error: string; line?: string; col?: string }[]> = {}; if (!ESBUILD) { @@ -967,7 +1009,7 @@ export function itBundled(id: string, opts: BundlerTestInput): BundlerTestRef { try { expectBundled(id, opts, true); } catch (error) { - it.skip(id, () => {}); + if (!HIDE_SKIP) it.skip(id, () => {}); return ref; } } @@ -981,7 +1023,7 @@ export function itBundled(id: string, opts: BundlerTestInput): BundlerTestRef { ); }); } catch (error: any) { - it.skip(id, () => {}); + if (!HIDE_SKIP) it.skip(id, () => {}); } } else { it(id, () => expectBundled(id, opts)); @@ -989,8 +1031,11 @@ export function itBundled(id: string, opts: BundlerTestInput): BundlerTestRef { return ref; } itBundled.skip = (id: string, opts: BundlerTestInput) => { + if (FILTER && id !== FILTER) { + return testRef(id, opts); + } const { it } = testForFile(callerSourceOrigin()); - it.skip(id, () => expectBundled(id, opts)); + if (!HIDE_SKIP) it.skip(id, () => expectBundled(id, opts)); return testRef(id, opts); }; @@ -1003,8 +1048,11 @@ export function bundlerTest(id: string, cb: () => void) { it(id, cb); } bundlerTest.skip = (id: string, cb: any) => { + if (FILTER && id !== FILTER) { + return; + } const { it } = testForFile(callerSourceOrigin()); - it.skip(id, cb); + if (!HIDE_SKIP) it.skip(id, cb); }; function formatError(err: { file: string; error: string; line?: string; col?: string }) { |