/// import { plugin } from "bun"; import { describe, expect, it } from "bun:test"; import { resolve } from "path"; plugin({ name: "boop beep beep", setup(builder) { builder.onResolve({ filter: /boop/, namespace: "beep" }, () => ({ path: "boop", namespace: "beep", })); builder.onLoad({ filter: /boop/, namespace: "beep" }, () => ({ contents: `export default 42;`, loader: "js", })); }, }); plugin({ name: "an object module", setup(builder) { globalThis.objectModuleResult ||= { hello: "world", }; builder.onResolve({ filter: /.*/, namespace: "obj" }, ({ path }) => ({ path, namespace: "obj", })); builder.onLoad({ filter: /.*/, namespace: "obj" }, () => ({ exports: globalThis.objectModuleResult, loader: "object", })); }, }); plugin({ name: "failing loader", setup(builder) { globalThis.failingObject ||= {}; builder.onResolve({ filter: /.*/, namespace: "fail" }, ({ path }) => ({ path, namespace: "fail", })); builder.onLoad({ filter: /.*/, namespace: "fail" }, () => globalThis.failingObject); }, }); plugin({ name: "delayed loader", setup(builder) { globalThis.laterCode = ""; builder.onResolve({ filter: /.*/, namespace: "delay" }, ({ path }) => ({ namespace: "delay", path, })); builder.onLoad({ filter: /.*/, namespace: "delay" }, ({ path }) => ({ contents: (globalThis.laterCode ||= ""), loader: "js", })); }, }); plugin({ name: "async onLoad", setup(builder) { globalThis.asyncOnLoad = ""; builder.onResolve({ filter: /.*/, namespace: "async" }, ({ path }) => ({ namespace: "async", path, })); builder.onLoad({ filter: /.*/, namespace: "async" }, async ({ path }) => { await Promise.resolve(1); return new Promise((resolve, reject) => { setTimeout(() => { resolve({ contents: (globalThis.asyncOnLoad ||= ""), loader: "js", }); }, 1); }); }); builder.onResolve({ filter: /.*/, namespace: "async-obj" }, ({ path }) => ({ namespace: "async-obj", path, })); globalThis.asyncObject = {}; builder.onLoad({ filter: /.*/, namespace: "async-obj" }, async ({ path }) => { await Promise.resolve(1); return new Promise((resolve, reject) => { setTimeout(() => { resolve({ exports: (globalThis.asyncObject ||= {}), loader: "object", }); }, 1); }); }); builder.onResolve({ filter: /.*/, namespace: "asyncfail" }, ({ path }) => ({ namespace: "asyncfail", path, })); globalThis.asyncfail = false; builder.onLoad({ filter: /.*/, namespace: "asyncfail" }, async ({ path }) => { await Promise.resolve(1); await 1; throw globalThis.asyncfail; }); builder.onResolve({ filter: /.*/, namespace: "asyncret" }, ({ path }) => ({ namespace: "asyncret", path, })); globalThis.asyncret = 123; builder.onLoad({ filter: /.*/, namespace: "asyncret" }, async ({ path }) => { await 100; await Promise.resolve(10); return await globalThis.asyncret; }); }, }); // This is to test that it works when imported from a separate file import "bun-loader-svelte"; describe("require", () => { it("SSRs `

Hello world!

` with Svelte", () => { const { default: App } = require("./hello.svelte"); const { html } = App.render(); expect(html).toBe("

Hello world!

"); }); it("beep:boop returns 42", () => { const result = require("beep:boop"); expect(result.default).toBe(42); }); it("object module works", () => { const result = require("obj:boop"); expect(result.hello).toBe(objectModuleResult.hello); objectModuleResult.there = true; const result2 = require("obj:boop2"); expect(result.there).toBe(undefined); expect(result2.there).toBe(objectModuleResult.there); expect(result2.there).toBe(true); }); }); describe("dynamic import", () => { it("SSRs `

Hello world!

` with Svelte", async () => { const { default: App }: any = await import("./hello.svelte"); const { html } = App.render(); expect(html).toBe("

Hello world!

"); }); it("beep:boop returns 42", async () => { const result = await import("beep:boop"); expect(result.default).toBe(42); }); it("async:onLoad returns 42", async () => { globalThis.asyncOnLoad = "export default 42;"; const result = await import("async:hello42"); expect(result.default).toBe(42); }); it("async object loader returns 42", async () => { globalThis.asyncObject = { foo: 42, default: 43 }; const result = await import("async-obj:hello42"); expect(result.foo).toBe(42); expect(result.default).toBe(43); }); }); describe("import statement", () => { it("SSRs `

Hello world!

` with Svelte", async () => { laterCode = ` import Hello from "${resolve(import.meta.dir, "hello2.svelte")}"; export default Hello; `; const { default: SvelteApp } = await import("delay:hello2.svelte"); const { html } = SvelteApp.render(); expect(html).toBe("

Hello world!

"); }); }); describe("errors", () => { it("valid loaders work", () => { const validLoaders = ["js", "jsx", "ts", "tsx"]; const inputs = ["export default 'hi';", "export default 'hi';", "export default 'hi';", "export default 'hi';"]; for (let i = 0; i < validLoaders.length; i++) { const loader = validLoaders[i]; const input = inputs[i]; globalThis.failingObject = { contents: input, loader }; expect(require(`fail:my-file-${loader}`).default).toBe("hi"); } }); it("invalid loaders throw", () => { const invalidLoaders = ["blah", "blah2", "blah3", "blah4"]; const inputs = ["body { background: red; }", "

hi

", '{"hi": "there"}', "hi"]; for (let i = 0; i < invalidLoaders.length; i++) { const loader = invalidLoaders[i]; const input = inputs[i]; globalThis.failingObject = { contents: input, loader }; try { require(`fail:my-file-${loader}`); throw -1; } catch (e: any) { if (e === -1) { throw new Error("Expected error"); } expect(e.message.length > 0).toBe(true); } } }); it("transpiler errors work", () => { const invalidLoaders = ["ts"]; const inputs = ["const x: string = -NaNAn../!!;"]; for (let i = 0; i < invalidLoaders.length; i++) { const loader = invalidLoaders[i]; const input = inputs[i]; globalThis.failingObject = { contents: input, loader }; try { require(`fail:my-file-${loader}-3`); throw -1; } catch (e: any) { if (e === -1) { throw new Error("Expected error"); } expect(e.message.length > 0).toBe(true); } } }); it("invalid async return value", async () => { try { globalThis.asyncret = { wat: true }; await import("asyncret:my-file"); throw -1; } catch (e: any) { if (e === -1) { throw new Error("Expected error"); } expect(e.message.length > 0).toBe(true); } }); it("async errors work", async () => { try { globalThis.asyncfail = new Error("async error"); await import("asyncfail:my-file"); throw -1; } catch (e: any) { if (e === -1) { throw new Error("Expected error"); } expect(e.message.length > 0).toBe(true); } }); it("invalid onLoad objects throw", () => { const invalidOnLoadObjects = [ {}, { contents: -1 }, { contents: "", loader: -1 }, { contents: "", loader: "klz", resolveDir: -1 }, ]; for (let i = 0; i < invalidOnLoadObjects.length; i++) { globalThis.failingObject = invalidOnLoadObjects[i]; try { require(`fail:my-file-${i}-2`); throw -1; } catch (e: any) { if (e === -1) { throw new Error("Expected error"); } expect(e.message.length > 0).toBe(true); } } }); it("async transpiler errors work", async () => { try { globalThis.asyncOnLoad = `const x: string = -NaNAn../!!;`; await import("async:fail"); throw -1; } catch (e: any) { if (e === -1) { throw new Error("Expected error"); } expect(e.message.length > 0).toBe(true); } }); });