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

@aklinker1/zero-factory

v1.1.4

Published

Zero dependency object factory generator for testing

Readme

@aklinker1/zero-factory

JSR NPM Version Docs API Reference License

Zero dependency object factory generator for testing.

import { createFactory, createSequence } from "@aklinker1/zero-factory";

const userFactory = createFactory<User>({
  id: createSequence("user-"),
  username: "example-username",
  email: () => "example-email-" + Math.random(),
});

userFactory({ id: "test", username: "user" });
// => {
//   id: "test",
//   username: "user",
//   email: "example-email-0.20088082049103195"
// }
npm i @aklinker1/zero-factory

Features:

  • ✅ Type-safe
  • ✨ Deeply merge overrides with default values
  • 🔢 Sequence generator for IDs
  • 🎨 "traits" - define multiple variants of default values
  • ⚡ Compatible with all fake data generators (@ngneat/falso, faker-js, chance, casual, etc)

Not Supported:

  • Class instances: Only objects can be created. Factories will not create class instances.

Usage

Factories

Use createFactory to build an object factory. Object factories are simple functions that return an object:

const userFactory = createFactory<User>({
  id: "user-id",
  username: "username",
  email: "[email protected]",
  preferences: {
    receiveMarketingEmails: true,
    receiveSecurityEmails: true,
  },
});
// typeof userFactory = (overrides?: DeepPartial<User>) => User

Then, to get an object conforming to the User type, just call the factory as a function:

const user = userFactory();
// => {
//   id: "user-id",
//   username: "username",
//   email: "[email protected]",
//   preferences: {
//     receiveMarketingEmails: true,
//     receiveSecurityEmails: true,
//   }
// }

You can also override specific properties at any level:

const user = userFactory({
  username: "overridden",
  preferences: {
    receiveMarketingEmails: false,
  },
});
// => {
//   id: "user-id",
//   username: "overridden",
//   email: "[email protected]",
//   preferences: {
//     receiveMarketingEmails: false,
//     receiveSecurityEmails: true,
//   }
// }

[!IMPORTANT] Arrays are not deeply merged. If a property is an array, overrides will fully replace it, like any other value.

Function Defaults

In addition to static values, the factory definition accepts functions for properties:

const userFactory = createFactory({
  email: () => `example.${Math.floor(Math.random() * 1000)}@gmail.com`,
  // ...
});

Every time the factory is called, this will call the function and, in this case, generate a different email each time:

userFactory(); // { email: "[email protected]", ... }
userFactory(); // { email: "[email protected]", ... }

This is where fake data generators and sequences come in clutch:

import { createFactory, createSequence } from "@aklinker1/zero-factory";
import {
  randEmail, // () => string
  randUsername, // () => string
  randBoolean, // () => boolean
} from "@ngneat/falso";

const userFactory = createFactory({
  id: createSequence("user-"),
  username: randUsername,
  email: randEmail,
  preferences: {
    receiveMarketingEmails: randBoolean,
    receiveSecurityEmails: randBoolean,
  },
});

Many

You can generate multiple objects using factory.many(...). This method will return an array of objects.

userFactory.many(2, { username: "override" });
// [
//   { usenrame: "override", ... }
//   { usenrame: "override", ... }
// ]

Overridden fields apply to all the returned objects.

Traits

If there are common variants or "traits" of an object you want to be able to generate, use factory.trait(...):

const userFactory = createFactory({
  // same as above
}).trait("noEmails", {
  preferences: {
    receiveMarketingEmails: false,
    receiveSecurityEmails: false,
  },
});

Then, to generate an object using this trait, the trait is a function defined on the object factory:

const user = userFactory.noEmails();
// => {
//   id: "user-id",
//   username: "username",
//   email: "[email protected]",
//   preferences: {
//     receiveMarketingEmails: false,
//     receiveSecurityEmails: false,
//   }
// }

When using a trait and overriding specific properties, the trait's default values are applied before the overrides:

const user = userFactory.noEmails({ username: "overridden" });
// => {
//   id: "user-id",
//   username: "overridden",
//   email: "[email protected]",
//   preferences: {
//     receiveMarketingEmails: false,
//     receiveSecurityEmails: false,
//   }
// }

Associations

If you want to override one or more fields based on a single value, use associations:

const postFactory = createFactory<Post>({
  id: createSequence(),
  userId: userIdSequence,
  // ...
}).associate("user", (user: User) => ({ userId: user.id }));

Then to generate a post associated with a user, use with:

user;
// => {
//   id: 3,
//   ...
// }

postFactory.with({ user })();
// => {
//   id: 0,
//   userId: 3,
//   ...
// }

Note that with returns a factory function, which needs to be called to generate the final object. This allows you to chain other utilities like .many and/or traits:

postFactory.with({ user }).noEmails.many(3);

Sequences

For values like IDs, it can be useful to generate them incrementally instead of using randomized values. Use the createSequence function to do this:

const userIdSequence = createSequence((i) => `user-${i}`);

userIdSequence(); // "user-0"
userIdSequence(); // "user-1"
userIdSequence(); // "user-2"
// ...

The argument i is a number starting at 0 that gets incremented by 1 each time the sequence is called. The return value can be anything (string, boolean, object, integer, etc).

const intSequence = createSequence((i) => i + 1);
intSequence(); // 1
intSequence(); // 2
intSequence(); // 3
// ...

const boolSequence = createSequence((i) => i % 2 === 0);
boolSequence(); // true
boolSequence(); // false
boolSequence(); // true
// ...

However, the most common types of return values are integers and strings. For both, there is a shorthand:

const intSequence = createSequence();
intSequence(); // 0
intSequence(); // 1
intSequence(); // 2
// ...

const strSequence = createSequence("prefix-");
intSequence(); // "prefix-0"
intSequence(); // "prefix-1"
intSequence(); // "prefix-2"