Files
bun.sh/packages/bun-plugin-svelte/test/index.test.ts
2025-05-12 17:12:17 -07:00

158 lines
4.5 KiB
TypeScript

import type { BuildOutput } from "bun";
import { afterAll, afterEach, beforeAll, describe, expect, it } from "bun:test";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { render } from "svelte/server";
import { SveltePlugin } from "../src";
const fixturePath = (...segs: string[]) => path.join(import.meta.dirname, "fixtures", ...segs);
// temp dir that gets deleted after all tests
let outdir: string;
beforeAll(() => {
const prefix = `svelte-test-${Math.random().toString(36).substring(2, 15)}`;
outdir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
});
afterAll(() => {
try {
fs.rmSync(outdir, { recursive: true, force: true });
} catch {
// suppress
}
});
describe("given a hello world component", () => {
const entrypoints = [fixturePath("foo.svelte")];
it("when no options are provided, builds successfully", async () => {
const res = await Bun.build({
entrypoints,
outdir,
plugins: [SveltePlugin()],
});
expect(res.success).toBeTrue();
});
describe("when a custom element is provided", () => {
let res: BuildOutput;
beforeAll(async () => {
res = await Bun.build({
entrypoints,
outdir,
plugins: [SveltePlugin({ compilerOptions: { customElement: true } })],
});
});
it("builds successfully", () => {
expect(res.success).toBeTrue();
});
});
});
describe("when importing `.svelte.ts` files with ESM", () => {
let res: BuildOutput;
beforeAll(async () => {
res = await Bun.build({
entrypoints: [fixturePath("with-modules.svelte")],
outdir,
plugins: [SveltePlugin()],
});
});
it("builds successfully", () => {
expect(res.success).toBeTrue();
});
it(`handles "svelte" export condition`, async () => {
const res = await Bun.build({
entrypoints: [fixturePath("svelte-export-condition.svelte")],
outdir,
plugins: [SveltePlugin()],
});
expect(res.success).toBeTrue();
});
});
describe("when importing `.svelte.ts` files with CJS", () => {
let res: BuildOutput;
beforeAll(async () => {
res = await Bun.build({
entrypoints: [fixturePath("with-cjs.svelte")],
outdir,
plugins: [SveltePlugin()],
});
});
it("builds successfully", () => {
expect(res.success).toBeTrue();
});
it("does not double-wrap the module with function(module, exports, __filename, __dirname)", async () => {
const ts = res.outputs.find(output => output.loader === "ts");
expect(ts).toBeDefined();
const code = await ts!.text();
expect(code).toContain("require_todo_cjs_svelte");
expect(code).toContain("var require_todo_cjs_svelte = __commonJS((exports, module) => {\n");
});
});
describe("Bun.build", () => {
it.each(["node", "bun"] as const)('Generates server-side code when targeting "node" or "bun"', async target => {
const res = await Bun.build({
entrypoints: [fixturePath("foo.svelte")],
outdir,
target,
plugins: [SveltePlugin({ forceSide: "server" })],
});
expect(res.success).toBeTrue();
const componentPath = res.outputs[0].path;
const component = await import(componentPath);
expect(component.default).toBeTypeOf("function");
expect(render(component.default)).toMatchSnapshot(`foo.svelte - server-side (${target})`);
});
it("Generates client-side code when targeting 'browser'", async () => {
const res = await Bun.build({
entrypoints: [fixturePath("foo.svelte")],
outdir,
target: "browser",
});
expect(res.success).toBeTrue();
const componentPath = path.resolve(res.outputs[0].path);
const entrypoint = await res.outputs[0].text();
expect(entrypoint).toMatchSnapshot(`foo.svelte - client-side index`);
expect(await Bun.file(componentPath).text()).toMatchSnapshot(`foo.svelte - client-side`);
});
});
describe("Bun.plugin", () => {
afterEach(() => {
Bun.plugin.clearAll();
});
// test.only("using { forceSide: 'server' } allows for imported components to be SSR'd", async () => {
it("Generates server-side code", async () => {
Bun.plugin(SveltePlugin());
const foo = await import(fixturePath("foo.svelte"));
expect(foo).toBeTypeOf("object");
expect(foo).toHaveProperty("default");
const actual = render(foo.default);
expect(actual).toEqual(
expect.objectContaining({
head: expect.any(String),
body: expect.any(String),
}),
);
expect(actual.head).toMatchSnapshot("foo.svelte - head");
expect(actual.body).toMatchSnapshot("foo.svelte - body");
});
});