diff options
Diffstat (limited to 'test/bundler/api.test.ts')
-rw-r--r-- | test/bundler/api.test.ts | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/test/bundler/api.test.ts b/test/bundler/api.test.ts new file mode 100644 index 000000000..dee37dad5 --- /dev/null +++ b/test/bundler/api.test.ts @@ -0,0 +1,265 @@ +import { test, expect, describe } from "bun:test"; +import { readFileSync } from "fs"; +import { bunEnv, bunExe } from "harness"; +import { join } from "path"; + +describe("Bun.build", () => { + test("passing undefined doesnt segfault", () => { + try { + // @ts-ignore + Bun.build(); + } catch (error) { + return; + } + throw new Error("should have thrown"); + }); + + test("invalid options throws", async () => { + expect(() => Bun.build({} as any)).toThrow(); + expect(() => + Bun.build({ + entrypoints: [], + } as any), + ).toThrow(); + expect(() => + Bun.build({ + entrypoints: ["hello"], + format: "invalid", + } as any), + ).toThrow(); + expect(() => + Bun.build({ + entrypoints: ["hello"], + target: "invalid", + } as any), + ).toThrow(); + expect(() => + Bun.build({ + entrypoints: ["hello"], + sourcemap: "invalid", + } as any), + ).toThrow(); + }); + + test("returns errors properly", async () => { + Bun.gc(true); + const build = await Bun.build({ + entrypoints: [join(import.meta.dir, "does-not-exist.ts")], + }); + expect(build.outputs).toHaveLength(0); + expect(build.logs).toHaveLength(1); + expect(build.logs[0]).toBeInstanceOf(BuildMessage); + expect(build.logs[0].message).toMatch(/ModuleNotFound/); + expect(build.logs[0].name).toBe("BuildMessage"); + expect(build.logs[0].position).toEqual(null); + expect(build.logs[0].level).toEqual("error"); + Bun.gc(true); + }); + + test("returns output files", async () => { + Bun.gc(true); + const build = await Bun.build({ + entrypoints: [join(import.meta.dir, "./fixtures/trivial/index.js")], + }); + expect(build.outputs).toHaveLength(1); + expect(build.logs).toHaveLength(0); + Bun.gc(true); + }); + + test("rebuilding busts the directory entries cache", () => { + Bun.gc(true); + const { exitCode, stderr } = Bun.spawnSync({ + cmd: [bunExe(), join(import.meta.dir, "bundler-reloader-script.ts")], + env: bunEnv, + stderr: "pipe", + stdout: "inherit", + }); + if (stderr.byteLength > 0) { + throw new Error(stderr.toString()); + } + expect(exitCode).toBe(0); + Bun.gc(true); + }); + + test("outdir + reading out blobs works", async () => { + Bun.gc(true); + const x = await Bun.build({ + entrypoints: [join(import.meta.dir, "./fixtures/trivial/index.js")], + outdir: "/tmp/bun-build-test-read-out", + }); + expect(await x.outputs.values().next().value?.text()).toMatchSnapshot(); + Bun.gc(true); + }); + + test("BuildArtifact properties", async () => { + Bun.gc(true); + const x = await Bun.build({ + entrypoints: [join(import.meta.dir, "./fixtures/trivial/index.js")], + }); + const [blob] = x.outputs; + expect(blob).toBeTruthy(); + expect(blob.type).toBe("text/javascript;charset=utf-8"); + expect(blob.size).toBeGreaterThan(1); + expect(blob.path).toBe("./index.js"); + expect(blob.hash).toBeTruthy(); + expect(blob.hash).toMatchSnapshot("hash"); + expect(blob.kind).toBe("entry-point"); + expect(blob.loader).toBe("jsx"); + expect(blob.sourcemap).toBe(null); + Bun.gc(true); + }); + + test("BuildArtifact properties + entry.naming", async () => { + Bun.gc(true); + const x = await Bun.build({ + entrypoints: [join(import.meta.dir, "./fixtures/trivial/index.js")], + naming: { + entry: "hello", + }, + }); + const [blob] = x.outputs; + expect(blob).toBeTruthy(); + expect(blob.type).toBe("text/javascript;charset=utf-8"); + expect(blob.size).toBeGreaterThan(1); + expect(blob.path).toBe("./hello"); + expect(blob.hash).toBeTruthy(); + expect(blob.hash).toMatchSnapshot("hash"); + expect(blob.kind).toBe("entry-point"); + expect(blob.loader).toBe("jsx"); + expect(blob.sourcemap).toBe(null); + Bun.gc(true); + }); + + test("BuildArtifact properties sourcemap", async () => { + Bun.gc(true); + const x = await Bun.build({ + entrypoints: [join(import.meta.dir, "./fixtures/trivial/index.js")], + sourcemap: "external", + }); + const [blob, map] = x.outputs; + expect(blob.type).toBe("text/javascript;charset=utf-8"); + expect(blob.size).toBeGreaterThan(1); + expect(blob.path).toBe("./index.js"); + expect(blob.hash).toBeTruthy(); + expect(blob.hash).toMatchSnapshot("hash index.js"); + expect(blob.kind).toBe("entry-point"); + expect(blob.loader).toBe("jsx"); + expect(blob.sourcemap).toBe(map); + + expect(map.type).toBe("application/json;charset=utf-8"); + expect(map.size).toBeGreaterThan(1); + expect(map.path).toBe("./index.js.map"); + expect(map.hash).toBeTruthy(); + expect(map.hash).toMatchSnapshot("hash index.js.map"); + expect(map.kind).toBe("sourcemap"); + expect(map.loader).toBe("file"); + expect(map.sourcemap).toBe(null); + Bun.gc(true); + }); + + // test("BuildArtifact properties splitting", async () => { + // Bun.gc(true); + // const x = await Bun.build({ + // entrypoints: [join(import.meta.dir, "./fixtures/trivial/index.js")], + // splitting: true, + // }); + // expect(x.outputs).toHaveLength(2); + // const [indexBlob, chunkBlob] = x.outputs; + + // expect(indexBlob).toBeTruthy(); + // expect(indexBlob.type).toBe("text/javascript;charset=utf-8"); + // expect(indexBlob.size).toBeGreaterThan(1); + // expect(indexBlob.path).toBe("/index.js"); + // expect(indexBlob.hash).toBeTruthy(); + // expect(indexBlob.hash).toMatchSnapshot("hash index.js"); + // expect(indexBlob.kind).toBe("entry-point"); + // expect(indexBlob.loader).toBe("jsx"); + // expect(indexBlob.sourcemap).toBe(null); + + // expect(chunkBlob).toBeTruthy(); + // expect(chunkBlob.type).toBe("text/javascript;charset=utf-8"); + // expect(chunkBlob.size).toBeGreaterThan(1); + // expect(chunkBlob.path).toBe(`/foo-${chunkBlob.hash}.js`); + // expect(chunkBlob.hash).toBeTruthy(); + // expect(chunkBlob.hash).toMatchSnapshot("hash foo.js"); + // expect(chunkBlob.kind).toBe("chunk"); + // expect(chunkBlob.loader).toBe("jsx"); + // expect(chunkBlob.sourcemap).toBe(null); + // Bun.gc(true); + // }); + + test("Bun.write(BuildArtifact)", async () => { + Bun.gc(true); + const x = await Bun.build({ + entrypoints: [join(import.meta.dir, "./fixtures/trivial/index.js")], + }); + Bun.write("/tmp/bun-build-test-write.js", x.outputs[0]); + expect(readFileSync("/tmp/bun-build-test-write.js", "utf-8")).toMatchSnapshot(); + Bun.gc(true); + }); + + test("new Response(BuildArtifact) sets content type", async () => { + const x = await Bun.build({ + entrypoints: [join(import.meta.dir, "./fixtures/trivial/index.js")], + }); + const response = new Response(x.outputs[0]); + expect(response.headers.get("content-type")).toBe("text/javascript;charset=utf-8"); + expect(await response.text()).toMatchSnapshot("response text"); + }); + + test("new Response(BuildArtifact) sets etag", async () => { + const x = await Bun.build({ + entrypoints: [join(import.meta.dir, "./fixtures/trivial/index.js")], + }); + const response = new Response(x.outputs[0]); + expect(response.headers.get("etag")).toBeTruthy(); + expect(response.headers.get("etag")).toMatchSnapshot("content-etag"); + }); + + // test("BuildArtifact with assets", async () => { + // const x = await Bun.build({ + // entrypoints: [join(import.meta.dir, "./fixtures/with-assets/index.js")], + // loader: { + // ".blob": "file", + // ".png": "file", + // }, + // }); + // console.log(x); + // const [blob, asset] = x.outputs; + // expect(blob).toBeTruthy(); + // expect(blob instanceof Blob).toBe(true); + // expect(blob.type).toBe("text/javascript;charset=utf-8"); + // expect(blob.size).toBeGreaterThan(1); + // expect(blob.path).toBe("/index.js"); + // expect(blob.hash).toBeTruthy(); + // expect(blob.hash).toMatchSnapshot(); + // expect(blob.kind).toBe("entry-point"); + // expect(blob.loader).toBe("jsx"); + // expect(blob.sourcemap).toBe(null); + // throw new Error("test was not fully written"); + // }); + + test("errors are returned as an array", async () => { + const x = await Bun.build({ + entrypoints: [join(import.meta.dir, "does-not-exist.ts")], + }); + expect(x.success).toBe(false); + expect(x.logs).toHaveLength(1); + expect(x.logs[0].message).toMatch(/ModuleNotFound/); + expect(x.logs[0].name).toBe("BuildMessage"); + expect(x.logs[0].position).toEqual(null); + }); + + test("warnings do not fail a build", async () => { + const x = await Bun.build({ + entrypoints: [join(import.meta.dir, "./fixtures/jsx-warning/index.jsx")], + }); + expect(x.success).toBe(true); + expect(x.logs).toHaveLength(1); + expect(x.logs[0].message).toBe( + '"key" prop before a {...spread} is deprecated in JSX. Falling back to classic runtime.', + ); + expect(x.logs[0].name).toBe("BuildMessage"); + expect(x.logs[0].position).toBeTruthy(); + }); +}); |