FabricFabricSDK

Testing utilities

Write unit tests against your fabric instance without scaffolding the runtime each time.

Subpath: @fabricorg/integrations/testing.

Quick example

import { describe, it, expect } from 'vitest';
import { slack } from '@fabricorg/integrations/plugins';
import {
  createTestFabric,
  mockFetcher,
  webhookFixture,
  expectPath,
} from '@fabricorg/integrations/testing';

describe('our slack notifier', () => {
  it('posts to the right channel', async () => {
    const fetcher = mockFetcher((req) => {
      if (req.url.endsWith('/chat.postMessage')) {
        return { body: { ok: true, channel: 'C1', ts: '0.0' } };
      }
      return { status: 404, body: { error: 'not_found' } };
    });

    const fabric = createTestFabric([
      slack({ botToken: 'xoxb-test', fetcher }),
    ]);

    await fabric.slack.api.messages.send({ channel: 'C1', text: 'hi' });

    expect(fetcher.calls).toHaveLength(1);
    expect(fetcher.calls[0].headers.Authorization).toBe('Bearer xoxb-test');
  });
});

API

createTestFabric(plugins)

Wraps createFabric with sensible test defaults. Same code path the runtime takes — hooks, permissions, key resolution, error handlers all run identically.

mockFetcher(handler)

Typed factory for the fetcher option each plugin accepts. The handler can return a real Response or an object shorthand:

const fetcher = mockFetcher((req) => {
  if (req.method === 'GET') return { body: { ok: true } };
  return new Response('explicit', { status: 201 });
});
PropertyDescription
fetcher.callsArray of every captured request (url, method, headers, body)
fetcher.reset()Clear the calls log without recreating

webhookFixture(input)

Build a normalized WebhookRequest for processWebhook tests. Defaults to POST + application/json so test bodies stay focused on payloads.

const fixture = webhookFixture({
  url: 'https://hooks.test/slack',
  headers: { 'x-slack-signature': 'v0=abc123' },
  body: { type: 'event_callback', event: { type: 'message', text: 'hi' } },
});

expectPath(fabric, dotPath)

Walk a dot-path, return the leaf or undefined. Use for assertions against the bound fabric surface:

expect(expectPath(fabric, 'slack.api.users.list')).toBeTypeOf('function');
expect(expectPath(fabric, 'stripe.api.charges.create')).toBeTypeOf('function');

Re-exports

To keep test files focused, the /testing subpath also re-exports the four in-memory store classes so you can construct isolated stores per test:

Re-exportFrom
InMemoryKeyStore, KeyStoreauth/key-store
InMemoryEntityStore, EntityStore, EntityRecorddb/entity-store
InMemoryPermissionStore, PermissionStore, PermissionRecord, PermissionStatus, CreatePermissionInputpermissions/store
InMemoryEventLogger, EventLogger, EventLogRecordevents

Each is a fresh instance — perfect for beforeEach setup.