From 65beb980f80647b031854a8a248960d6444aed4e Mon Sep 17 00:00:00 2001 From: "BENJAMIN\\bensh" Date: Sun, 20 Oct 2024 21:43:55 +0100 Subject: [PATCH] feat(factory): Improved factories, added faker package, added test --- package.json | 1 + src/core/base/Factory.ts | 17 ++++++--- src/core/domains/auth/actions/create.ts | 2 +- .../domains/auth/factory/apiTokenFactory.ts | 9 ++--- src/core/domains/auth/factory/userFactory.ts | 2 +- src/core/interfaces/IFactory.ts | 3 +- src/tests/auth/auth.test.ts | 2 +- src/tests/factory/TestMovieFaker.ts | 23 ++++++++++++ src/tests/factory/factory.test.ts | 36 +++++++++++++++++++ yarn.lock | 5 +++ 10 files changed, 86 insertions(+), 14 deletions(-) create mode 100644 src/tests/factory/TestMovieFaker.ts create mode 100644 src/tests/factory/factory.test.ts diff --git a/package.json b/package.json index bf2929cb4..c01710a4d 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ }, "devDependencies": { "@eslint/compat": "^1.1.1", + "@faker-js/faker": "^9.0.3", "@jest/test-sequencer": "^29.7.0", "@types/bcryptjs": "^2.4.6", "@types/body-parser": "^1.19.5", diff --git a/src/core/base/Factory.ts b/src/core/base/Factory.ts index b4b155e5d..d93f8a9f7 100644 --- a/src/core/base/Factory.ts +++ b/src/core/base/Factory.ts @@ -1,5 +1,9 @@ -import IFactory from "@src/core/interfaces/IFactory"; +import { faker } from "@faker-js/faker"; import { ICtor } from "@src/core/interfaces/ICtor"; +import IFactory from "@src/core/interfaces/IFactory"; + +import { IModel } from "../interfaces/IModel"; +import IModelAttributes from "../interfaces/IModelData"; /** * Abstract base class for factories that create instances of a specific model. @@ -7,7 +11,12 @@ import { ICtor } from "@src/core/interfaces/ICtor"; * @template Model The type of model to create. * @template Data The type of data to pass to the model constructor. */ -export default abstract class Factory implements IFactory { +export default abstract class Factory implements IFactory { + + /** + * The faker instance to use. + */ + protected faker = faker; /** * The constructor of the model to create. @@ -29,8 +38,8 @@ export default abstract class Factory implements IFactory { * @param data The data to pass to the model constructor. * @returns A new instance of the model. */ - create(data: Data): Model { + createWithData(data: Data | null = null): Model { return new this.modelCtor(data) } - + } diff --git a/src/core/domains/auth/actions/create.ts b/src/core/domains/auth/actions/create.ts index 1898836c4..0ba497917 100644 --- a/src/core/domains/auth/actions/create.ts +++ b/src/core/domains/auth/actions/create.ts @@ -28,7 +28,7 @@ export default async (req: Request, res: Response): Promise => { } // Create a new user - const user = new UserFactory().create({ + const user = new UserFactory().createWithData({ email, password, hashedPassword: hashPassword(password ?? ''), diff --git a/src/core/domains/auth/factory/apiTokenFactory.ts b/src/core/domains/auth/factory/apiTokenFactory.ts index 3f4bcfb6e..51d3ffcd1 100644 --- a/src/core/domains/auth/factory/apiTokenFactory.ts +++ b/src/core/domains/auth/factory/apiTokenFactory.ts @@ -1,16 +1,13 @@ import ApiToken from '@src/app/models/auth/ApiToken' import Factory from '@src/core/base/Factory' -import IApiTokenModel, { IApiTokenData } from '@src/core/domains/auth/interfaces/IApitokenModel' +import IApiTokenModel from '@src/core/domains/auth/interfaces/IApitokenModel' import IUserModel from '@src/core/domains/auth/interfaces/IUserModel' import tokenFactory from '@src/core/domains/auth/utils/generateToken' /** * Factory for creating ApiToken models. - * - * @class ApiTokenFactory - * @extends {Factory} */ -class ApiTokenFactory extends Factory { +class ApiTokenFactory extends Factory { constructor() { super(ApiToken) @@ -23,7 +20,7 @@ class ApiTokenFactory extends Factory { * @returns {IApiTokenModel} */ createFromUser(user: IUserModel, scopes: string[] = []): IApiTokenModel { - return new this.modelCtor({ + return this.createWithData({ userId: user.attributes?.id, token: tokenFactory(), scopes: scopes, diff --git a/src/core/domains/auth/factory/userFactory.ts b/src/core/domains/auth/factory/userFactory.ts index b9e084756..cf718b8d6 100644 --- a/src/core/domains/auth/factory/userFactory.ts +++ b/src/core/domains/auth/factory/userFactory.ts @@ -7,7 +7,7 @@ import Factory from '@src/core/base/Factory'; * @class UserFactory * @extends {Factory} */ -export default class UserFactory extends Factory { +export default class UserFactory extends Factory { /** * Constructor diff --git a/src/core/interfaces/IFactory.ts b/src/core/interfaces/IFactory.ts index c3358aa97..59cdb1085 100644 --- a/src/core/interfaces/IFactory.ts +++ b/src/core/interfaces/IFactory.ts @@ -1,4 +1,5 @@ + export default interface IFactory { // eslint-disable-next-line no-unused-vars - create(...args: any[]): any; + createWithData(...args: any[]): any; } \ No newline at end of file diff --git a/src/tests/auth/auth.test.ts b/src/tests/auth/auth.test.ts index 494e36571..010cecdd9 100644 --- a/src/tests/auth/auth.test.ts +++ b/src/tests/auth/auth.test.ts @@ -36,7 +36,7 @@ describe('attempt to run app with normal appConfig', () => { /** * Create a test user */ - testUser = new UserFactory().create({ + testUser = new UserFactory().createWithData({ email, hashedPassword, roles: [], diff --git a/src/tests/factory/TestMovieFaker.ts b/src/tests/factory/TestMovieFaker.ts new file mode 100644 index 000000000..0782b72dc --- /dev/null +++ b/src/tests/factory/TestMovieFaker.ts @@ -0,0 +1,23 @@ +import Factory from "@src/core/base/Factory"; + +import { TestMovieModel } from "../models/models/TestMovie"; + +class TestMovieFactory extends Factory { + + constructor() { + super(TestMovieModel) + } + + createFakeMovie(): TestMovieModel { + return this.createWithData({ + authorId: this.faker.number.int({ min: 1, max: 100 }).toString(), + name: this.faker.person.fullName(), + yearReleased: this.faker.number.int({ min: 1900, max: 2000 }), + createdAt: this.faker.date.past(), + updatedAt: this.faker.date.recent() + }) + } + +} + +export default TestMovieFactory \ No newline at end of file diff --git a/src/tests/factory/factory.test.ts b/src/tests/factory/factory.test.ts new file mode 100644 index 000000000..272ea5c1b --- /dev/null +++ b/src/tests/factory/factory.test.ts @@ -0,0 +1,36 @@ +/* eslint-disable no-undef */ +import { describe } from '@jest/globals'; +import Kernel from '@src/core/Kernel'; +import testAppConfig from '@src/tests/config/testConfig'; + +import TestDatabaseProvider from '../providers/TestDatabaseProvider'; +import TestMovieFactory from './TestMovieFaker'; + +describe('test migrations', () => { + + + beforeAll(async () => { + await Kernel.boot({ + ...testAppConfig, + providers: [ + ...testAppConfig.providers, + new TestDatabaseProvider() + ] + }, {}) + + + }); + + + test('test factory', async () => { + const factory = new TestMovieFactory(); + const movie = factory.createFakeMovie(); + + expect(movie).toBeTruthy(); + expect(typeof movie.getAttribute('authorId') === 'string').toEqual(true); + expect(typeof movie.getAttribute('name') === 'string').toEqual(true); + expect(typeof movie.getAttribute('yearReleased') === 'number').toEqual(true); + expect(movie.getAttribute('createdAt') instanceof Date).toEqual(true); + expect(movie.getAttribute('updatedAt') instanceof Date).toEqual(true); + }); +}); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 1e5dfdb37..dc234be0a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -380,6 +380,11 @@ dependencies: levn "^0.4.1" +"@faker-js/faker@^9.0.3": + version "9.0.3" + resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-9.0.3.tgz#be817db896b07d1716bc65d9aad1ba587b499826" + integrity sha512-lWrrK4QNlFSU+13PL9jMbMKLJYXDFu3tQfayBsMXX7KL/GiQeqfB1CzHkqD5UHBUtPAuPo6XwGbMFNdVMZObRA== + "@gar/promisify@^1.0.1": version "1.1.3" resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"