summaryrefslogtreecommitdiffhomepage
path: root/packages/host-bin/src/load-external.test.ts
blob: a373e3d45dc8c4de1c2022db273bdfb01c7f8ed6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import type { Logger } from "@dispatch/kernel";
import { describe, expect, it } from "vitest";
import { loadExternalExtensions } from "./load-external.js";

function makeLogger(): Logger {
  const noop = () => {};
  const logger = {
    debug: noop,
    info: noop,
    warn: noop,
    error: noop,
    child: () => logger,
    span: () => {
      throw new Error("not used");
    },
  } as unknown as Logger;
  return logger;
}

describe("loadExternalExtensions", () => {
  it("returns an empty array for no specifiers", async () => {
    expect(await loadExternalExtensions([], makeLogger())).toEqual([]);
  });

  it("loads a real extension module by package name", async () => {
    // auth-apikey is a bundled extension that exports `extension`; we use it as
    // a stand-in for an external module to exercise the dynamic-import path.
    const loaded = await loadExternalExtensions(["@dispatch/auth-apikey"], makeLogger());
    expect(loaded).toHaveLength(1);
    expect(loaded[0]?.manifest.id).toBe("auth-apikey");
  });

  it("skips a specifier that cannot be imported without throwing", async () => {
    const loaded = await loadExternalExtensions(
      ["./does-not-exist-xyz.js", "@dispatch/auth-apikey"],
      makeLogger(),
    );
    // The bad one is skipped; the good one still loads.
    expect(loaded.map((e) => e.manifest.id)).toEqual(["auth-apikey"]);
  });

  it("skips a module that exports no valid extension", async () => {
    // `@dispatch/journal-sink` exports factories but no `extension`.
    const loaded = await loadExternalExtensions(["@dispatch/journal-sink"], makeLogger());
    expect(loaded).toEqual([]);
  });
});