Ctrl K
ComunidadGuías…

test/scripts/inline-jsquash-wasm.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { assert, assertStringIncludes } from "@std/assert";
import { expect } from "@std/expect";
import { fromFileUrl } from "@std/path";
import { describe, it as test } from "@std/testing/bdd";
import { FakeTime } from "@std/testing/time";
import type {
  OnLoadArgs,
  OnLoadResult,
  OnResolveArgs,
  OnResolveResult,
  PluginBuild,
} from "esbuild";
import {
  buildModule,
  buildPackageModule,
  buildRemoteModule,
  createPlugin,
  isBytesImport,
} from "#scripts/inline-jsquash-wasm.ts";
import { ASSETS } from "#shared/images/wasm-assets.ts";
import { expectIncludesAll } from "#test-utils/assertions.ts";
import { stubFetch } from "#test-utils/fetch-stub.ts";

type ResolveCallback = Parameters<PluginBuild["onResolve"]>[1];
type LoadCallback = Parameters<PluginBuild["onLoad"]>[1];
type GeneratedModule = {
  jpegDec: () => Uint8Array | Promise<Uint8Array>;
  webpEnc: () => Uint8Array | Promise<Uint8Array>;
};

const importGeneratedModule = (source: string): Promise<GeneratedModule> =>
  import(
    `data:text/javascript;charset=utf-8,${encodeURIComponent(source)}#${crypto.randomUUID()}`
  );

const fakePluginBuild = (): {
  build: PluginBuild;
  loadCallbacks: LoadCallback[];
  resolveCallbacks: ResolveCallback[];
} => {
  const resolveCallbacks: ResolveCallback[] = [];
  const loadCallbacks: LoadCallback[] = [];
  const build = {
    onLoad(
      _options: Parameters<PluginBuild["onLoad"]>[0],
      callback: LoadCallback,
    ) {
      loadCallbacks.push(callback);
    },
    onResolve(
      _options: Parameters<PluginBuild["onResolve"]>[0],
      callback: ResolveCallback,
    ) {
      resolveCallbacks.push(callback);
    },
  } as unknown as PluginBuild;
  return { build, loadCallbacks, resolveCallbacks };
};

describe("isBytesImport", () => {
  test("matches the shared image wasm module and rejects unrelated imports", () => {
    const imagesDir = "/repo/src/shared/images";
    expect(
      isBytesImport(
        "#shared/images/wasm-bytes.ts",
        "/repo/src/shared/images",
        imagesDir,
      ),
    ).toBe(true);
    expect(
      isBytesImport(
        "/repo/src/shared/images/wasm-bytes.ts",
        "/repo/src/shared/images",
        imagesDir,
      ),
    ).toBe(true);
    expect(isBytesImport("./wasm-bytes.ts", imagesDir, imagesDir)).toBe(true);
    expect(
      isBytesImport("./wasm-bytes.ts", "/repo/src/shared/other", imagesDir),
    ).toBe(false);
    expect(isBytesImport("./other.ts", imagesDir, imagesDir)).toBe(false);
  });

  test("normalizes Windows package paths", () => {
    expect(
      isBytesImport(
        ".\\wasm-bytes.ts",
        "C:\\repo\\src\\shared\\images",
        "C:/repo/src/shared/images",
      ),
    ).toBe(true);
  });
});

describe("buildModule", () => {
  test("builds working base64-backed exports from supplied bytes", async () => {
    const source = buildModule(
      [{ exportName: "jpegDec" }, { exportName: "webpEnc" }] as const,
      (asset) =>
        asset.exportName === "jpegDec"
          ? new Uint8Array([1, 2, 3])
          : new Uint8Array([4, 5]),
    );
    expectIncludesAll(source, [
      'const jpegDecBytes = b64ToBytes("AQID");',
      "export const jpegDec = () => jpegDecBytes;",
      'const webpEncBytes = b64ToBytes("BAU=");',
      "export const webpEnc = () => webpEncBytes;",
    ]);
    const generated = await importGeneratedModule(source);
    expect([...(await generated.jpegDec())]).toEqual([1, 2, 3]);
    expect([...(await generated.webpEnc())]).toEqual([4, 5]);
  });

  test("builds the real jSquash module with every expected export", () => {
    const source = buildPackageModule();
    for (const asset of ASSETS) {
      assertStringIncludes(source, `export const ${asset.exportName} = () =>`);
    }
    assert(!source.includes("src/shared/images/wasm"));
  });
});

describe("buildRemoteModule", () => {
  test("builds checked fetch-backed exports for published wasm", async () => {
    const source = buildRemoteModule(
      [{ exportName: "jpegDec" }, { exportName: "webpEnc" }] as const,
      {
        "jpegDec.wasm": "https://assets.example.com/release/jpegDec.wasm",
        "webpEnc.wasm": "https://assets.example.com/release/webpEnc.wasm",
      },
    );
    using fetchStub = stubFetch(new Response(new Uint8Array([4, 5])));
    const generated = await importGeneratedModule(source);
    expect([...(await generated.webpEnc())]).toEqual([4, 5]);
    expect(fetchStub.calls.map((call) => String(call.args[0]))).toEqual([
      "https://assets.example.com/release/webpEnc.wasm",
    ]);
  });

  test("reports the URL and status when published wasm cannot load", async () => {
    const url = "https://assets.example.com/release/webpEnc.wasm";
    const source = buildRemoteModule([{ exportName: "webpEnc" }] as const, {
      "webpEnc.wasm": url,
    });
    using _fetch = stubFetch(new Response(null, { status: 503 }));
    const generated = await importGeneratedModule(source);
    await expect(generated.webpEnc()).rejects.toThrow(
      `Failed to load image codec ${url}: HTTP 503`,
    );
  });

  test("aborts a stalled published wasm request after 30 seconds", async () => {
    using time = new FakeTime();
    const source = buildRemoteModule([{ exportName: "webpEnc" }] as const, {
      "webpEnc.wasm": "https://assets.example.com/release/webpEnc.wasm",
    });
    const originalFetch = globalThis.fetch;
    let error: unknown;
    let settled = false;
    globalThis.fetch = (_input, init) => {
      const signal = init?.signal;
      if (!signal) throw new Error("Expected bounded codec request");
      return new Promise((_resolve, reject) => {
        signal.addEventListener("abort", () => reject(signal.reason), {
          once: true,
        });
      });
    };
    try {
      const generated = await importGeneratedModule(source);
      const observed = Promise.resolve(generated.webpEnc())
        .catch((caught: unknown) => {
          error = caught;
        })
        .finally(() => {
          settled = true;
        });
      await time.tickAsync(29_999);
      expect(settled).toBe(false);
      await time.tickAsync(1);
      await observed;
      if (!(error instanceof DOMException)) {
        throw new Error("Expected codec timeout DOMException");
      }
      expect(error.name).toBe("TimeoutError");
    } finally {
      globalThis.fetch = originalFetch;
    }
  });

  test("rejects a release missing one of its wasm URLs", () => {
    expect(() =>
      buildRemoteModule([{ exportName: "jpegDec" }] as const, {}),
    ).toThrow("jpegDec.wasm");
  });
});

describe("createPlugin", () => {
  test("registers a resolver and loader for the wasm-bytes module", async () => {
    const { build, loadCallbacks, resolveCallbacks } = fakePluginBuild();
    const plugin = createPlugin(() => "export const ok = true;");
    plugin.setup(build);

    const resolved = (await resolveCallbacks[0]!({
      path: "#shared/images/wasm-bytes.ts",
      resolveDir: "/repo/src/shared/images",
    } as OnResolveArgs)) as OnResolveResult;
    expect(resolved).toEqual({
      namespace: "inline-jsquash-wasm",
      path: "#shared/images/wasm-bytes.ts",
    });
    const ignored = await resolveCallbacks[0]!({
      path: "./other.ts",
      resolveDir: "/repo/src/shared/images",
    } as OnResolveArgs);
    expect(ignored).toBe(undefined);
    const imagesDir = fromFileUrl(
      new URL("../../src/shared/images", import.meta.url),
    );
    const relative = await resolveCallbacks[0]!({
      path: "./wasm-bytes.ts",
      resolveDir: imagesDir,
    } as OnResolveArgs);
    expect(relative).toEqual({
      namespace: "inline-jsquash-wasm",
      path: "./wasm-bytes.ts",
    });

    const loaded = (await loadCallbacks[0]!({} as OnLoadArgs)) as OnLoadResult;
    expect(loaded).toEqual({
      contents: "export const ok = true;",
      loader: "ts",
    });
  });
});