npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@quarry-systems/drift-testing

v0.3.0-alpha.3

Published

Mock services and testing utilities for MCG (Managed Cyclic Graph) workflows.

Readme

@quarry-systems/drift-testing

Mock services and testing utilities for MCG (Managed Cyclic Graph) workflows.

Overview

drift-testing provides a comprehensive mock service framework for testing MCG workflows. It includes:

  • Mock Service Base Classes - Extensible base for creating custom mocks
  • Pre-built Mock Services - Secrets, HTTP, and more
  • Call Tracking - Automatic recording of all method calls
  • Fluent API - Chainable methods for easy test setup
  • Behavior Configuration - Control return values, errors, and delays

Installation

npm install @quarry-systems/drift-testing --save-dev

Quick Start

import { mockSecrets, mockHttp } from '@quarry-systems/drift-testing';
import { createManager } from '@quarry-systems/drift-core';

describe('My Workflow', () => {
  it('should fetch data with secrets', async () => {
    // Create mocks
    const secrets = mockSecrets({
      'API_KEY': 'test-key-123'
    });

    const http = mockHttp()
      .getReturns('/api/data', { items: [] });

    // Use in manager
    const manager = createManager(myGraph, {
      services: {
        secrets: secrets.build(),
        http: http.build()
      }
    });

    await manager.start();

    // Assert calls
    expect(secrets.wasResolveCalledWith('API_KEY')).toBe(true);
    expect(http.wasGetCalledWith('/api/data')).toBe(true);
  });
});

Mock Services

Mock Secrets

import { mockSecrets } from '@quarry-systems/drift-testing';

const secrets = mockSecrets({
  'DB_PASSWORD': 'test-password',
  'API_KEY': 'test-key'
})
  .resolveThrows('INVALID_KEY', new Error('Not found'))
  .resolveDelays(100);

const service = secrets.build();

// Use in tests
await service.resolve('DB_PASSWORD'); // Returns 'test-password'
await service.resolve('INVALID_KEY'); // Throws error

// Assert calls
expect(secrets.getResolveCallCount()).toBe(2);
expect(secrets.wasResolveCalledWith('DB_PASSWORD')).toBe(true);

Mock HTTP

import { mockHttp } from '@quarry-systems/drift-testing';

const http = mockHttp()
  .getReturns('/api/users', { users: [] })
  .postReturns('/api/users', { id: 1, name: 'Test' }, 201)
  .postThrows('/api/invalid', new Error('Validation failed'))
  .withDelay(50);

const service = http.build();

// Use in tests
const response = await service.get('/api/users');
expect(response.status).toBe(200);

// Assert calls
expect(http.getGetCallCount()).toBe(1);
expect(http.wasPostCalledWith('/api/users')).toBe(false);

Mock Store

import { mockStore } from '@quarry-systems/drift-testing';

const store = mockStore({
  'user:123': { name: 'Alice', email: '[email protected]' },
  'config:theme': 'dark'
})
  .getThrows('INVALID_KEY', new Error('Key not found'))
  .withDelay(10);

const service = store.build();

// Use in tests
const user = await service.get('user:123');
expect(user).toEqual({ name: 'Alice', email: '[email protected]' });

await service.set('session:abc', { userId: '123' });
await service.delete('user:123');

// Assert calls
expect(store.wasGetCalledWith('user:123')).toBe(true);
expect(store.getSetCallCount()).toBe(1);

Mock Vectors

import { mockVectors } from '@quarry-systems/drift-testing';

const vectors = mockVectors()
  .queryReturns([0.1, 0.2, 0.3], [
    { id: '1', document: 'Relevant document', score: 0.95 },
    { id: '2', document: 'Another match', score: 0.87 }
  ])
  .insertReturns('doc-1', true)
  .withDelay(50);

const service = vectors.build();

// Use in tests
const results = await service.query([0.1, 0.2, 0.3], { topK: 5 });
expect(results).toHaveLength(2);
expect(results[0].score).toBe(0.95);

await service.insert('doc-1', [0.1, 0.2, 0.3], 'New document');

// Assert calls
expect(vectors.wasQueryCalledWith([0.1, 0.2, 0.3])).toBe(true);
expect(vectors.getInsertCallCount()).toBe(1);

API Reference

MockService Base Class

All mock services extend MockService which provides:

  • getCalls() - Get all recorded calls
  • getCallsFor(method) - Get calls for specific method
  • getCallCount(method) - Get call count for method
  • wasCalled(method) - Check if method was called
  • wasCalledWith(method, ...args) - Check if called with args
  • clearCalls() - Clear call history
  • reset() - Reset calls and behaviors

MockBuilder Base Class

All mock builders extend MockBuilder which provides:

  • build() - Get the mock service instance
  • getCalls() - Get all recorded calls
  • getCallsFor(method) - Get calls for specific method
  • wasCalled(method) - Check if method was called
  • wasCalledWith(method, ...args) - Check if called with args
  • reset() - Reset mock state

Creating Custom Mocks

import { MockService, MockBuilder } from '@quarry-systems/drift-testing';

interface MyService {
  doSomething(arg: string): Promise<string>;
}

class MockMyService extends MockService implements MyService {
  async doSomething(arg: string): Promise<string> {
    return this.executeMock('doSomething', [arg], `result-${arg}`);
  }
}

class MockMyServiceBuilder extends MockBuilder<MyService> {
  constructor() {
    const mockService = new MockMyService();
    super(mockService, mockService);
  }

  doSomethingReturns(value: string): this {
    this.setBehavior('doSomething', { returns: value });
    return this;
  }

  doSomethingThrows(error: Error): this {
    this.setBehavior('doSomething', { throws: error });
    return this;
  }
}

export function mockMyService(): MockMyServiceBuilder {
  return new MockMyServiceBuilder();
}

Recording & Replay

Recording Service Calls

Record real service calls during execution for later replay:

import { createRecorder } from '@quarry-systems/drift-testing';

const recorder = createRecorder();

const manager = createManager(graph, {
  services: recorder.wrapServices({
    secrets: mySecretsService,
    http: myHttpService
  })
});

await manager.start();

// Get the recording
const recording = recorder.getRecording('run-123', 'graph-456');

// Save to file
fs.writeFileSync('recording.json', recorder.toJSON());

Replaying Recorded Calls

Replay recorded calls for deterministic testing:

import { createReplayer, loadRecording } from '@quarry-systems/drift-testing';

// Load recording
const recording = loadRecording(fs.readFileSync('recording.json', 'utf-8'));
const replayer = createReplayer(recording);

const manager = createManager(graph, {
  services: replayer.wrapServices({
    secrets: mySecretsService,
    http: myHttpService
  })
});

await manager.start(); // Uses recorded responses

// Validate replay
const validation = replayer.getValidation();
expect(validation.valid).toBe(true);
expect(validation.callsReplayed).toBe(validation.callsExpected);

Recording Options

const recorder = createRecorder({
  services: ['http'],           // Only record specific services
  excludeMethods: ['ping'],     // Exclude certain methods
  maxCalls: 1000,               // Limit number of calls
  recordErrors: true,           // Record errors (default: true)
  recordDuration: true          // Record call duration (default: true)
});

Replay Options

const replayer = createReplayer(recording, {
  validateSequence: true,       // Validate call order (default: true)
  validateArgs: true,           // Validate arguments (default: true)
  throwOnMismatch: false,       // Throw on validation errors (default: false)
  services: ['http']            // Only replay specific services
});

Recording Format

Recordings are saved as JSON:

{
  "metadata": {
    "version": "1.0.0",
    "timestamp": "2025-12-27T10:00:00Z",
    "runId": "run-123",
    "graphId": "graph-456",
    "totalCalls": 5,
    "totalDuration": 1234,
    "services": ["secrets", "http"]
  },
  "calls": [
    {
      "service": "secrets",
      "method": "resolve",
      "args": ["API_KEY"],
      "result": "test-key-123",
      "timestamp": 1735300800000,
      "duration": 10,
      "sequence": 0
    }
  ]
}

Testing Patterns

Error Simulation

const secrets = mockSecrets()
  .resolveThrows('MISSING_KEY', new Error('Secret not found'));

await expect(service.resolve('MISSING_KEY')).rejects.toThrow('Secret not found');

Delay Simulation

const http = mockHttp()
  .withDelay(1000);

const start = Date.now();
await service.get('/api/slow');
const duration = Date.now() - start;

expect(duration).toBeGreaterThan(900);

Call Verification

const secrets = mockSecrets({ 'KEY': 'value' });
const service = secrets.build();

await service.resolve('KEY');
await service.resolve('KEY');

expect(secrets.getResolveCallCount()).toBe(2);
expect(secrets.wasResolveCalledWith('KEY')).toBe(true);

const calls = secrets.getCallsFor('resolve');
expect(calls[0].args[0]).toBe('KEY');

Record and Replay Workflow

// 1. Record a real execution
const recorder = createRecorder();
const manager = createManager(graph, {
  services: recorder.wrapServices({ secrets, http })
});

await manager.start({ query: 'test' });
fs.writeFileSync('test-run.json', recorder.toJSON());

// 2. Replay in tests (fast and deterministic)
const recording = loadRecording(fs.readFileSync('test-run.json', 'utf-8'));
const replayer = createReplayer(recording);

const testManager = createManager(graph, {
  services: replayer.wrapServices({ secrets, http })
});

await testManager.start({ query: 'test' }); // Instant, uses recorded data

const validation = replayer.getValidation();
expect(validation.valid).toBe(true);

Building

Run nx build drift-testing to build the library.

Running Tests

Run nx test drift-testing or npm test to execute the unit tests via Vitest.

Documentation

For more examples and detailed documentation, see the examples directory.

License

Dual-licensed under AGPL-3.0 and Commercial License. See LICENSE files for details.