Core Building Blocks / Command

Testing

Unit test handlers in isolation or validate the full runtime path with typed mocks.

PURISTA provides a dedicated test runner for commands. Import it from @purista/core and use it to test your command function in isolation with mocked resources.

Handler test with getCommandFunctionTestRunner

Use getCommandFunctionTestRunner to run your command function with injected mock resources:

import { describe, test, expect, vi } from 'vitest'
import { getCommandFunctionTestRunner } from '@purista/core'
import { signUpCommandBuilder } from './signUpCommand.js'

describe('signUp command', () => {
  test('creates a user and returns the userId', async () => {
    const mockDb = { insert: vi.fn().mockResolvedValue({ id: 'user-123' }) }

    const runner = await getCommandFunctionTestRunner(signUpCommandBuilder, {
      resources: { db: mockDb },
    })

    const result = await runner({ email: 'alice@example.com', password: 'secure1234' })

    expect(result.userId).toBeDefined()
    expect(mockDb.insert).toHaveBeenCalledOnce()
  })

  test('rejects disposable email addresses', async () => {
    const mockDb = { insert: vi.fn() }

    const runner = await getCommandFunctionTestRunner(signUpCommandBuilder, {
      resources: { db: mockDb },
    })

    await expect(
      runner({ email: 'bob@tempmail.com', password: 'secure1234' })
    ).rejects.toThrow()
  })
})

The runner:

  • Calls your command function directly with the provided payload
  • Injects the resources, secrets, configs, and states you pass in the options
  • Bypasses the full event bridge pipeline (no validation guards, no transforms)
  • Is fast and deterministic — ideal for unit testing business logic

Which level should you use?

ScenarioRecommended approach
Business logic branchinggetCommandFunctionTestRunner
Resource interaction patternsgetCommandFunctionTestRunner
Schema validation behaviorIntegration/runtime test
Guard hook integrationIntegration/runtime test
Transform hook integrationIntegration/runtime test
Full end-to-end flowIntegration/runtime test

As a rule of thumb: write handler tests first using getCommandFunctionTestRunner. They are fast, deterministic, and cover the majority of your logic. Add integration tests for the pipeline stages (validation, guards, transforms) where multiple components interact.