npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@odla-ai/test

v0.1.1

Published

Deterministic, dependency-free test doubles and black-box contract assertions for odla and Cloudflare Worker unit tests; intentionally not a workerd or SQL emulator.

Downloads

60

Readme

@odla-ai/test

Deterministic, dependency-free test doubles for odla applications and Cloudflare Worker unit tests. It is designed for fast agent feedback loops: unexpected network and database calls fail immediately, time advances without sleeping, and Worker responses can be checked as black-box contracts without a test-runner dependency in the published package.

npm view @odla-ai/[email protected] version
npm install --save-dev --save-exact @odla-ai/[email protected]

Require the exact-version lookup to succeed first. An E404 means this release is unavailable; do not substitute an unchecked local or similarly named package.

The runtime is portable across Node 20+, Cloudflare Workers, and modern browser test environments. It imports no cloudflare:* modules. The public types are structural, so doubles can be injected into narrow application interfaces and, at a Worker test boundary, cast to the corresponding Cloudflare binding type.

What is included

  • FetchDouble — strict fetch router and call recorder; unmatched requests throw and never escape to the network.
  • createServiceBinding / runWorker — invoke an exported Worker handler with an inspectable TestExecutionContext.
  • MemoryKV — immediate-consistency, single-process KV subset with text, JSON, bytes, streams, metadata, TTL, deletion, prefix listing, and pagination.
  • D1Stub — a programmable D1-shaped seam that records SQL/bindings and returns scripted rows. It deliberately does not parse or execute SQL.
  • WorkflowStepDouble — deterministic do, sleep, sleepUntil, and waitForEvent primitives with snapshotted named-step replay.
  • ManualClock / createSequenceId — injectable time and stable ids.
  • odla fixtures — realistic bearer/API-key headers, data/admin/registry request builders, environment-safe tenant ids, and provisioning payloads.
  • assertResponse / assertWorkerContract — framework-neutral response and Worker-handler contract assertions.

A black-box Worker contract

import {
  assertWorkerContract,
  odlaAppRequest,
} from "@odla-ai/test";

const worker = {
  async fetch(request: Request, env: Env, ctx: ExecutionContext) {
    // Your real handler.
  },
};

await assertWorkerContract(worker, testEnv, [
  {
    name: "anonymous callers are denied",
    request: new Request("https://db.test/app/notes/query"),
    response: {
      status: 401,
      contentType: /^application\/json/,
      json: { error: { code: "unauthorized" } },
    },
    waitUntil: 0,
  },
  {
    name: "the app key can query",
    request: () => odlaAppRequest("notes", {
      baseUrl: "https://db.test",
      route: "query",
      credential: { kind: "api-key", token: "odla_sk_fixture" },
      json: { notes: {} },
    }),
    response: {
      status: 200,
      headers: { "x-request-id": /^req_/ },
      json: (body) => Array.isArray((body as { notes?: unknown }).notes),
    },
  },
]);

assertResponse clones the response before reading its body, so the original remains available. Contracts can allow multiple statuses, match headers or text with regular expressions, assert that a header is absent with null, and run sync or async body predicates. Failures throw ContractAssertionError with expected and actual fields.

By default Worker contracts drain waitUntil work and surface its rejections. Set drainWaitUntil: false on a case only when testing response-path behavior independently from background work.

Fetch and service-binding doubles

import { createFetchDouble, createServiceBinding, jsonResponse } from "@odla-ai/test";

const upstream = createFetchDouble()
  .when("/v1/items?limit=10", jsonResponse({ items: [] }))
  .when(/\/v1\/items\/[^/]+$/, (request) =>
    jsonResponse({ id: new URL(request.url).pathname.split("/").at(-1) }),
  );

await upstream.fetch("https://api.test/v1/items?limit=10");
upstream.calls[0]!.request; // retained Request clone

const binding = createServiceBinding(otherWorker, otherEnv);
const env = { OTHER_SERVICE: binding };
await appWorker.fetch(request, env, context);
await binding.drain(); // finish every captured waitUntil promise

A string matcher beginning with / matches pathname plus query exactly. Other strings match the complete URL. Routes are checked in insertion order. A static Response is cloned for every call; responders may also be async functions. Use .fallback(...) only when an explicit catch-all is part of the test.

KV with deterministic expiry

import { ManualClock, MemoryKV } from "@odla-ai/test";

const clock = new ManualClock(Date.parse("2026-01-01T00:00:00Z"));
const kv = new MemoryKV(clock);

await kv.put("job:1", JSON.stringify({ state: "queued" }), {
  expirationTtl: 60,
  metadata: { owner: "agent-1" },
});

await kv.get<{ state: string }>("job:1", "json");
await kv.list({ prefix: "job:", limit: 100 });
clock.advance(60_000);
await kv.get("job:1"); // null

Values and metadata are copied at the boundary. Listing is lexicographically stable for an unchanged key set, uses an implementation-specific deterministic cursor, and removes expired entries. Mutating keys between pages can shift the in-memory offset; production cursor behavior is intentionally not simulated. Cache TTL options are accepted for structural convenience but do not simulate edge caches. Empty keys and unknown read modes fail immediately.

Scripted D1, not fake SQL

import { createD1Stub } from "@odla-ai/test";

const rows = new Map([["j1", { id: "j1", state: "queued" }]]);
const db = createD1Stub()
  .when("SELECT id, state FROM jobs WHERE id = ?", (call) => ({
    rows: rows.has(String(call.bindings[0]))
      ? [rows.get(String(call.bindings[0]))!]
      : [],
  }))
  .when(/UPDATE jobs SET state/, (call) => {
    const current = rows.get(String(call.bindings[1]));
    if (current) rows.set(current.id, { ...current, state: String(call.bindings[0]) });
    return { meta: { changes: current ? 1 : 0, rows_written: current ? 1 : 0 } };
  });

const job = await db
  .prepare("SELECT id, state FROM jobs WHERE id = ?")
  .bind("j1")
  .first<{ id: string; state: string }>();

db.calls; // method, exact SQL, and copied bindings

Exact SQL routes normalize whitespace; regex and predicate routes can match a family of statements. Responders may close over Maps or domain repositories to provide intentional state. Unknown statements throw D1UnexpectedQueryError. prepare, bind, first, all, run, raw, batch, exec, and a synthetic session bookmark are present. dump() fails loudly.

For positional raw fixtures, supply columns when testing raw({ columnNames: true }); row-width mismatches fail closed.

This design avoids a dangerous class of false-positive tests. D1Stub does not implement SQL parsing, constraints, transactions, triggers, query planning, SQLite typing, D1 limits, or replica/session consistency. Scripted batch() is sequential and not atomic. Use Cloudflare's Vitest pool, Miniflare, or workerd for any behavior that depends on those properties.

Workflow orchestration

import { ManualClock, createWorkflowStep } from "@odla-ai/test";

const clock = new ManualClock(0);
const step = createWorkflowStep({ clock })
  .queueEvent("approved", { reviewer: "human-1" });

const loaded = await step.do("load", { timeout: "1 minute" }, async (ctx) => {
  return { attempt: ctx.attempt };
});
await step.sleep("backoff", "5 seconds"); // clock is now 5000; no wall wait
await step.waitForEvent("approval", { type: "approved", timeout: "1 day" });

Successful names are memoized to model deterministic replay; failures are not. Values are snapshotted when persisted and cloned again on replay, so mutation cannot rewrite a prior checkpoint. clearReplay() clears named checkpoint and attempt caches; queued events and historical records remain available for inspection. Step names, event types, fixed retry settings, timeout values, and the one-year sleep ceiling are checked against the current public Cloudflare limits. Numeric durations are milliseconds; human-readable durations use second through year (not ms strings). The manual parser treats a month as 30 days and a year as 365 days. The callback context exposes the supplied config (or {}), not Cloudflare's runtime-resolved defaults. The double intentionally executes callbacks once: retry timing, rollback, serialization, eviction, resource quotas, and engine replay require a real Cloudflare integration test. waitForEvent consumes a pre-queued event or throws immediately, so a missing fixture cannot hang an autonomous test run.

Authentication fixtures

import { fixtureCredentials, odlaAdminRequest, provisionFixture } from "@odla-ai/test";

const credentials = fixtureCredentials("suite-a");
const request = odlaAdminRequest("apps/notes/schema", {
  credential: { kind: "developer", token: credentials.developerToken },
  json: { version: 2, schema: {} },
});

const enableDevDb = provisionFixture({
  appId: "notes",
  env: "dev",       // tenantId defaults to notes--dev
  service: "db",
  action: "enable",
});

These helpers build the real public header and URL shapes. They do not sign a JWT or bypass a verifier. Use a verifier seam for unit tests; use a real test issuer or workerd integration for cryptographic authentication. No helper emits internal trust headers such as x-odla-trusted. Scoped route builders reject literal or percent-encoded ./.. segments and encoded path separators instead of allowing URL normalization to escape /app, /admin, or /registry.

Fidelity boundary

This package tests application decisions and contracts, not the Cloudflare runtime itself. Its deliberate non-goals are:

  • workerd isolation, subrequest/CPU limits, compatibility dates, WebSockets, cache behavior, alarms, and Durable Object storage semantics;
  • D1/SQLite execution, atomicity, constraints, and migrations;
  • KV replication lag, size limits, minimum TTLs, and production cursor format;
  • Workflow retries, rollback, persistence, engine serialization, scheduler timing, and runtime quotas beyond the explicitly checked names/durations;
  • JWT signatures or odla server authorization policy.

A useful split is: run most handler and package tests here; run a smaller suite with @cloudflare/vitest-pool-workers for runtime/storage semantics; keep live smokes for deployed bindings, DNS, secrets, and IAM. Passing a test double suite must never be described as proof of workerd parity. Cloudflare limits and accepted duration syntax can evolve, so runtime-sensitive paths still belong in that integration suite.

API

The installed package's exported TypeScript declarations/JSDoc are the version-matched reference; the rendered reference is at https://odla.ai/docs/packages/test.