import assert from "assert"; import dedent from "dedent"; import { BundlerTestInput, itBundled, testForFile } from "./expectBundled"; var { describe, test, expect } = testForFile(import.meta.path); const helpers = { "/node_modules/bun-test-helpers/index.js": /* js */ ` export function print(arg) { const replacer = (_, val) => { if(typeof val === "function") { if(val.name) return 'Function:' + val.name; return val.toString(); } if(typeof val === "symbol") return val.toString(); if(val === undefined) return "undefined"; if(val === null) return "null"; return val; } const stringified = JSON.stringify(arg, replacer); if(!process.env.IS_TEST_RUNNER) { console.log(arg); } console.log(stringified); } `, "/node_modules/react/jsx-dev-runtime.js": /* js */ ` const $$typeof = Symbol.for("jsxdev"); export function jsxDEV(type, props, key, source, self) { return { $$typeof, type, props, key, source, self } } export const Fragment = Symbol.for("jsxdev.fragment"); `, "/node_modules/react/jsx-runtime.js": /* js */ ` const $$typeof = Symbol.for("jsx"); export function jsx(type, props, key) { return { $$typeof, type, props, key } } export const Fragment = Symbol.for("jsx.fragment"); `, "/node_modules/custom-jsx-dev/index.js": /* js */ ` export function jsxDEV(type, props, key, source, self) { return ['custom-jsx-dev', type, props, key, source, self] } export const Fragment = "CustomFragment" `, "/node_modules/custom-jsx/index.js": /* js */ ` export function jsx(a, b, c) { return ['custom-jsx', a, b, c] } export const Fragment = "CustomFragment" `, "/node_modules/custom-classic/index.js": /* js */ ` export function createElement(type, props, ...children) { return ['custom-classic', type, props, children] } export const Fragment = "CustomFragment" export const something = "something" `, "/node_modules/custom-automatic/jsx-runtime.js": /* js */ ` const $$typeof = Symbol.for("custom_jsx"); export function jsx(type, props, key) { return { $$typeof, type, props, key } } export const Fragment = Symbol.for("custom.fragment"); `, "/node_modules/custom-automatic/jsx-dev-runtime.js": /* js */ ` const $$typeof = Symbol.for("custom_jsxdev"); export function jsxDEV(type, props, key, source, self) { return { $$typeof, type, props, key, source, self } } export const Fragment = Symbol.for("custom_dev.fragment"); `, "/node_modules/custom-automatic/index.js": /* js */ ` export const Fragment = "FAILED" `, "/node_modules/react/index.js": /* js */ ` export function createElement(type, props, ...children) { return ['react', type, props, children] } export const Fragment = Symbol.for("react.fragment") export const fn = () => { throw new Error('test failed') } export const something = 'test failed'; `, "/node_modules/custom-renamed/index.js": /* js */ ` export function fn(type, props, ...children) { return ['custom-renamed', type, props, children] } export const Fragment = "CustomFragment" export const something = "something" `, "/node_modules/preact/index.js": /* js */ ` export function h(type, props, ...children) { return ['preact', type, props, children] } export const Fragment = "PreactFragment" `, }; function itBundledDevAndProd( id: string, opts: BundlerTestInput & { devStdout?: string; prodStdout?: string; devTodo?: boolean; prodTodo?: boolean; }, ) { const { devStdout, prodStdout, ...rest } = opts; itBundled(id + "Dev", { ...rest, env: { NODE_ENV: "development", }, run: devStdout ? { ...(rest.run === true ? {} : rest.run), stdout: devStdout, } : rest.run, }); itBundled(id + "Prod", { ...rest, env: { NODE_ENV: "production", }, run: prodStdout ? { ...(rest.run === true ? {} : rest.run), stdout: prodStdout, } : rest.run, }); } describe("bundler", () => { itBundledDevAndProd("jsx/Automatic", { files: { "index.jsx": /* js*/ ` import { print } from 'bun-test-helpers' const Component = 'hello' print(
Hello World
) print(

1}>hello

) `, ...helpers, }, target: "bun", devStdout: ` {"$$typeof":"Symbol(jsxdev)","type":"div","props":{"children":"Hello World"},"key":"undefined","source":false,"self":"undefined"} {"$$typeof":"Symbol(jsxdev)","type":"div","props":{"className":"container","children":{"$$typeof":"Symbol(jsxdev)","type":"hello","props":{"prop":2,"children":{"$$typeof":"Symbol(jsxdev)","type":"h1","props":{"onClick":"Function:onClick","children":"hello"},"key":"undefined","source":false,"self":"undefined"}},"key":"undefined","source":false,"self":"undefined"}},"key":"undefined","source":false,"self":"undefined"} `, prodStdout: ` {"$$typeof":"Symbol(react.element)","type":"div","key":"null","ref":"null","props":{"children":"Hello World"},"_owner":"null"} {"$$typeof":"Symbol(react.element)","type":"div","key":"null","ref":"null","props":{"className":"container","children":{"$$typeof":"Symbol(react.element)","type":"hello","key":"null","ref":"null","props":{"prop":2,"children":{"$$typeof":"Symbol(react.element)","type":"h1","key":"null","ref":"null","props":{"onClick":"Function:onClick","children":"hello"},"_owner":"null"}},"_owner":"null"}},"_owner":"null"} `, }); // bun does not do the production transform for fragments as good as it could be right now. itBundledDevAndProd("jsx/AutomaticFragment", { todo: true, files: { "index.jsx": /* js*/ ` import { print } from 'bun-test-helpers' const Component = 'hello' print(
Hello World
) print(

1}>hello

) print(<>Fragment) `, ...helpers, }, target: "bun", devStdout: ` {"$$typeof":"Symbol(jsxdev)","type":"Symbol(jsxdev.fragment)","props":{"children":"Fragment"},"key":"undefined","source":false,"self":"undefined"} `, prodStdout: ` {"$$typeof":"Symbol(react.element)","type":"Symbol("jsx.fragment")","key":"null","ref":"null","props":{"children":"Fragment"},"_owner":"null"} `, }); itBundledDevAndProd("jsx/ImportSource", { prodTodo: true, files: { "/index.jsx": /* js*/ ` import { print } from 'bun-test-helpers' print([
Hello World
, <>Fragment]) `, ...helpers, }, target: "bun", jsx: { importSource: "custom-automatic", }, devStdout: ` [{"$$typeof":"Symbol(custom_jsxdev)","type":"div","props":{"props":123,"children":"Hello World"},"key":"undefined","source":false,"self":"undefined"},{"$$typeof":"Symbol(custom_jsxdev)","type":"Symbol(custom_dev.fragment)","props":{"children":"Fragment"},"key":"undefined","source":false,"self":"undefined"}] `, prodStdout: ` [{"$$typeof":"Symbol(custom_jsx)","type":"div","props":{"props":123,"children":"Hello World"},"key":"undefined"},{"$$typeof":"Symbol(custom_jsx)","type":"Symbol(custom_dev.fragment)","props":{"children":"Fragment"},"key":"undefined"}] `, }); itBundledDevAndProd("jsx/Classic", { todo: true, files: { "/index.jsx": /* js*/ ` import { print } from 'bun-test-helpers' // not react to catch if bun auto imports or uses the global import * as React from 'custom-classic' print([
Hello World
, <>Fragment]) `, ...helpers, }, target: "bun", jsx: { runtime: "classic", importSource: "ignore-me", }, run: { stdout: ` [["custom-classic","div",{"props":123},["Hello World"]],["custom-classic","CustomFragment","null",["Fragment"]]] `, }, }); itBundledDevAndProd("jsx/ClassicPragma", { todo: true, files: { "/index.jsx": /* js*/ ` // @jsx fn // @jsxFrag something import { print } from 'bun-test-helpers' import { fn, something } from 'custom-renamed' print([
Hello World
, <>Fragment]) `, ...helpers, }, target: "bun", jsx: { runtime: "classic", importSource: "ignore-me", }, run: { stdout: ` [["custom-renamed","div",{"props":123},["Hello World"]],["custom-renamed","something","null",["Fragment"]]] `, }, }); itBundledDevAndProd("jsx/PragmaMultiple", { todo: true, files: { "/index.jsx": /* js*/ ` import './classic.jsx' import './classic-renamed.jsx' import './automatic.jsx' import './automatic-source2.jsx' `, "/classic.jsx": /* js*/ ` /* @jsxRuntime classic */ import { print } from 'bun-test-helpers' // not react to catch if bun auto imports or uses the global import * as React from 'custom-classic' print(['classic.jsx',
Hello World
, <>Fragment]) `, "/classic-renamed.jsx": /* js*/ ` /* @jsxRuntime classic */ // @jsx fn // @jsxFrag something import { print } from 'bun-test-helpers' import { fn, something } from 'custom-renamed' print(['classic-renamed.jsx',
Hello World
, <>Fragment]) `, "/automatic.jsx": /* js*/ ` import { print } from 'bun-test-helpers' print(['automatic.jsx',
Hello World
, process.env.NODE_ENV === 'production' ? '' : <>Fragment]) `, "/automatic-source2.jsx": /* js*/ ` // @jsxImportSource custom-automatic import { print } from 'bun-test-helpers' print(['automatic-source2.jsx',
Hello World
, <>Fragment]) `, ...helpers, }, target: "bun", devStdout: ` ["classic.jsx",["custom-classic","div",{"props":123},["Hello World"]],["custom-classic","CustomFragment","null",["Fragment"]]] ["classic-renamed.jsx",["custom-renamed","div",{"props":123},["Hello World"]],["custom-renamed","something","null",["Fragment"]]] ["automatic.jsx",{"$$typeof":"Symbol(jsxdev)","type":"div","props":{"props":123,"children":"Hello World"},"key":"undefined","source":false,"self":"undefined"},{"$$typeof":"Symbol(jsxdev)","type":"Symbol(jsxdev.fragment)","props":{"children":"Fragment"},"key":"undefined","source":false,"self":"undefined"}] ["automatic-source2.jsx",{"$$typeof":"Symbol(custom_jsxdev)","type":"div","props":{"props":123,"children":"Hello World"},"key":"undefined","source":false,"self":"undefined"},{"$$typeof":"Symbol(custom_jsxdev)","type":"Symbol(custom_dev.fragment)","props":{"children":"Fragment"},"key":"undefined","source":false,"self":"undefined"}] `, prodStdout: ` ["classic.jsx",["custom-classic","div",{"props":123},["Hello World"]],["custom-classic","CustomFragment","null",["Fragment"]]] ["classic-renamed.jsx",["custom-renamed","div",{"props":123},["Hello World"]],["custom-renamed","something","null",["Fragment"]]] ["automatic.jsx",{"$$typeof":"Symbol(react.element)","type":"div","key":"null","ref":"null","props":{"props":123,"children":"Hello World"},"_owner":"null"},""] ["automatic-source2.jsx",{"$$typeof":"Symbol(custom_jsx)","type":"div","props":{"props":123,"children":"Hello World"},"key":"undefined"},{"$$typeof":"Symbol(custom_jsx)","type":"Symbol(custom.fragment)","props":{"children":"Fragment"},"key":"undefined"}] `, }); itBundledDevAndProd("jsx/Factory", { todo: true, files: { "/index.jsx": /* js*/ ` const h = () => 'hello' const Fragment = 123; import * as React from "react"; import { print } from 'bun-test-helpers' print([
Hello World
, <>Fragment]) `, ...helpers, }, target: "bun", jsx: { runtime: "classic", factory: "h", }, run: { stdout: ` [\"hello\",\"hello\"] `, }, }); itBundledDevAndProd("jsx/FactoryImport", { todo: false, files: { "/index.jsx": /* js*/ ` import { h, fragment } from './jsx.ts'; const Fragment = 123; import { print } from 'bun-test-helpers' print([
Hello World
, <>Fragment]) `, "/jsx.ts": /* ts */ ` export const h = () => 'hello factory'; export const fragment = () => 'hello fragment'; `, ...helpers, }, target: "bun", jsx: { runtime: "classic", factory: "h", fragment: "fragment", }, run: { stdout: ` [\"hello factory\",\"hello factory\"] `, }, onAfterBundle(api) { expect(api.readFile("out.js")).toContain("h(fragment"); }, }); itBundledDevAndProd("jsx/FactoryImportExplicitReactDefault", { todo: false, files: { "/index.jsx": /* js*/ ` import { print } from 'bun-test-helpers' import * as React from 'react'; print([
Hello World
, <>Fragment]) `, ...helpers, }, target: "bun", jsx: { runtime: "classic", factory: "React.createElement", fragment: "React.Fragment", }, onAfterBundle(api) { expect(api.readFile("out.js")).toContain(" createElement"); expect(api.readFile("out.js")).toContain("(Fragment"); }, }); itBundledDevAndProd("jsx/FactoryImportExplicitReactDefaultExternal", { todo: false, files: { "/index.jsx": /* js*/ ` import { print } from 'bun-test-helpers' import * as React from 'react'; print([
Hello World
, <>Fragment]) `, ...helpers, }, target: "bun", jsx: { runtime: "classic", factory: "React.createElement", fragment: "React.Fragment", }, external: ["react"], onAfterBundle(api) { const file = api.readFile("out.js"); expect(file).toContain("React.createElement"); expect(file).toContain("React.Fragment"); expect(file).toContain('import * as React from "react"'); }, }); });