@upkeel/testing
v0.2.0
Published
Test harness for the Upkeel SDK — an in-memory fake + virtual clock so your test suite can assert expect/fulfill behavior without hitting the network.
Readme
@upkeel/testing
Test harness for @upkeel/sdk.
createTestKit() gives you an in-memory fake of the Upkeel SDK plus a virtual
clock, so you can assert against your instrumentation without a network round
trip. Drop it in wherever your test code would otherwise construct a real
Upkeel instance.
Install
npm install --save-dev @upkeel/testing
# peer: @upkeel/sdkUse
import { createTestKit } from '@upkeel/testing'
import { describe, it, expect } from 'vitest'
describe('my checkout handler', () => {
it('registers a payment expectation that misses when the webhook never arrives', () => {
const { keel, clock, expectations } = createTestKit()
// Run your code with the fake keel instead of the real one.
runCheckout(keel, { orderId: 'ord_1' })
// Nothing has missed yet.
expect(expectations.pending('payment.succeeded')).toHaveLength(1)
// Simulate 31 seconds passing — the `within: '30s'` expectation fires.
clock.advance('31s')
expect(expectations.missed('payment.succeeded')).toBe(true)
})
it('is fulfilled when the webhook lands in time', () => {
const { keel, clock, expectations } = createTestKit()
runCheckout(keel, { orderId: 'ord_2' })
clock.advance('10s')
runStripeWebhook(keel, { orderId: 'ord_2' })
expect(expectations.fulfilled('payment.succeeded')).toBe(true)
expect(expectations.missed('payment.succeeded')).toBe(false)
})
})API
createTestKit(config?)
Returns { keel, clock, expectations, events }.
keel— satisfies the fullUpkeelinterface. Pass it anywhere your production code expects a real client. All methods are synchronous.flush()andclose()are no-ops.clock.now()— current virtual time as an epoch ms.clock.advance(by)— move the clock forward. Accepts a duration string ('30s','5m','2h','1d') or raw ms. Evaluates every pending expectation's deadline synchronously, so misses are visible on the next assertion.clock.set(to)— set the clock to an absoluteDateor ms.expectations.missed(name)— did any expectation with this name miss?expectations.met(name)/fulfilled(name)— did any fulfill?expectations.pending(name?)— still-open expectations (optionally filtered by name).expectations.missCount(name)/fulfillCount(name)— counts.expectations.all()— full history.events.all()— every event emitted, chronological.events.ofType(type)/events.named(name)— filtered views.
TestKitConfig
Optional. All fields default to the values the real SDK uses:
createTestKit({
now: new Date('2026-01-01T00:00:00Z'), // virtual clock starting point
environment: 'test', // echoed into event records
})What it is / isn't
- Is: a way to assert that your code called the right sequence of
keel.expect / keel.fulfill / keel.cancelin the right order with the right options — the same thing you'd assert in a handler unit test. - Is: a way to simulate time passing and see misses fire without
setTimeoutin your tests. - Isn't: an integration test for the Upkeel platform. It doesn't hit
the real API, doesn't exercise retries/batching, doesn't check that
api.upkeel.devaccepts your payload shape. - Isn't: a mock generator or an http interceptor. It replaces the SDK
entirely; if your code imports
Upkeeldirectly, use dependency injection (pass the keel through) so your tests can substitute the fake.
License
MIT. See the Upkeel SDK repo.
