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

@seedts/testing

v0.1.1

Published

Testing utilities for SeedTS - Snapshot testing, deterministic seeding, and test helpers

Readme

@seedts/testing

Testing utilities for SeedTS - Snapshot testing, deterministic seeding, and test helpers.

Installation

npm install --save-dev @seedts/testing
# or
pnpm add -D @seedts/testing
# or
yarn add --dev @seedts/testing

Features

  • 📸 Snapshot Testing - Create and compare snapshots of seeded data
  • 🎲 Deterministic Seeding - Generate consistent data for reliable tests
  • 🧪 Test Helpers - Utilities for asserting and validating seed results
  • Framework Integration - Jest and Vitest support
  • 🔧 Flexible - Works with any test framework

Quick Start

Snapshot Testing

import { snapshot } from '@seedts/testing';
import { Executor } from '@seedts/core';

test('users seed generates correct data', async () => {
  const executor = new Executor([UsersSeed]);
  const results = await executor.execute();

  const result = await snapshot('users', results[0].data);
  expect(result.pass).toBe(true);
});

Deterministic Seeding

import { withDeterministicContext } from '@seedts/testing';

test('users seed with deterministic data', async () => {
  await withDeterministicContext(async (ctx) => {
    // Math.random and Date.now() are now deterministic
    const executor = new Executor([UsersSeed]);
    const results = await executor.execute();

    // Results will be identical on every run
    expect(results[0].data[0].createdAt).toEqual(new Date('2024-01-01T00:00:00Z'));
  }, { seed: 42 });
});

Snapshot Testing

Creating Snapshots

import { snapshot } from '@seedts/testing';

const result = await snapshot('users', usersData, {
  snapshotDir: '__snapshots__',
  pretty: true
});

if (result.isNew) {
  console.log('New snapshot created:', result.snapshotPath);
}

Comparing Snapshots

const result = await snapshot('users', usersData);

if (!result.pass) {
  console.error('Snapshot mismatch:');
  console.error(result.diff?.diff);
}

Updating Snapshots

// Programmatically
const result = await snapshot('users', usersData, {
  updateSnapshot: true
});

// Via environment variable
// UPDATE_SNAPSHOTS=true npm test

Snapshot Options

interface SnapshotOptions {
  snapshotDir?: string;        // Default: '__snapshots__'
  snapshotName?: string;        // Default: seed name
  pretty?: boolean;             // Default: true
  updateSnapshot?: boolean;     // Default: false
  excludeFields?: string[];     // Fields to exclude
  serializer?: (data: any) => string;  // Custom serializer
  normalize?: (data: any[]) => any[];  // Data normalizer
}

Normalizing Data

import { snapshot, normalizeSeedResult } from '@seedts/testing';

// Remove timestamps and sort by ID for consistent snapshots
const result = await snapshot('users', usersData, {
  normalize: normalizeSeedResult
});

// Custom normalizer
const result = await snapshot('products', productsData, {
  normalize: (data) => data.sort((a, b) => a.sku.localeCompare(b.sku))
});

Excluding Fields

const result = await snapshot('users', usersData, {
  excludeFields: ['createdAt', 'updatedAt', 'id']
});

Deterministic Seeding

Seeded Random Number Generator

import { SeededRandom } from '@seedts/testing';

const random = new SeededRandom(42);

random.next();                    // 0-1 random number
random.int(1, 100);               // Random integer 1-100
random.float(0, 1);               // Random float 0-1
random.pick(['a', 'b', 'c']);     // Random array element
random.shuffle([1, 2, 3]);        // Shuffle array
random.boolean();                 // Random boolean

Deterministic Context

import { createDeterministicContext } from '@seedts/testing';

const ctx = createDeterministicContext({
  seed: 42,
  freezeTime: true,
  timestamp: new Date('2024-01-01T00:00:00Z')
});

// Use in factories
const factory = () => ({
  name: ctx.random.pick(['Alice', 'Bob', 'Charlie']),
  age: ctx.random.int(18, 80),
  createdAt: ctx.getDate(),
  score: ctx.random.float(0, 100)
});

// Always restore after use
ctx.restore();

Deterministic Execution

import { withDeterministicContext } from '@seedts/testing';

await withDeterministicContext(async (ctx) => {
  // Everything inside is deterministic
  const data = Array.from({ length: 10 }, (_, i) => ({
    id: i + 1,
    value: ctx.random.int(1, 100),
    timestamp: ctx.getDate()
  }));

  return data;
}, { seed: 42 });
// Context automatically restored

Deterministic Faker

import { setupDeterministicFaker } from '@seedts/testing';
import { faker } from '@faker-js/faker';

const { restore } = setupDeterministicFaker(42);

// Faker will generate consistent data
const name = faker.person.fullName(); // Always same for seed 42
const email = faker.internet.email(); // Always same for seed 42

restore(); // Restore Math.random

Deterministic Generators

import {
  DeterministicIdGenerator,
  createDeterministicUUID,
  createDeterministicEmail,
  createDeterministicUsername
} from '@seedts/testing';

// ID generator
const idGen = new DeterministicIdGenerator(1);
idGen.next(); // 1
idGen.next(); // 2
idGen.next(); // 3

// UUID generator
const uuidGen = createDeterministicUUID();
uuidGen(); // '00000000-0000-0000-0000-000000000001'
uuidGen(); // '00000000-0000-0000-0000-000000000002'

// Email generator
const emailGen = createDeterministicEmail();
emailGen(); // '[email protected]'
emailGen(); // '[email protected]'

// Username generator
const usernameGen = createDeterministicUsername();
usernameGen(); // 'user0'
usernameGen(); // 'user1'

Test Helpers

Execution Helpers

import { executeSeedsAsMap } from '@seedts/testing';

const executor = new Executor([UsersSeed, PostsSeed]);
const results = await executeSeedsAsMap(executor);

// Access by name
const users = results.get('users');
const posts = results.get('posts');

Assertions

import {
  assertSeedSuccess,
  assertAllSeedsSuccess,
  assertSeedCount,
  assertSeedData
} from '@seedts/testing';

const results = await executor.execute();

// Assert single seed succeeded
assertSeedSuccess(results[0]);

// Assert all seeds succeeded
assertAllSeedsSuccess(results);

// Assert record count
assertSeedCount(results[0], 10);

// Assert data validity
assertSeedData(results[0], (user) => {
  return user.email.includes('@') && user.age >= 18;
});

Data Validation

import { createValidator, assertSeedData } from '@seedts/testing';

const validateUser = createValidator<User>({
  email: (v) => typeof v === 'string' && v.includes('@'),
  age: (v) => typeof v === 'number' && v >= 0 && v <= 150,
  name: (v) => typeof v === 'string' && v.length > 0
});

assertSeedData(usersResult, validateUser);

Performance Assertions

import { assertSeedDuration } from '@seedts/testing';

const results = await executor.execute();

// Assert completed within 1 second
assertSeedDuration(results[0], 1000);

Test Framework Integration

Vitest Integration

import { expect, describe, it } from 'vitest';
import { extendVitestMatchers } from '@seedts/testing/vitest';

// Extend Vitest matchers
extendVitestMatchers(expect);

describe('Seed Snapshots', () => {
  it('users seed matches snapshot', async () => {
    const executor = new Executor([UsersSeed]);
    const results = await executor.execute();

    await expect(results[0].data).toMatchSeedSnapshot('users');
  });
});

Jest Integration

import { expect, describe, it } from '@jest/globals';
import { extendJestMatchers } from '@seedts/testing/jest';

// Extend Jest matchers
extendJestMatchers(expect);

describe('Seed Snapshots', () => {
  it('users seed matches snapshot', async () => {
    const executor = new Executor([UsersSeed]);
    const results = await executor.execute();

    await expect(results[0].data).toMatchSeedSnapshot('users');
  });
});

Updating Snapshots

# Vitest
UPDATE_SNAPSHOTS=true npm test

# Jest
npm test -- --updateSnapshot
# or
npm test -- -u

Complete Examples

Example 1: Snapshot Testing with Deterministic Data

import { describe, it, expect } from 'vitest';
import { Executor } from '@seedts/core';
import { MemoryAdapter } from '@seedts/memory';
import {
  withDeterministicContext,
  snapshot,
  normalizeSeedResult
} from '@seedts/testing';

describe('Users Seed', () => {
  it('generates consistent snapshot', async () => {
    await withDeterministicContext(async () => {
      const adapter = new MemoryAdapter();
      const executor = new Executor([
        (props) => UsersSeed({ ...props, adapter })
      ]);

      const results = await executor.execute();
      const usersData = results[0].data;

      const result = await snapshot('users-deterministic', usersData, {
        normalize: normalizeSeedResult,
        excludeFields: ['id']
      });

      expect(result.pass).toBe(true);
    }, { seed: 42 });
  });
});

Example 2: Testing Multiple Seeds

import {
  Executor,
  executeSeedsAsMap,
  assertAllSeedsSuccess,
  assertSeedCount
} from '@seedts/testing';

describe('All Seeds', () => {
  it('execute successfully', async () => {
    const adapter = new MemoryAdapter();
    const executor = new Executor([
      (props) => UsersSeed({ ...props, adapter }),
      (props) => PostsSeed({ ...props, adapter }),
      (props) => CommentsSeed({ ...props, adapter })
    ]);

    const results = await executeSeedsAsMap(executor);

    // Assert all succeeded
    assertAllSeedsSuccess(Array.from(results.values()));

    // Assert counts
    assertSeedCount(results.get('users')!, 10);
    assertSeedCount(results.get('posts')!, 25);
    assertSeedCount(results.get('comments')!, 100);
  });
});

Example 3: Deterministic Faker Integration

import { setupDeterministicFaker } from '@seedts/testing';
import { faker } from '@faker-js/faker';

describe('Deterministic Faker', () => {
  it('generates consistent data', () => {
    const { restore } = setupDeterministicFaker(42);

    const users = Array.from({ length: 5 }, () => ({
      name: faker.person.fullName(),
      email: faker.internet.email(),
      age: faker.number.int({ min: 18, max: 80 })
    }));

    // These will be the same on every run
    expect(users[0].name).toBe('Expected Name'); // Based on seed 42
    expect(users.length).toBe(5);

    restore();
  });
});

Example 4: Custom Validators

import { createValidator, assertSeedData } from '@seedts/testing';

describe('Data Validation', () => {
  it('validates user data structure', async () => {
    const validateUser = createValidator<User>({
      id: (v) => typeof v === 'number' && v > 0,
      email: (v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v),
      age: (v) => Number.isInteger(v) && v >= 18 && v <= 120,
      name: (v) => typeof v === 'string' && v.length >= 2,
      createdAt: (v) => v instanceof Date || typeof v === 'string'
    });

    const executor = new Executor([UsersSeed]);
    const results = await executor.execute();

    assertSeedData(results[0], validateUser);
  });
});

Example 5: Snapshot Diff Workflow

import { snapshot } from '@seedts/testing';

describe('Snapshot Workflow', () => {
  it('handles snapshot lifecycle', async () => {
    const data = [
      { id: 1, name: 'Alice' },
      { id: 2, name: 'Bob' }
    ];

    // First run - creates snapshot
    let result = await snapshot('test-data', data);
    expect(result.isNew).toBe(true);

    // Second run - matches snapshot
    result = await snapshot('test-data', data);
    expect(result.pass).toBe(true);

    // Modified data - shows diff
    const modifiedData = [
      { id: 1, name: 'Alice' },
      { id: 2, name: 'Charlie' } // Changed from Bob
    ];

    result = await snapshot('test-data', modifiedData);
    expect(result.pass).toBe(false);
    expect(result.diff).toBeDefined();
    console.log(result.diff?.diff);

    // Update snapshot
    result = await snapshot('test-data', modifiedData, {
      updateSnapshot: true
    });
    expect(result.wasUpdated).toBe(true);
  });
});

API Reference

Snapshot Functions

  • snapshot(name, data, options?) - Create or compare snapshot
  • updateSnapshot(name, data, options?) - Update existing snapshot
  • deleteSnapshot(name, options?) - Delete snapshot file
  • listSnapshots(dir?) - List all snapshots
  • clearSnapshots(dir?) - Clear all snapshots
  • createSnapshotAssertion(data, testName, options?) - Create assertion helper
  • shouldUpdateSnapshots() - Check if UPDATE_SNAPSHOTS=true
  • normalizeSeedResult(data) - Normalize data for snapshots

Deterministic Functions

  • SeededRandom(seed?) - Seeded random number generator class
  • DeterministicContext(options?) - Context with frozen time and seeded random
  • createDeterministicContext(options?) - Create deterministic context
  • withDeterministicContext(fn, options?) - Execute with deterministic context
  • setupDeterministicFaker(seed?) - Make Faker.js deterministic
  • DeterministicIdGenerator(start?) - Sequential ID generator
  • createDeterministicUUID() - Deterministic UUID generator
  • createDeterministicEmail() - Deterministic email generator
  • createDeterministicUsername() - Deterministic username generator

Test Helpers

  • executeSeedsAsMap(executor) - Execute and return results as map
  • assertSeedSuccess(result) - Assert seed succeeded
  • assertAllSeedsSuccess(results) - Assert all seeds succeeded
  • getSeedByName(results, name) - Get seed by name
  • assertSeedCount(result, count) - Assert record count
  • assertSeedData(result, predicate) - Assert data validity
  • assertSeedDuration(result, maxMs) - Assert execution time
  • createValidator(rules) - Create data validator
  • waitFor(condition, timeout?, interval?) - Wait for condition
  • deepEqual(a, b) - Deep equality comparison

TypeScript Support

All functions are fully typed:

import type {
  SnapshotOptions,
  SnapshotResult,
  SnapshotDiff,
  DeterministicOptions
} from '@seedts/testing';

License

MIT