Test your code
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.