Guides

Test your code

Run your code against an in-memory forge or recorded responses.

forges ships two test helpers. forges/fake is an in-memory forge. forges/testing replays recorded HTTP responses. Leave both out of production bundles.

Use the in-memory forge

fake() has the full provider API. Seed it, run your code and assert on store. Every write updates store and appends a ForgeEvent to store.events:

import { fake } from 'forges/fake'
import { expect, it } from 'vitest'

it('closes stale issues', async () => {
  const forge = fake({
    seed: {
      threads: [
        {
          repo: 'acme/widgets',
          kind: 'issue',
          title: 'Crash on start',
          labels: ['stale'],
        },
      ],
    },
  })

  await closeStale(forge.create())

  expect(forge.store.events.map(event => event.action)).toEqual([
    'closed',
  ])
})

To match a real forge, pass capabilities with the capabilities of a real provider, or support to override single verbs, for example { 'threads.addLabels': false }. Your fallback paths then run in tests.

Replay recorded responses

fixtureFetch() serves recorded responses to a real provider, so the provider's parsing runs in your test. signDelivery() signs a webhook body with the scheme of a forge:

import { readFile } from 'node:fs/promises'
import { github } from 'forges/github'
import {
  fixtureFetch,
  loadFixtures,
  signDelivery,
} from 'forges/testing'

const { fetch, calls } = fixtureFetch(
  await loadFixtures(new URL('./fixtures/', import.meta.url)),
)
const forge = github({ fetch, webhookSecret: 'secret' }).create()

const body = await readFile(
  new URL('./fixtures/issue-opened.json', import.meta.url),
  'utf8',
)
const headers = await signDelivery('github', body, 'secret', {
  'x-github-event': 'issues',
})
const events = await forge.webhooks.ingest({ headers, body })

calls records every request the provider made, including ones that no fixture matched. Use it to assert that a capability check prevented a write.

Record your own fixtures

recordingFetch() wraps fetch and collects each response as a fixture that you can save and replay. It doesn't record request headers, but it does record URLs and response bodies, which can hold tokens. Pass a redact function to clean each fixture before you save it.

Copyright © 2026