Skip to content
DomainKit
Esc
navigateopen⌘Jpreview
On this page

Test against the seam

Drive the real services with in-memory fakes, render UI against a recording transport, and check your own implementations with the conformance runners.

domainkit/testing exists so host tests never stub global fetch. Every fake is a real implementation of a seam the lifecycle already goes through, so the code under test is the code that ships.

A fake provider

/**
 * A provider definition over in-memory zones, with a token method and optionally OAuth. Give each
 * test its own zone: `Testing.provider` registers zones in one process-wide table that
 * `Testing.resolver` reads.
 */
export const fake = Testing.provider({
  zones: ["plans.example.com"],
  records: [
    {
      zone: "plans.example.com",
      record: DnsRecord.txt({ name: "_acme.plans.example.com", value: "acme-verify=7f3a" }),
    },
  ],
  oauth: true,
});

Seed records to produce Noop and Conflict operations, set failWrite to exercise a partial receipt, and set oauth to add the interactive method beside the token one.

/** Exercise a partial receipt by failing one write, and a mismatch by seeding the wrong record. */
export const failsTheSecondWrite = Testing.provider({
  zones: ["partial.example.com"],
  failWrite: (index) => index === 1,
});

One layer for the lifecycle

/** One layer for the whole lifecycle: memory Storage, a throwaway custody key, and the fake pool. */
export const TestLive = DomainKit.layerMemory({
  providers: [fake],
  resolver: Testing.resolver(),
});
/** A host test drives the real services; nothing stubs global `fetch`. */
export const plansTheSecondRecord = Effect.gen(function* () {
  yield* Connect.start({
    provider: fake.id,
    method: Connect.Method.token("test-token"),
    domain: "app.plans.example.com",
  });
  const plan = yield* Provision.plan({
    domain: "app.plans.example.com",
    requirements: [
      DnsRecord.cname({ name: "app.plans.example.com", target: "edge.acme.dev" }),
      DnsRecord.txt({ name: "_acme.plans.example.com", value: "acme-verify=7f3a" }),
    ],
  });
  return plan.operations.map((operation) => operation._tag); // ["Create", "Noop"]
}).pipe(Effect.provideService(Principal.Service, Testing.principal), Effect.provide(TestLive));

DomainKit.layerMemory adds Storage.layerMemory and a throwaway custody key, so a test needs no database and no key material.

Public DNS answers

/** Answer public DNS from a table instead of the fake provider's own zones. */
export const StaleResolver = Testing.resolver([
  {
    name: "app.example.com",
    records: [DnsRecord.cname({ name: "app.example.com", target: "old.acme.dev" })],
  },
]);

export const seesTheOldTarget = Verify.observe({ domain: "app.example.com" });

Passing a table replaces the fake providers’ zones entirely, which is how you test a requirement that is satisfied at the provider and still missing in public DNS.

UI tests

/**
 * The whole lifecycle behind a `Transport.Interface`, over an in-memory server, recording every
 * call. Declare fewer capabilities to render a UI against a host that mounted only part of the
 * group.
 */
export const transport = Testing.transport({ capabilities: ["connection", "provisioning"] });

export const callsSoFar = () => transport.calls.map((call) => call.method);

Testing.transport mounts domainkit/server over memory storage and a fake provider, then points Transport.fromFetch at that handler. Rendering <DomainKit.Root transport={transport}> gives a component tree that connects, plans, approves, applies, observes, and cleans up for real.

transport.calls records { method, input } for every call, so a test can assert that approving sent the operation ids the customer selected. Declaring fewer capabilities renders the UI against a host that mounted only part of the route group.

Conformance

/**
 * Register every `Storage` invariant with your test runner: tenant isolation, apply leases,
 * exactly-once continuations, revocation recovery, and lock semantics. Both shipped
 * implementations pass this suite, so a host can swap them without a behaviour change.
 */
export const registerStorageCases = (
  layer: Layer.Layer<Storage.Service, unknown>,
  it: (name: string, run: () => Promise<void>) => void,
) => Testing.conformance.storage(layer, { it });
/**
 * A provider author runs this against a real account before shipping: create and read back, exact
 * no-op, conflict, stale plan, and partial apply, all through the same services hosts use. Every
 * record it creates carries the prefix and is removed again.
 */
export const check = (definition: Provider.Definition, token: string, zone: string) =>
  Testing.conformance.provider(
    definition,
    { secret: Redacted.make(token), context: { apiKey: token } },
    zone,
    { prefix: "acme-conformance" },
  );

export const run = (definition: Provider.Definition, token: string) =>
  Effect.runPromise(check(definition, token, "example.com"));

The storage runner takes a layer and registers one case per invariant with your test runner. The provider runner writes to a real account and cleans up after itself, so it belongs in an opt-in suite rather than in CI.

The domainkit/testing reference lists every fake and its options.

Was this page helpful?