mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
395 lines
9.7 KiB
TypeScript
395 lines
9.7 KiB
TypeScript
// ESM tests are about various esm features in development mode.
|
|
import { devTest, emptyHtmlFile, minimalFramework } from "../bake-harness";
|
|
|
|
const liveBindingTest = devTest("live bindings with `var`", {
|
|
framework: minimalFramework,
|
|
files: {
|
|
"state.ts": `
|
|
export var value = 0;
|
|
export function increment() {
|
|
value++;
|
|
}
|
|
`,
|
|
"routes/index.ts": `
|
|
import { value, increment } from '../state';
|
|
export default function(req, meta) {
|
|
increment();
|
|
return new Response('State: ' + value);
|
|
}
|
|
`,
|
|
},
|
|
async test(dev) {
|
|
await dev.fetch("/").equals("State: 1");
|
|
await dev.fetch("/").equals("State: 2");
|
|
await dev.fetch("/").equals("State: 3");
|
|
await dev.patch("routes/index.ts", {
|
|
find: "State",
|
|
replace: "Value",
|
|
});
|
|
await dev.fetch("/").equals("Value: 4");
|
|
await dev.fetch("/").equals("Value: 5");
|
|
await dev.write(
|
|
"state.ts",
|
|
`
|
|
export var value = 0;
|
|
export function increment() {
|
|
value--;
|
|
}
|
|
`,
|
|
);
|
|
await dev.fetch("/").equals("Value: -1");
|
|
await dev.fetch("/").equals("Value: -2");
|
|
},
|
|
});
|
|
devTest("live bindings through export clause", {
|
|
framework: minimalFramework,
|
|
files: {
|
|
"state.ts": `
|
|
export var value = 0;
|
|
export function increment() {
|
|
value++;
|
|
}
|
|
`,
|
|
"proxy.ts": `
|
|
import { value } from './state';
|
|
export { value as live };
|
|
`,
|
|
"routes/index.ts": `
|
|
import { increment } from '../state';
|
|
import { live } from '../proxy';
|
|
export default function(req, meta) {
|
|
increment();
|
|
return new Response('State: ' + live);
|
|
}
|
|
`,
|
|
},
|
|
test: liveBindingTest.test,
|
|
});
|
|
devTest("live bindings through export from", {
|
|
framework: minimalFramework,
|
|
files: {
|
|
"state.ts": `
|
|
export var value = 0;
|
|
export function increment() {
|
|
value++;
|
|
}
|
|
`,
|
|
"proxy.ts": `
|
|
export { value as live } from './state';
|
|
`,
|
|
"routes/index.ts": `
|
|
import { increment } from '../state';
|
|
import { live } from '../proxy';
|
|
export default function(req, meta) {
|
|
increment();
|
|
return new Response('State: ' + live);
|
|
}
|
|
`,
|
|
},
|
|
test: liveBindingTest.test,
|
|
});
|
|
// devTest("live bindings through export star", {
|
|
// framework: minimalFramework,
|
|
// files: {
|
|
// "state.ts": `
|
|
// export var value = 0;
|
|
// export function increment() {
|
|
// value++;
|
|
// }
|
|
// `,
|
|
// "proxy.ts": `
|
|
// export * from './state';
|
|
// `,
|
|
// "routes/index.ts": `
|
|
// import { increment } from '../state';
|
|
// import { live } from '../proxy';
|
|
// export default function(req, meta) {
|
|
// increment();
|
|
// return new Response('State: ' + live);
|
|
// }
|
|
// `,
|
|
// },
|
|
// test: liveBindingTest.test,
|
|
// });
|
|
devTest("export { x as y }", {
|
|
framework: minimalFramework,
|
|
files: {
|
|
"module.ts": `
|
|
function x(value) {
|
|
return value + 1;
|
|
}
|
|
export { x as y };
|
|
`,
|
|
"routes/index.ts": `
|
|
import { y } from '../module';
|
|
export default function(req, meta) {
|
|
return new Response('Value: ' + y(1));
|
|
}
|
|
`,
|
|
},
|
|
async test(dev) {
|
|
await dev.fetch("/").equals("Value: 2");
|
|
await dev.patch("module.ts", {
|
|
find: "1",
|
|
replace: "2",
|
|
});
|
|
await dev.fetch("/").equals("Value: 3");
|
|
},
|
|
});
|
|
devTest("import { x as y }", {
|
|
framework: minimalFramework,
|
|
files: {
|
|
"module.ts": `
|
|
export const x = 1;
|
|
`,
|
|
"routes/index.ts": `
|
|
import { x as y } from '../module';
|
|
export default function(req, meta) {
|
|
return new Response('Value: ' + y);
|
|
}
|
|
`,
|
|
},
|
|
async test(dev) {
|
|
await dev.fetch("/").equals("Value: 1");
|
|
await dev.patch("module.ts", {
|
|
find: "1",
|
|
replace: "2",
|
|
});
|
|
await dev.fetch("/").equals("Value: 2");
|
|
},
|
|
});
|
|
devTest("import { default as y }", {
|
|
framework: minimalFramework,
|
|
files: {
|
|
"module.ts": `
|
|
export default 1;
|
|
`,
|
|
"routes/index.ts": `
|
|
import { default as y } from '../module';
|
|
export default function(req, meta) {
|
|
return new Response('Value: ' + y);
|
|
}
|
|
`,
|
|
},
|
|
async test(dev) {
|
|
await dev.fetch("/").equals("Value: 1");
|
|
await dev.patch("module.ts", {
|
|
find: "1",
|
|
replace: "2",
|
|
});
|
|
await dev.fetch("/").equals("Value: 2");
|
|
},
|
|
});
|
|
devTest("export { default as y }", {
|
|
framework: minimalFramework,
|
|
files: {
|
|
"module.ts": `
|
|
export default 1;
|
|
`,
|
|
"middle.ts": `
|
|
export { default as y } from './module';
|
|
`,
|
|
"routes/index.ts": `
|
|
import { y } from '../middle';
|
|
export default function(req, meta) {
|
|
return new Response('Value: ' + y);
|
|
}
|
|
`,
|
|
},
|
|
async test(dev) {
|
|
await dev.fetch("/").equals("Value: 1");
|
|
await dev.patch("module.ts", {
|
|
find: "1",
|
|
replace: "2",
|
|
});
|
|
await dev.fetch("/").equals("Value: 2");
|
|
},
|
|
});
|
|
devTest("export * as namespace", {
|
|
files: {
|
|
"index.html": emptyHtmlFile({
|
|
scripts: ["index.ts"],
|
|
}),
|
|
"index.ts": `
|
|
import { ns as renamed } from './module';
|
|
if (typeof renamed !== 'object') throw new Error('renamed should be an object');
|
|
if (renamed.x !== 1) throw new Error('renamed.x should be 1');
|
|
if (renamed.y !== 2) throw new Error('renamed.y should be 2');
|
|
console.log('PASS');
|
|
`,
|
|
"module.ts": `
|
|
export * as ns from './module2';
|
|
`,
|
|
"module2.ts": `
|
|
export const x = 1;
|
|
export const y = 2;
|
|
export const ns = "FAIL";
|
|
`,
|
|
},
|
|
async test(dev) {
|
|
await using c = await dev.client();
|
|
await c.expectMessage("PASS");
|
|
},
|
|
});
|
|
devTest("ESM <-> CJS sync", {
|
|
files: {
|
|
"index.html": emptyHtmlFile({
|
|
scripts: ["index.ts"],
|
|
}),
|
|
"index.ts": `
|
|
const mod = require('./esm');
|
|
if (!mod.__esModule) throw new Error('mod.__esModule should be set');
|
|
console.log('PASS');
|
|
`,
|
|
"esm.ts": `
|
|
export const x = 1;
|
|
`,
|
|
},
|
|
async test(dev) {
|
|
await using c = await dev.client();
|
|
await c.expectMessage("PASS");
|
|
},
|
|
});
|
|
devTest("ESM <-> CJS (async)", {
|
|
files: {
|
|
"index.html": emptyHtmlFile({
|
|
scripts: ["index.ts"],
|
|
}),
|
|
"index.ts": `
|
|
const esmImport = await import('./esm'); // TODO: implement sync ESM
|
|
const mod = require('./esm');
|
|
if (!mod.__esModule) throw new Error('mod.__esModule should be set');
|
|
if (esmImport.x !== mod.x) throw new Error('esmImport.x should be equal to mod.x');
|
|
if ('__esModule' in esmImport) throw new Error('esmImport.__esModule should be unset');
|
|
console.log('PASS');
|
|
`,
|
|
"esm.ts": `
|
|
export const x = 1;
|
|
`,
|
|
},
|
|
async test(dev) {
|
|
await using c = await dev.client();
|
|
await c.expectMessage("PASS");
|
|
},
|
|
});
|
|
devTest("cannot require a module with top level await", {
|
|
files: {
|
|
"index.html": emptyHtmlFile({
|
|
scripts: ["index.ts"],
|
|
}),
|
|
"index.ts": `
|
|
const mod = require('./esm');
|
|
console.log('FAIL');
|
|
`,
|
|
"esm.ts": `
|
|
console.log("FAIL");
|
|
import { hello } from './dir';
|
|
hello;
|
|
`,
|
|
"dir/index.ts": `
|
|
import './async';
|
|
`,
|
|
"dir/async.ts": `
|
|
console.log("FAIL");
|
|
await 1;
|
|
`,
|
|
},
|
|
async test(dev) {
|
|
await using c = await dev.client("/", {
|
|
errors: [
|
|
`error: Cannot require "esm.ts" because "dir/async.ts" uses top-level await, but 'require' is a synchronous operation.`,
|
|
],
|
|
});
|
|
},
|
|
});
|
|
devTest("function that is assigned to should become a live binding", {
|
|
files: {
|
|
"index.html": emptyHtmlFile({
|
|
scripts: ["index.ts"],
|
|
}),
|
|
"index.ts": `
|
|
// 1. basic test
|
|
import { live, change } from "./live.js";
|
|
{
|
|
if (live() !== 1) throw new Error("live() should be 1");
|
|
change();
|
|
if (live() !== 2) throw new Error("live() should be 2");
|
|
}
|
|
|
|
// 2. integration test with @babel/runtime
|
|
import inheritsLoose from "./inheritsLoose.js";
|
|
{
|
|
function A() {}
|
|
function B() {}
|
|
inheritsLoose(B, A);
|
|
}
|
|
|
|
console.log('PASS');
|
|
`,
|
|
"live.js": `
|
|
export function live() {
|
|
return 1;
|
|
}
|
|
export function change() {
|
|
live = function() {
|
|
return 2;
|
|
}
|
|
}
|
|
`,
|
|
"inheritsLoose.js": `
|
|
import setPrototypeOf from "./setPrototypeOf.js";
|
|
function _inheritsLoose(t, o) {
|
|
t.prototype = Object.create(o.prototype), t.prototype.constructor = t, setPrototypeOf(t, o);
|
|
}
|
|
export { _inheritsLoose as default };
|
|
`,
|
|
"setPrototypeOf.js": `
|
|
function _setPrototypeOf(t, e) {
|
|
return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) {
|
|
return t.__proto__ = e, t;
|
|
}, _setPrototypeOf(t, e);
|
|
}
|
|
export { _setPrototypeOf as default };
|
|
`,
|
|
},
|
|
async test(dev) {
|
|
await using c = await dev.client();
|
|
await c.expectMessage("PASS");
|
|
},
|
|
});
|
|
|
|
devTest("browser field is used", {
|
|
files: {
|
|
// Ensure the package.json gets parsed before the HTML is bundled.
|
|
"bunfig.toml": `
|
|
preload = [
|
|
"axios/lib/utils.js",
|
|
]
|
|
`,
|
|
"index.html": emptyHtmlFile({
|
|
scripts: ["index.ts"],
|
|
}),
|
|
"node_modules/axios/package.json": JSON.stringify({
|
|
name: "axios",
|
|
version: "1.0.0",
|
|
browser: {
|
|
"./lib/utils.js": "./lib/utils.browser.js",
|
|
},
|
|
}),
|
|
"node_modules/axios/lib/utils.js": `
|
|
export default "FAIL";
|
|
`,
|
|
"node_modules/axios/lib/utils.browser.js": `
|
|
export default "PASS";
|
|
`,
|
|
"index.ts": `
|
|
import axios from "axios/lib/utils.js";
|
|
console.log(axios);
|
|
`,
|
|
},
|
|
async test(dev) {
|
|
await using c = await dev.client();
|
|
await c.expectMessage("PASS");
|
|
},
|
|
});
|