LocalMode
Core

Testing Utilities

Mock implementations and helpers for testing LocalMode applications

LocalMode provides comprehensive mock utilities for testing applications without loading real ML models. These mocks are deterministic, configurable, and match the exact API of real implementations.

Overview

Testing utilities include:

  • Mock models — Embedding, classification, NER, vision, audio, LLM, and more
  • Mock storage — In-memory storage for unit tests
  • Mock VectorDB — Full-featured database mock
  • Test helpers — Seeded random generators, test vectors, spies

All mocks produce deterministic output when given the same inputs and seed, making tests reproducible.

Mock Embedding Model

The most commonly used mock for testing embedding-related features.

import { createMockEmbeddingModel, embed } from '@localmode/core';

const model = createMockEmbeddingModel({
  dimensions: 384,
  seed: 42, // Deterministic embeddings
});

const { embedding } = await embed({
  model,
  value: 'Hello world',
});

// embedding is a Float32Array of length 384
// Same input + seed always produces same output

Configuration Options

Prop

Type

Testing Failure Handling

const failingModel = createMockEmbeddingModel({
  failCount: 2, // Fail first 2 attempts
  failError: new Error('Model load failed'),
});

// First two calls will fail, third will succeed
try {
  await embed({ model: failingModel, value: 'test' });
} catch (error) {
  console.log('First attempt failed');
}

Tracking Calls

const calls: string[][] = [];

const model = createMockEmbeddingModel({
  onEmbed: ({ values }) => {
    calls.push(values);
  },
});

await embed({ model, value: 'test 1' });
await embed({ model, value: 'test 2' });

console.log(calls); // [['test 1'], ['test 2']]
console.log(model.callCount); // 2

// Reset for next test
model.resetCallCount();

All Mock Models

Mock Storage

In-memory storage that implements the Storage interface:

import { createMockStorage } from '@localmode/core';

const storage = createMockStorage();

await storage.set('key', {
  id: 'doc-1',
  vector: new Float32Array(384),
  metadata: { text: 'Hello' },
});

const doc = await storage.get('key');
const keys = await storage.keys();

// Access internal data for assertions
const allData = storage.getData(); // Map<string, StoredDocument>
console.log(storage.size); // 1

await storage.clear();

Mock VectorDB

Full-featured VectorDB mock with search support:

import { createMockVectorDB, createTestVector } from '@localmode/core';

const db = createMockVectorDB({
  name: 'test-db',
  dimensions: 384,
  delay: 0, // Optional delay for async operations
});

// Add documents
await db.add({
  id: 'doc-1',
  vector: createTestVector(384, 1),
  metadata: { text: 'Hello world', category: 'greeting' },
});

// Search with filters
const results = await db.search(queryVector, {
  k: 10,
  threshold: 0.5,
  filter: { category: 'greeting' },
});

// Filter operators supported: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin
await db.search(queryVector, {
  filter: {
    score: { $gte: 0.8 },
    category: { $in: ['greeting', 'farewell'] },
  },
});

Test Vectors

Create deterministic test vectors:

import { createTestVector, createTestVectors } from '@localmode/core';

// Single vector (same seed = same vector)
const vector1 = createTestVector(384, 42);
const vector2 = createTestVector(384, 42);
// vector1 and vector2 are identical

// Multiple vectors
const vectors = createTestVectors(100, 384, 0);
// 100 vectors with seeds 0-99

// Unnormalized vectors
const rawVector = createTestVector(384, 42, false);

Seeded Random

For reproducible random numbers in tests:

import { createSeededRandom } from '@localmode/core';

const rng = createSeededRandom(42);

const value1 = rng(); // Always same value for seed 42
const value2 = rng(); // Next value in sequence

// Reset by creating new RNG with same seed
const rng2 = createSeededRandom(42);
// rng2() produces same sequence as rng

Test Helpers

Wait for Condition

import { waitFor } from '@localmode/core';

// Wait for async condition
await waitFor(
  () => document.querySelector('.loaded') !== null,
  5000, // timeout
  50 // check interval
);

// Wait for async function
await waitFor(async () => (await db.count()) > 0);

Deferred Promises

import { createDeferred } from '@localmode/core';

const { promise, resolve, reject } = createDeferred<string>();

// Later...
resolve('success');
// or: reject(new Error('failed'));

const result = await promise;

Spy Functions

import { createSpy } from '@localmode/core';

const spy = createSpy<(x: number, y: number) => void>();

spy(1, 2);
spy(3, 4);

console.log(spy.callCount); // 2
console.log(spy.calls); // [[1, 2], [3, 4]]

spy.reset();
console.log(spy.callCount); // 0

Vitest Example

import { describe, it, expect, beforeEach } from 'vitest';
import {
  createMockEmbeddingModel,
  createMockVectorDB,
  createTestVector,
  embed,
} from '@localmode/core';

describe('Semantic Search', () => {
  let model: ReturnType<typeof createMockEmbeddingModel>;
  let db: ReturnType<typeof createMockVectorDB>;

  beforeEach(() => {
    model = createMockEmbeddingModel({ dimensions: 384, seed: 42 });
    db = createMockVectorDB({ dimensions: 384 });
  });

  it('should find similar documents', async () => {
    // Arrange
    await db.add({
      id: 'doc-1',
      vector: createTestVector(384, 1),
      metadata: { text: 'Machine learning is AI' },
    });

    // Act
    const { embedding } = await embed({ model, value: 'What is ML?' });
    const results = await db.search(embedding, { k: 5 });

    // Assert
    expect(results).toHaveLength(1);
    expect(results[0].id).toBe('doc-1');
    expect(results[0].score).toBeGreaterThan(0);
  });

  it('should support AbortSignal', async () => {
    const controller = new AbortController();
    controller.abort();

    await expect(embed({ model, value: 'test', abortSignal: controller.signal })).rejects.toThrow();
  });

  it('should handle failures with retry', async () => {
    const failingModel = createMockEmbeddingModel({
      failCount: 1,
      failError: new Error('Temporary failure'),
    });

    // First call fails, second succeeds
    await expect(embed({ model: failingModel, value: 'test', maxRetries: 0 })).rejects.toThrow(
      'Temporary failure'
    );

    // With retry, should succeed
    const result = await embed({
      model: failingModel,
      value: 'test',
      maxRetries: 2,
    });
    expect(result.embedding).toBeInstanceOf(Float32Array);
  });
});

On this page