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

fabbrica

v1.0.0

Published

TypeScript library to create object factories that do mocking and testing a breeze

Readme

fabbrica is TypeScript and JavaScript library for creating object factories that will make your mocking and testing a breeze!

Key features:

  • Extensible, data source agnostic
  • Lazy-evaluated
  • Supports various states (traits), extending and picking
  • Minimal, elegant, declarative API
  • Built with TypeScript
  • Zero dependencies

Inspired by factory_boy and Laravel's factories

Usage

Installation

You can use any data source you want with fabbrica. In the examples we are going to use faker.js and we can recommend it!

yarn add fabbrica faker

Defining factories

import { Factory } from 'fabbrica';
import faker from 'faker';

interface User {
  id: string;
  email: string;
  name: string;
  age: number;
};

class UserFactory extends Factory<User> {
  define = {
    id: () => faker.datatype.uuid(),
    email: () => faker.internet.email(),
    name: () => faker.name.findName(),
    age: () => faker.datatype.number({ min: 1, max: 99 }),
  };
}

In this example UserFactory extends fabbrica's Factory with interface User. This makes us confident that definition of the Factory matches User model.

Keys of the field define can be both functions and expressions. Expressions are evaluated once, per factory definition and never change. Functions are lazy-evaluated when you call create.

Since first three keys are functions already we don't want to pass anything to them, we can simplify the definition:

class UserFactory extends Factory<User> {
  define = {
    id: faker.datatype.uuid,
    email: faker.internet.email,
    name: faker.name.findName,
    age: () => faker.datatype.number({ min: 1, max: 99 }),
  };
}

Creating objects

With defined factory you can now create User object:

const user = new UserFactory().create(); // User

Simply pass number of Users if you want to create many of them:

const users = new UserFactory().create(4) // [User, User, User, User]

Overriding data

Sometimes you want to override data with specific, case determined values. It's simple:

const me = new UserFactory()
  .override({
    id: '58fca697-2ab1-4a08-a8f1-8473c5979f10',
    name: 'Arkadiusz Bachorski',
  })
  .create();

/*
{
  id: '58fca697-2ab1-4a08-a8f1-8473c5979f10',
  email: <random>,
  name: 'Arkadiusz Bachorski',
  age: <random>,
}
*/

You can pass both functions and expressions to the override method, just like to the define field. In this case faker.datatype.uuid and faker.name.findName will never be called, since they're overrided.

Implementing reusable states

You can easily create specific, reusable and chainable states. Just return override call of the Factory class in your custom method:

class UserFactory extends Factory<User> {
  define = {
    id: faker.datatype.uuid,
    email: faker.internet.email,
    name: faker.name.findName,
    age: () => faker.datatype.number({ min: 1, max: 99 }),
  };

  me() {
    return this.override({
      id: '58fca697-2ab1-4a08-a8f1-8473c5979f10',
      name: 'Arkadiusz Bachorski',
    })
  }
  
  exampleEmail(user: string) {
    return this.override({
      email: `${user}@example.com`,
    })
  }

  old() {
    return this.override({
      age: () => faker.datatype.number({ min: 90, max: 99 }),
    })
  }
}

const oldMe = new UserFactory()
  .me()
  .old()
  .exampleEmail('arkadiusz')
  .create()

/*
{
  id: '58fca697-2ab1-4a08-a8f1-8473c5979f10',
  email: '[email protected]',
  name: 'Arkadiusz Bachorski',
  age: <random between 90 - 99>,
}
*/

Remember to return this.override result! It allows you to chain methods.

Nested factories

You can simply pass factory as part of the definition if your types are matching.

type BlogPost = {
    id: string;
    content: string;
    user: User;
}

class BlogPostFactory extends Factory<BlogPost> {
    define = {
        id: 'uuid',
        content: 'Lorem ipsum',
        user: UserFactory,
    }
}

As simple as that!

If you need an array of nested objects, utilize many helper function

type BlogPost = {
    id: string;
    content: string;
    users: User[];
}

class BlogPostFactory extends Factory<BlogPost> {
    define = {
        id: 'uuid',
        content: 'Lorem ipsum',
        user: many(UserFactory, { min: 2, max: 5 }),
    }
}

Repeatable data series

You can use sequence helper if you need repeatable data sequences in your factories.

type BlogPost = {
    variant: string
}

class BlogPostFactory extends Factory<BlogPost> {
    define = {
        variant: sequence(['long', 'short', (index) => `long-${index}`])
    }
}

const variants = new BlogPostFactory().create(5).map(post => post.variant);
// [ 'long', 'short', 'long-2', 'long', 'short' ]

If you need only sequence function:

class BlogPostFactory extends Factory<BlogPost> {
    define = {
        variant: sequence((index) => `variant-${index}`)
    }
}

const variants = new BlogPostFactory().create(5).map(post => post.variant);
// [ 'variant-0', 'variant-1', 'variant-2', 'variant-3', 'variant-4' ]

Probability

You can use chance helper if you need to add possibility to your factories.

type BlogPost = {
    variant: 'long' | 'short' | 'unique'
}

class BlogPostFactory extends Factory<BlogPost> {
    define = {
        variant: chance([
            [4, 'long'], // 4/10 chance for `long`
            [5, 'short'], // 5/10 chance for `short`
            [1, 'unique'], // 1/10 chance for `unique`
        ])
    }
}

fabbrica also exposes orNull and orUndefined helpers, which resolves common cases like T | null.

type BlogPost = {
    variant: 'long' | null
}

class BlogPostFactory extends Factory<BlogPost> {
    define = {
        variant: orNull('long', 80) // 80% "long", 20% null
    }
}

If you would like to create your own orX helper, you can use simpleChanceCreator.

export const orEmptyString = <T>(value: T, chance = 80) => {
    return simpleChanceCreator(value, chance, '');
}

Picking fields

Picking fields allows you to take advantage of your factories goods and keep the execution fast.

type BlogPost = {
    id: string;
    name: string;
    content: string; 
}

class BlogPostFactory extends Factory<BlogPost> {
    define = {
        id: faker.datatype.uuid,
        name: faker.lorem.words,
        content: veryExpensiveCaluclation
    }
}

If you need only id

const blogWithIdOnly = new BlogPostFactory().pick(['id']).create();

If you need everything besides expensive content

const blogWithoutContent = new BlogPostFactory().omit(['content']).create();

You must always call pick and omit before create.

Extending factories

Factories, just like types, are extensible in their natures. All you have to do is spread desired define fields into the new factory definition

type BlogPostList = {
    id: string;
    name: string;
    isFavorite: boolean;
}

type BlogPostDetails = Omit<BlogPostList, 'isFavorite'> & {
    content: string;
}

class BlogPostListFactory extends Factory<BlogPostList> {
    define = {
        id: faker.datatype.uuid,
        name: faker.lorem.words,
        isFavorite: faker.datatype.boolean,
    }
}

class BlogPostDetailsFactory extends Factory<BlogPostDetails> {
    define = {
        ...new BlogPostListFactory().omit(['isFavorite']).define,
        content: veryExpensiveCaluclation
    }
}

More examples

If you need more examples, you can go through src/__tests__.