Test Kernels

Use testing utilities to write unit tests for custom kernels and middleware.

Test Kernels

Use the @taucad/runtime/testing utilities to write unit tests for custom kernels and middleware. The package provides worker setup, mock runtimes, filesystem seeding, and geometry validation helpers.

Prerequisites

Goal

Write unit tests that exercise kernel logic, middleware hooks, and geometry output using createTestWorker, mock runtimes, and geometry validation helpers.

Steps

1. Import Testing Utilities from @taucad/runtime/testing

All testing helpers are exported from the testing subpath:

import {
  createTestWorker,
  initializeWorkerForTesting,
  seedTestFileSystem,
  clearTestFileSystem,
  createMockLogger,
  createMockFileSystem,
  createMockRuntime,
  createMockRuntimeClient,
  createMockDependencies,
  createMockCreateGeometryHandler,
  createMockGetParametersHandler,
  createSuccessResult,
  createErrorResult,
  createMockInput,
  createMockResponse,
  MockKernelWorker,
  validateGlbData,
  getInspectReport,
  createGeometryTestHelpers,
} from '@taucad/runtime/testing';

2. Use createTestWorker for Kernel Integration Tests

createTestWorker creates and initializes a KernelRuntimeWorker with a kernel definition and seeded files. It uses the production code path:

import { describe, it, expect } from 'vitest';
import { createTestWorker } from '@taucad/runtime/testing';
import replicadDefinition from '@taucad/runtime/kernels/replicad';

describe('Replicad kernel', () => {
  it('creates geometry from TypeScript', async () => {
    const worker = await createTestWorker(replicadDefinition, {
      'main.ts': `
          import { drawRoundedRectangle } from 'replicad';
          export default function main() {
            return drawRoundedRectangle(30, 50, 5).sketchOnPlane('XY').extrude(10);
          }
        `,
    });

    const result = await worker.createGeometry({
      file: { filename: 'main.ts', path: '/projects/test' },
      parameters: {},
    });

    expect(result.success).toBe(true);
    if (result.success) {
      expect(result.data).toHaveLength(1);
    }
  });
});

3. Use initializeWorkerForTesting for Custom Worker Setup

When you need more control over worker initialization (e.g., custom middleware, telemetry):

import { KernelRuntimeWorker } from '@taucad/runtime/worker';
import { initializeWorkerForTesting, seedTestFileSystem } from '@taucad/runtime/testing';

await seedTestFileSystem({
  '/projects/test/main.ts': `export default function main() { return null; }`,
});

const worker = new KernelRuntimeWorker();
await initializeWorkerForTesting(worker, {
  onLog: ({ message }) => console.log(message),
  workerOptions: {
    kernelModules: [
      /* ... */
    ],
  },
});

4. Seed and Clear the Test Filesystem

seedTestFileSystem resets the in-memory filesystem and writes files. clearTestFileSystem resets without seeding:

import { seedTestFileSystem, clearTestFileSystem } from '@taucad/runtime/testing';

beforeEach(async () => {
  await seedTestFileSystem({
    '/projects/test/main.ts': 'export default function main() { return null; }',
    '/projects/test/lib/utils.ts': 'export const x = 1;',
  });
});

afterEach(async () => {
  await clearTestFileSystem();
});

5. Use Mock Utilities for Middleware Tests

For middleware unit tests, use mocks to avoid a real worker:

import {
  createMockLogger,
  createMockFileSystem,
  createMockRuntime,
  createMockInput,
  createMockCreateGeometryHandler,
  createSuccessResult,
  createErrorResult,
} from '@taucad/runtime/testing';

const logger = createMockLogger();
const filesystem = createMockFileSystem({
  existsResult: true,
  readFileResult: (path) => Promise.resolve(new TextEncoder().encode('content')),
});

const runtime = createMockRuntime({
  filesystemOverrides: { existsResult: true },
  dependencies: [],
  dependencyHash: 'abc123',
});

const input = createMockInput({ filePath: '/projects/test/main.ts' });
const handler = createMockCreateGeometryHandler(createSuccessResult([]));

const result = await myMiddleware.wrapCreateGeometry(input, handler, runtime);
expect(result.success).toBe(true);

createMockRuntimeClient() -- Returns a RuntimeClient mock for transport-level testing.

MockKernelWorker -- A worker-shaped mock class for middleware integration tests.

createMockResponse(body, headers?) -- Creates a mock Response object for testing HTTP-dependent kernels (e.g., Zoo).

6. Validate Geometry with validateGlbData and getInspectReport

Use validateGlbData to assert GLB format and getInspectReport for detailed geometry stats:

import {
  validateGlbData,
  getInspectReport,
  extractGltfFromResult,
  getGeometryStatsFromInspect,
  getBoundingBoxFromInspect,
} from '@taucad/runtime/testing';

const result = await worker.createGeometry({
  /* ... */
});
const glb = extractGltfFromResult(result);

expect(glb).toBeDefined();
validateGlbData(glb!);

const report = await getInspectReport(glb!);
const stats = getGeometryStatsFromInspect(report);
console.log(`Vertices: ${stats.vertexCount}, Faces: ${stats.faceCount}, Meshes: ${stats.meshCount}`);

const bbox = getBoundingBoxFromInspect(report);
if (bbox) {
  console.log(`Size: ${bbox.size}, Center: ${bbox.center}`);
}

7. Use createGeometryTestHelpers for Geometry Assertions

createGeometryTestHelpers provides helpers for common geometry assertions:

import { createGeometryTestHelpers, createGeometryVariant } from '@taucad/runtime/testing';

const helpers = createGeometryTestHelpers();

const result = await worker.createGeometry({
  /* ... */
});

await helpers.expectValidGltf(result);
await helpers.expectMeshCount(result, 1);
await helpers.expectVertexCount(result, 24);
await helpers.expectBoundingBoxSize(result, [30, 50, 10], 0.1);

createGeometryVariant(base, overrides) -- Create variant GeometryExpectation objects from a base for parametric testing.

Variations

  • createSuccessResult / createErrorResult: Build CreateGeometryResult values for middleware tests without running a kernel.
  • createMockDependencies(overrides?): Create mock Dependency[] arrays for dependency hash testing.
  • createMockGetParametersHandler(result?): Create a mock handler for wrapGetParameters tests.
  • Skip bundler in tests: Use skipBundler: true in createTestWorker for kernels that do not need bundling.