https://github.com/aklinker1/zero-factory
Zero dependency object factory generator for testing
https://github.com/aklinker1/zero-factory
factory testing zero-dependencies
Last synced: about 1 month ago
JSON representation
Zero dependency object factory generator for testing
- Host: GitHub
- URL: https://github.com/aklinker1/zero-factory
- Owner: aklinker1
- License: mit
- Created: 2025-08-13T19:28:31.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2025-08-21T18:41:49.000Z (about 2 months ago)
- Last Synced: 2025-08-29T11:58:11.147Z (about 1 month ago)
- Topics: factory, testing, zero-dependencies
- Language: TypeScript
- Homepage: https://jsr.io/@aklinker1/zero-factory
- Size: 31.3 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# @aklinker1/zero-factory
[](https://jsr.io/@aklinker1/zero-factory) [](https://www.npmjs.com/package/@aklinker1/zero-factory) [](https://jsr.io/@aklinker1/zero-factory) [](https://jsr.io/@aklinker1/zero-factory/doc) [](https://github.com/aklinker1/zero-factory/blob/main/LICENSE)
Zero dependency object factory generator for testing.
```ts
import { createFactory, createSequence } from "@aklinker1/zero-factory";const userFactory = createFactory({
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"
// }
``````sh
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:
```ts
const userFactory = createFactory({
id: "user-id",
username: "username",
email: "example@gmail.com",
preferences: {
receiveMarketingEmails: true,
receiveSecurityEmails: true,
},
});
// typeof userFactory = (overrides?: DeepPartial) => User
```Then, to get an object conforming to the `User` type, just call the factory as a function:
```ts
const user = userFactory();
// => {
// id: "user-id",
// username: "username",
// email: "example@gmail.com",
// preferences: {
// receiveMarketingEmails: true,
// receiveSecurityEmails: true,
// }
// }
```You can also override specific properties at any level:
```ts
const user = userFactory({
username: "overridden",
preferences: {
receiveMarketingEmails: false,
},
});
// => {
// id: "user-id",
// username: "overridden",
// email: "example@gmail.com",
// preferences: {
// receiveMarketingEmails: false,
// receiveSecurityEmails: true,
// }
// }
```#### Traits
If there are common variants or "traits" of an object you want to be able to generate, use `factory.trait(...)`:
```ts
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:
```ts
const user = userFactory.noEmails();
// => {
// id: "user-id",
// username: "username",
// email: "example@gmail.com",
// preferences: {
// receiveMarketingEmails: false,
// receiveSecurityEmails: false,
// }
// }
```When using a trait and overriding specific properties, the trait's default values are applied before the overrides:
```ts
const user = userFactory.noEmails({ username: "overridden" });
// => {
// id: "user-id",
// username: "overridden",
// email: "example@gmail.com",
// preferences: {
// receiveMarketingEmails: false,
// receiveSecurityEmails: false,
// }
// }
```### Function Defaults
In addition to static values, you can pass a function as a value:
```ts
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:
```ts
userFactory(); // { email: "example.424@gmail.com", ... }
userFactory(); // { email: "example.133@gmail.com", ... }
```This is where [fake data generators](https://www.npmjs.com/search?q=fake%20data) and [sequences](#sequences) come in clutch:
```ts
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,
},
});
```### 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:
```ts
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).
```ts
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:
```ts
const intSequence = createSequence();
intSequence(); // 0
intSequence(); // 1
intSequence(); // 2
// ...const strSequence = createSequence("prefix-");
intSequence(); // "prefix-0"
intSequence(); // "prefix-1"
intSequence(); // "prefix-2"
```---
## Future Features?
May or may not implement these.
- Generate multiple items:
```ts
userFactory.many(4, { username: "override" });
// [
// { id: "user-0", username: "override", ... },
// { id: "user-1", username: "override", ... },
// { id: "user-2", username: "override", ... },
// { id: "user-3", username: "override", ... },
// ]
```
- Associations:```ts
const userIdSequence = createSequence("user-")
const userFactory = createFactory({
id: userIdSequence,
// ...
})
const postFactory = createFactory({
id: createSequence("post-"),
userId: userIdSequence,
})
.associate("user", (user) => ({
userId: user.id
}))const user = userFactory(); // { id: "user-0", ... }
const postFactory.with({ user })(/* optional overrides */) // { id: "post-0", userId: "user-0", ... }
```