Skip to content

Testing

Problem

Implement testing in a production-friendly way with @vielzeug/wireit while keeping setup and cleanup explicit.

Runnable Example

The snippet below is copy-paste runnable in a TypeScript project with @vielzeug/wireit installed.

Unit test with createTestContainer

ts
import { createTestContainer } from '@vielzeug/wireit';

describe('UserService', () => {
  let container: Container;
  let dispose: () => Promise<void>;
  const mockDb = {
    users: {
      findById: vi.fn(),
      create: vi.fn(),
    },
  };

  beforeEach(() => {
    ({ container, dispose } = createTestContainer(appContainer));
    container.value(DbToken, mockDb, { overwrite: true });
  });

  afterEach(() => dispose());

  it('returns a user by id', async () => {
    mockDb.users.findById.mockResolvedValue({ id: '1', name: 'Alice' });

    const svc = container.get(ServiceToken);
    const user = await svc.getById('1');

    expect(user.name).toBe('Alice');
    expect(mockDb.users.findById).toHaveBeenCalledWith('1');
  });

  it('throws when user not found', async () => {
    mockDb.users.findById.mockResolvedValue(null);

    const svc = container.get(ServiceToken);
    await expect(svc.getById('unknown')).rejects.toThrow('User not found');
  });
});

Temporary mock with container.mock()

ts
it('falls back to cache on DB error', async () => {
  const brokenDb = {
    users: { findById: vi.fn().mockRejectedValue(new Error('DB connection lost')) },
  };

  const result = await container.mock(DbToken, brokenDb, async () => {
    const svc = container.get(ServiceToken);
    return svc.getById('1'); // should return cached value
  });

  expect(result).toBeDefined(); // returned from cache
  // DbToken is fully restored after mock()
});

Testing async providers

ts
it('connects to the database on first get', async () => {
  const mockConnect = vi.fn().mockResolvedValue(undefined);
  const fakeDb = { connect: mockConnect, query: vi.fn() };

  await container.mock(
    DbToken,
    {
      useFactory: async () => {
        await fakeDb.connect();
        return fakeDb;
      },
    },
    async () => {
      const db = await container.getAsync(DbToken);
      expect(mockConnect).toHaveBeenCalledOnce();
    },
  );
});

Expected Output

  • The example runs without type errors in a standard TypeScript setup.
  • The main flow produces the behavior described in the recipe title.

Common Pitfalls

  • Forgetting cleanup/dispose calls can leak listeners or stale state.
  • Skipping explicit typing can hide integration issues until runtime.
  • Not handling error branches makes examples harder to adapt safely.