diff --git a/README.md b/README.md index c2115f2..56d5525 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,15 @@ new UserFactory().make({ email: 'other@mail.com' }) new UserFactory().makeMany(10, { email: 'other@mail.com' }) ``` +When making many entities, the details on each instance can be fine-tuned using a callback or an array syntax: +```ts +// each second user will be created with disabled flag set +new UserFactory().makeMany(10, [{ }, { disabled: true }]) + +// each second user will be created with disabled flag set, using a function syntax. The result will be similar to the above. +new UserFactory().makeMany(10, (index) => ({ disabled: Boolean(index % 2) })) +``` + ## `create` & `createMany` the create and createMany method is similar to the make and makeMany method, but at the end the created entity instance gets persisted in the database using TypeORM entity manager. @@ -145,6 +154,8 @@ new UserFactory().createMany(10, { email: 'other@mail.com' }) // using save options new UserFactory().create({ email: 'other@mail.com' }, { listeners: false }) new UserFactory().createMany(10, { email: 'other@mail.com' }, { listeners: false }) +new UserFactory().createMany(10, [{}, { disabled: true }]) +new UserFactory().createMany(10, (index) => ({ disabled: Boolean(index % 2) })) ``` ## `attrs` diff --git a/src/factory.ts b/src/factory.ts index b0af41b..ea7f0a5 100644 --- a/src/factory.ts +++ b/src/factory.ts @@ -1,7 +1,7 @@ import type { DataSource, SaveOptions } from "typeorm"; import { EagerInstanceAttribute, LazyInstanceAttribute } from "./instanceAttributes"; import { BaseSubfactory } from "./subfactories"; -import type { Constructable, FactorizedAttrs } from "./types"; +import type { Constructable, FactorizedAttrs, SequenceAttrs } from "./types"; export abstract class Factory { protected abstract entity: Constructable; @@ -25,10 +25,11 @@ export abstract class Factory { /** * Make many new entities without persisting it */ - async makeMany(amount: number, overrideParams: Partial> = {}): Promise { + async makeMany(amount: number, overrideParams: SequenceAttrs = {}): Promise { const list = []; for (let index = 0; index < amount; index++) { - list[index] = await this.make(overrideParams); + const attrs = await this.getAttrsFromSequence(index, overrideParams); + list[index] = await this.make(attrs); } return list; } @@ -53,14 +54,11 @@ export abstract class Factory { /** * Create many new entities and persist them */ - async createMany( - amount: number, - overrideParams: Partial> = {}, - saveOptions?: SaveOptions, - ): Promise { + async createMany(amount: number, overrideParams: SequenceAttrs = {}, saveOptions?: SaveOptions): Promise { const list = []; for (let index = 0; index < amount; index++) { - list[index] = await this.create(overrideParams, saveOptions); + const attrs = await this.getAttrsFromSequence(index, overrideParams); + list[index] = await this.create(attrs, saveOptions); } return list; } @@ -103,6 +101,12 @@ export abstract class Factory { ); } + private async getAttrsFromSequence(index: number, params: SequenceAttrs): Promise>> { + if (typeof params === "function") return params(index); + if (Array.isArray(params)) return params[index % params.length] ?? {}; + return params; + } + private static async resolveValue(value: unknown, shouldPersist: boolean): Promise { if (value instanceof BaseSubfactory) { return shouldPersist ? value.create() : value.make(); diff --git a/src/types.ts b/src/types.ts index 4fe26ad..cb9f0f3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -18,3 +18,5 @@ export type InstanceAttributeCallback = (entity: T) => FactorizedAttr; // Helper types export type Constructable = new () => T; export type IsObject = T extends object ? T : never; +export type GetChildAttrs = (index: number) => Partial>; +export type SequenceAttrs = GetChildAttrs | Partial> | Partial>[]; diff --git a/test/factory.test.ts b/test/factory.test.ts index dd4193b..0f53101 100644 --- a/test/factory.test.ts +++ b/test/factory.test.ts @@ -167,6 +167,37 @@ describe(Factory, () => { expect(entity.id).toBeUndefined(); } }); + + test("Should make entities with array based overrideParams", async () => { + const count = 4; + const factory = new UserFactory(); + const entitiesMaked = await factory.makeMany(count, [ + { email: "foo@no-reply.bar" }, + { email: "foo@no-reply.bar" }, + ]); + + expect(entitiesMaked).toHaveLength(count); + + for (let i = 0; i < count; i++) { + const entity = entitiesMaked[i] as User; + expect(entity.id).toBeUndefined(); + expect(entity.email).toEqual(["foo@no-reply.bar", "foo@no-reply.bar"][i % 2]); + } + }); + + test("Should make entities with function based overrideParams", async () => { + const count = 4; + const factory = new UserFactory(); + const entitiesMaked = await factory.makeMany(count, (index) => ({ email: `${index}@no-reply.bar` })); + + expect(entitiesMaked).toHaveLength(count); + + for (let i = 0; i < count; i++) { + const entity = entitiesMaked[i] as User; + expect(entity.id).toBeUndefined(); + expect(entity.email).toEqual(`${i}@no-reply.bar`); + } + }); }); describe(Factory.prototype.create, () => { @@ -324,5 +355,36 @@ describe(Factory, () => { expect(entity.id).toBeDefined(); } }); + + test("Should create entities with array based overrideParams", async () => { + const count = 4; + const factory = new UserFactory(); + const entitiesCreated = await factory.createMany(count, [ + { email: "foo@no-reply.bar" }, + { email: "foo@no-reply.bar" }, + ]); + + expect(entitiesCreated).toHaveLength(count); + + for (let i = 0; i < count; i++) { + const entity = entitiesCreated[i] as User; + expect(entity.id).toBeDefined(); + expect(entity.email).toEqual(["foo@no-reply.bar", "foo@no-reply.bar"][i % 2]); + } + }); + + test("Should create entities with function based overrideParams", async () => { + const count = 4; + const factory = new UserFactory(); + const entitiesCreated = await factory.createMany(count, (index) => ({ email: `${index}@no-reply.bar` })); + + expect(entitiesCreated).toHaveLength(count); + + for (let i = 0; i < count; i++) { + const entity = entitiesCreated[i] as User; + expect(entity.id).toBeDefined(); + expect(entity.email).toEqual(`${i}@no-reply.bar`); + } + }); }); });