From 2ba31148ca53b0a8774678cc200608b52b0f1493 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Sun, 15 Dec 2024 00:49:10 +0200 Subject: [PATCH] feat: initialize the server e2e tests --- .../modules/Auth/AuthApplication.sevice.ts | 27 +--- .../Auth/AuthForgetPassword.service.ts | 1 - .../modules/Auth/AuthResetPassword.service.ts | 132 ------------------ .../src/modules/Auth/AuthSignin.service.ts | 88 ------------ .../src/modules/Auth/AuthSignup.service.ts | 1 - packages/server-nest/test/app.e2e-spec.ts | 24 ---- packages/server-nest/test/init-app-test.ts | 20 +++ packages/server-nest/test/items.e2e-spec.ts | 19 +++ packages/server-nest/test/jest-e2e.json | 3 + packages/webapp/package.json | 6 - 10 files changed, 43 insertions(+), 278 deletions(-) delete mode 100644 packages/server-nest/src/modules/Auth/AuthForgetPassword.service.ts delete mode 100644 packages/server-nest/src/modules/Auth/AuthResetPassword.service.ts delete mode 100644 packages/server-nest/src/modules/Auth/AuthSignin.service.ts delete mode 100644 packages/server-nest/src/modules/Auth/AuthSignup.service.ts delete mode 100644 packages/server-nest/test/app.e2e-spec.ts create mode 100644 packages/server-nest/test/init-app-test.ts create mode 100644 packages/server-nest/test/items.e2e-spec.ts diff --git a/packages/server-nest/src/modules/Auth/AuthApplication.sevice.ts b/packages/server-nest/src/modules/Auth/AuthApplication.sevice.ts index d93cf0dfc..38371c565 100644 --- a/packages/server-nest/src/modules/Auth/AuthApplication.sevice.ts +++ b/packages/server-nest/src/modules/Auth/AuthApplication.sevice.ts @@ -1,29 +1,4 @@ -import { AuthForgetPasswordService } from './AuthForgetPassword.service'; -import { AuthSendResetPasswordService } from './AuthResetPassword.service'; -import { AuthSigninService } from './AuthSignin.service'; -import { AuthSignupService } from './AuthSignup.service'; export class AuthApplication { - constructor( - private readonly authSigninService: AuthSigninService, - private readonly authSignupService: AuthSignupService, - private readonly authResetPasswordService: AuthSendResetPasswordService, - private readonly authForgetPasswordService: AuthForgetPasswordService, - ) {} - - async signin(email: string, password: string) { - return this.authSigninService.signIn(email, password); - } - - async signup(data: any) { - return this.authSignupService.signup(data); - } - - async resetPassword(data: any) { - return this.authResetPasswordService.resetPassword(data); - } - - async forgetPassword(data: any) { - return this.authForgetPasswordService.execute(data); - } + } diff --git a/packages/server-nest/src/modules/Auth/AuthForgetPassword.service.ts b/packages/server-nest/src/modules/Auth/AuthForgetPassword.service.ts deleted file mode 100644 index eb21b7992..000000000 --- a/packages/server-nest/src/modules/Auth/AuthForgetPassword.service.ts +++ /dev/null @@ -1 +0,0 @@ -export class AuthForgetPasswordService {} diff --git a/packages/server-nest/src/modules/Auth/AuthResetPassword.service.ts b/packages/server-nest/src/modules/Auth/AuthResetPassword.service.ts deleted file mode 100644 index 02d38d867..000000000 --- a/packages/server-nest/src/modules/Auth/AuthResetPassword.service.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { Injectable, Inject } from '@nestjs/common'; -import uniqid from 'uniqid'; -import moment from 'moment'; -import config from '@/config'; -import { - IAuthResetedPasswordEventPayload, - IAuthSendedResetPassword, - IAuthSendingResetPassword, - IPasswordReset, - ISystemUser, -} from '@/interfaces'; -import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; -import events from '@/subscribers/events'; -import { PasswordReset } from '@/system/models'; -import { ERRORS } from './_constants'; -import { ServiceError } from '@/exceptions'; -import { hashPassword } from '@/utils'; - -@Injectable() -export class AuthSendResetPasswordService { - constructor( - private readonly eventPublisher: EventPublisher, - @Inject('SystemUserRepository') private readonly systemUserRepository: any, - - @Inject('PasswordResetModel') - private readonly passwordResetModel: typeof PasswordReset, - ) {} - - /** - * Generates and retrieve password reset token for the given user email. - * @param {string} email - * @return {} - */ - public async sendResetPassword(email: string): Promise { - const user = await this.validateEmailExistance(email); - - const token: string = uniqid(); - - // Triggers sending reset password event. - await this.eventPublisher.emitAsync(events.auth.sendingResetPassword, { - user, - token, - } as IAuthSendingResetPassword); - - // Delete all stored tokens of reset password that associate to the give email. - this.deletePasswordResetToken(email); - - // Creates a new password reset row with unique token. - const passwordReset = await this.passwordResetModel - .query() - .insert({ email, token }); - - // Triggers sent reset password event. - await this.eventPublisher.emitAsync(events.auth.sendResetPassword, { - user, - token, - } as IAuthSendedResetPassword); - - return passwordReset; - } - - /** - * Resets a user password from given token. - * @param {string} token - Password reset token. - * @param {string} password - New Password. - * @return {Promise} - */ - public async resetPassword(token: string, password: string): Promise { - // Finds the password reset token. - const tokenModel: IPasswordReset = await this.passwordResetModel - .query() - .findOne('token', token); - // In case the password reset token not found throw token invalid error.. - if (!tokenModel) { - throw new ServiceError(ERRORS.TOKEN_INVALID); - } - // Different between token creation datetime and current time. - if ( - moment().diff(tokenModel.createdAt, 'seconds') > - config.resetPasswordSeconds - ) { - // Deletes the expired token by expired token email. - await this.deletePasswordResetToken(tokenModel.email); - throw new ServiceError(ERRORS.TOKEN_EXPIRED); - } - const user = await this.systemUserRepository.findOneByEmail( - tokenModel.email, - ); - - if (!user) { - throw new ServiceError(ERRORS.USER_NOT_FOUND); - } - const hashedPassword = await hashPassword(password); - - await this.systemUserRepository.update( - { password: hashedPassword }, - { id: user.id }, - ); - // Deletes the used token. - await this.deletePasswordResetToken(tokenModel.email); - - // Triggers `onResetPassword` event. - await this.eventPublisher.emitAsync(events.auth.resetPassword, { - user, - token, - password, - } as IAuthResetedPasswordEventPayload); - } - - /** - * Deletes the password reset token by the given email. - * @param {string} email - * @returns {Promise} - */ - private async deletePasswordResetToken(email: string) { - return this.passwordResetModel.query().where('email', email).delete(); - } - - /** - * Validates the given email existance on the storage. - * @throws {ServiceError} - * @param {string} email - email address. - */ - private async validateEmailExistance(email: string): Promise { - const userByEmail = await this.systemUserRepository.findOneByEmail(email); - - if (!userByEmail) { - throw new ServiceError(ERRORS.EMAIL_NOT_FOUND); - } - return userByEmail; - } -} diff --git a/packages/server-nest/src/modules/Auth/AuthSignin.service.ts b/packages/server-nest/src/modules/Auth/AuthSignin.service.ts deleted file mode 100644 index c50ff9054..000000000 --- a/packages/server-nest/src/modules/Auth/AuthSignin.service.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { Inject, Injectable } from '@nestjs/common'; -import { cloneDeep } from 'lodash'; -import { SystemUser } from '../System/models/SystemUser'; -import { TenantModel } from '../System/models/TenantModel'; -import { EventEmitter2 } from '@nestjs/event-emitter'; -import { events } from '@/common/events/events'; -import { ServiceError } from '../Items/ServiceError'; -import { ERRORS } from '../Items/Items.constants'; -import { - IAuthSignedInEventPayload, - IAuthSigningInEventPayload, - IAuthSignInPOJO, -} from './Auth.interfaces'; - -@Injectable() -export class AuthSigninService { - constructor( - private readonly eventEmitter: EventEmitter2, - - @Inject(SystemUser.name) - private readonly systemUserModel: typeof SystemUser, - - @Inject(TenantModel.name) - private readonly tenantModel: typeof TenantModel, - ) {} - - /** - * Validates the given email and password. - * @param {ISystemUser} user - */ - public async validateSignIn(user: SystemUser) { - // Validate if the given user is inactive. - if (!user.active) { - throw new ServiceError(ERRORS.USER_INACTIVE); - } - } - - /** - * sign-in and generates JWT token. - * @param {string} email - Email address. - * @param {string} password - Password. - * @return {Promise<{user: IUser, token: string}>} - */ - public async signIn( - email: string, - password: string, - ): Promise { - // Finds the user of the given email address. - const user = await SystemUser.query() - .findOne('email', email) - .modify('inviteAccepted'); - - // Validate the given email and password. - await this.validateSignIn(user); - - // Triggers on signing-in event. - await this.eventEmitter.emitAsync(events.auth.signingIn, { - email, - password, - user, - } as IAuthSigningInEventPayload); - - const token = generateToken(user); - - // Update the last login at of the user. - // await systemUserRepository.patchLastLoginAt(user.id); - - // Triggers `onSignIn` event. - await this.eventEmitter.emitAsync(events.auth.signIn, { - email, - password, - user, - } as IAuthSignedInEventPayload); - - const tenant = await this.tenantModel - .query() - .findById(user.tenantId) - .withGraphFetched('metadata'); - - // Keep the user object immutable. - const outputUser = cloneDeep(user); - - // Remove password property from user object. - Reflect.deleteProperty(outputUser, 'password'); - - return { user: outputUser, token, tenant }; - } -} diff --git a/packages/server-nest/src/modules/Auth/AuthSignup.service.ts b/packages/server-nest/src/modules/Auth/AuthSignup.service.ts deleted file mode 100644 index 873b010c1..000000000 --- a/packages/server-nest/src/modules/Auth/AuthSignup.service.ts +++ /dev/null @@ -1 +0,0 @@ -export class AuthSignupService {} diff --git a/packages/server-nest/test/app.e2e-spec.ts b/packages/server-nest/test/app.e2e-spec.ts deleted file mode 100644 index a9147ca2c..000000000 --- a/packages/server-nest/test/app.e2e-spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { INestApplication } from '@nestjs/common'; -import * as request from 'supertest'; -import { AppModule } from '../src/modules/App/App.module'; - -describe('AppController (e2e)', () => { - let app: INestApplication; - - beforeEach(async () => { - const moduleFixture: TestingModule = await Test.createTestingModule({ - imports: [AppModule], - }).compile(); - - app = moduleFixture.createNestApplication(); - await app.init(); - }); - - it('/ (GET)', () => { - return request(app.getHttpServer()) - .get('/') - .expect(200) - .expect('Hello World!'); - }); -}); diff --git a/packages/server-nest/test/init-app-test.ts b/packages/server-nest/test/init-app-test.ts new file mode 100644 index 000000000..0096b2a97 --- /dev/null +++ b/packages/server-nest/test/init-app-test.ts @@ -0,0 +1,20 @@ +import { INestApplication } from '@nestjs/common'; +import { Test, TestingModule } from '@nestjs/testing'; +import { AppModule } from '../src/modules/App/App.module'; + +let app: INestApplication; + +beforeAll(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + app = moduleFixture.createNestApplication(); + await app.init(); +}); + +afterAll(async () => { + await app.close(); +}); + +export { app }; diff --git a/packages/server-nest/test/items.e2e-spec.ts b/packages/server-nest/test/items.e2e-spec.ts new file mode 100644 index 000000000..dd3a1a6da --- /dev/null +++ b/packages/server-nest/test/items.e2e-spec.ts @@ -0,0 +1,19 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { INestApplication } from '@nestjs/common'; +import * as request from 'supertest'; +import { faker } from '@faker-js/faker'; +import { AppModule } from '../src/modules/App/App.module'; +import { app } from './init-app-test'; + +describe('Items (e2e)', () => { + it('/items (POST)', () => { + return request(app.getHttpServer()) + .post('/items') + .set('organization-id', '4064541lv40nhca') + .send({ + name: faker.commerce.productName(), + type: 'service', + }) + .expect(201); + }); +}); diff --git a/packages/server-nest/test/jest-e2e.json b/packages/server-nest/test/jest-e2e.json index e9d912f3e..11e9b9a4e 100644 --- a/packages/server-nest/test/jest-e2e.json +++ b/packages/server-nest/test/jest-e2e.json @@ -5,5 +5,8 @@ "testRegex": ".e2e-spec.ts$", "transform": { "^.+\\.(t|j)s$": "ts-jest" + }, + "moduleNameMapper": { + "^@/(.*)$": "/../src/$1" } } diff --git a/packages/webapp/package.json b/packages/webapp/package.json index c997612b2..c3a2edb6b 100644 --- a/packages/webapp/package.json +++ b/packages/webapp/package.json @@ -23,7 +23,6 @@ "@reduxjs/toolkit": "^1.2.5", "@stripe/connect-js": "^3.3.12", "@stripe/react-connect-js": "^3.3.13", - "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.4.0", "@testing-library/user-event": "^7.2.1", "@tiptap/core": "2.1.13", @@ -33,7 +32,6 @@ "@tiptap/pm": "2.1.13", "@tiptap/react": "2.1.13", "@tiptap/starter-kit": "2.1.13", - "@types/jest": "^26.0.15", "@types/js-money": "^0.6.1", "@types/lodash": "^4.14.172", "@types/node": "^14.14.9", @@ -68,10 +66,6 @@ "helmet": "^3.21.0", "history": "4.10.1", "http-proxy-middleware": "^1.0.0", - "jest": "24.9.0", - "jest-environment-jsdom-fourteen": "1.0.1", - "jest-resolve": "24.9.0", - "jest-watch-typeahead": "0.4.2", "js-cookie": "2.2.1", "js-money": "^0.6.3", "lodash": "^4.17.15",