From ebf2383ad832b277618a91f9b242e945ab3a8b4e Mon Sep 17 00:00:00 2001 From: Yuta1409 Date: Fri, 17 May 2024 11:20:57 +0200 Subject: [PATCH 1/6] :white_check_mark: test unit service user --- .../src/api/users/users.service.spec.ts | 160 ++++++++---------- 1 file changed, 68 insertions(+), 92 deletions(-) diff --git a/backend-nest/src/api/users/users.service.spec.ts b/backend-nest/src/api/users/users.service.spec.ts index cfd4305..fecc887 100644 --- a/backend-nest/src/api/users/users.service.spec.ts +++ b/backend-nest/src/api/users/users.service.spec.ts @@ -3,149 +3,125 @@ import { UsersService } from './users.service'; import { PrismaService } from '../../prisma/prisma.service'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; +import { PrismaClient } from '@prisma/client'; import { user_role } from '@prisma/client'; -function createNewUser(): CreateUserDto { - return { - email: `create${Math.random()}@example.com`, - password: 'createpassword', - firstname: 'createfirstname', - lastname: 'cretelastname', - role: user_role.STUDENT, - classGroupId: 1, - }; -} - describe('UsersService', () => { let service: UsersService; + let prisma: PrismaClient; + let testUser: CreateUserDto; + let testUserId: number; beforeEach(async () => { + prisma = new PrismaClient({ + datasources: { + db: { + url: process.env.DATABASE_URL, + }, + }, + }); + + testUser = { + email: `test${Date.now()}@example.com`, + password: 'password', + firstname: 'firstname', + lastname: 'lastname', + role: user_role.STUDENT, + classGroupId: 10, + }; + await prisma.user.deleteMany(); + + testUser.email = `test${Date.now()}@example.com`; + const createdUser = await prisma.user.create({ + data: testUser, + }); + testUserId = createdUser.id; + const module: TestingModule = await Test.createTestingModule({ - providers: [UsersService, PrismaService], + providers: [ + UsersService, + { + provide: PrismaService, + useValue: prisma, + }, + ], }).compile(); - service = module.get(UsersService); }); + afterEach(async () => { + await prisma.$disconnect(); + }); + it('should be defined', () => { expect(service).toBeDefined(); }); describe('findOne', () => { it('return a user if a valid id is provided', async () => { - const userId = 11; - const user = await service.findOne({ id: userId }); - expect(user).not.toBeNull(); - expect(user).not.toBeUndefined(); - expect(user.email).not.toBeNull(); - expect(user.email).not.toBeUndefined(); - expect(user.password).not.toBeNull(); - expect(user.password).not.toBeUndefined(); - expect(user.firstname).not.toBeNull(); - expect(user.firstname).not.toBeUndefined(); - expect(user.lastname).not.toBeNull(); - expect(user.lastname).not.toBeUndefined(); - expect(user.role).not.toBeNull(); - expect(user.role).not.toBeUndefined(); - expect(user.classGroupId).not.toBeNull(); - expect(user.classGroupId).not.toBeUndefined(); + const { id, ...user } = await service.findOne({ email: testUser.email }); + expect(user).toEqual(testUser); }); }); describe('findAll', () => { it('return an array of users', async () => { const users = await service.findAll({}); - expect(users).not.toBeNull(); - expect(users).not.toBeUndefined(); - expect(users.length).toBeGreaterThan(0); - users.forEach((user) => { - expect(user).toHaveProperty('email'); - expect(user).toHaveProperty('password'); - expect(user).toHaveProperty('firstname'); - expect(user).toHaveProperty('lastname'); - expect(user).toHaveProperty('role'); - expect(user).toHaveProperty('classGroupId'); - }); + expect(users.map(({ id, ...user }) => user)).toEqual([testUser]); }); }); describe('findOneByEmail', () => { it('return a user if a valid email is provided', async () => { - const users = await service.findAll({}); - for (const user of users) { - const foundUser = await service.findOneByEmail(user.email); - expect(foundUser).not.toBeNull(); - expect(foundUser).not.toBeUndefined(); - expect(foundUser.email).not.toBeNull(); - } + const { id, ...user } = await service.findOneByEmail(testUser.email); + expect(user).toEqual(testUser); }); }); describe('create', () => { it('create a new user', async () => { - const newUser = createNewUser(); - const user = await service.create(newUser); - expect(user).not.toBeNull(); - expect(user).not.toBeUndefined(); - expect(user.email).toBe(newUser.email); - expect(user.password).toBe(newUser.password); - expect(user.firstname).toBe(newUser.firstname); - expect(user.lastname).toBe(newUser.lastname); - expect(user.role).toBe(newUser.role); + const newUser: CreateUserDto = { + email: `new${Date.now()}@example.com`, + password: 'newpassword', + firstname: 'newfirstname', + lastname: 'newlastname', + role: user_role.STUDENT, + classGroupId: 11, + }; + const { id, ...user } = await service.create(newUser); + expect(user).toEqual(newUser); }); }); - describe('update', () => { - let existingUser; - - beforeEach(async () => { - const newUser = createNewUser(); - existingUser = await service.create(newUser); + describe('delete', () => { + it('delete an existing user', async () => { + const { id, ...deletedUser } = await service.delete({ email: testUser.email }); + expect(deletedUser).toEqual(testUser); }); + }); + describe('update', () => { it('update a user', async () => { const data: UpdateUserDto = { - email: existingUser.email, // Use the existing user's email + email: `updated${Date.now()}@example.com`, password: 'updatedpassword', firstname: 'updatedfirstname', lastname: 'updatedlastname', role: user_role.STUDENT, }; - const user = await service.update({ - where: { id: existingUser.id }, - data, + const { id, ...user } = await service.update({ + where: { id: testUserId }, + data: { ...data, email: testUser.email }, }); - expect(user).not.toBeNull(); - expect(user).toHaveProperty('email', data.email); - expect(user).toHaveProperty('password', data.password); - expect(user).toHaveProperty('firstname', data.firstname); - expect(user).toHaveProperty('lastname', data.lastname); - expect(user).toHaveProperty('role', data.role); - }); - }); - - describe('delete', () => { - let existingUser; - - beforeEach(async () => { - const newUser = createNewUser(); - existingUser = await service.create(newUser); - }); - - it('delete an existing user', async () => { - const deletedUser = await service.delete({ id: existingUser.id }); - expect(deletedUser).toEqual(existingUser); + expect(user).toEqual({ ...testUser, ...data, email: testUser.email }); }); }); describe('updateClassGroup', () => { it('update the class of a user', async () => { - const userId = 11; - const classGroupId = 11; - const user = await service.updateClassGroup(userId, classGroupId); - expect(user).not.toBeNull(); - expect(user).not.toBeUndefined(); - expect(user.classGroupId).toBe(classGroupId); + const newClassGroupId = 12; + const { id, ...user } = await service.updateClassGroup(testUserId, newClassGroupId); + expect(user).toEqual({ ...testUser, classGroupId: newClassGroupId }); }); }); }); From 0ce98d3f1d5c872e14b921c726c63ae08d91c5fc Mon Sep 17 00:00:00 2001 From: Yuta1409 Date: Fri, 17 May 2024 14:02:55 +0200 Subject: [PATCH 2/6] :recycle: change url for database --- backend-nest/src/api/users/users.controller.spec.ts | 7 +++++++ backend-nest/src/api/users/users.service.spec.ts | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/backend-nest/src/api/users/users.controller.spec.ts b/backend-nest/src/api/users/users.controller.spec.ts index c403984..99e54d1 100644 --- a/backend-nest/src/api/users/users.controller.spec.ts +++ b/backend-nest/src/api/users/users.controller.spec.ts @@ -4,6 +4,7 @@ import { UsersService } from './users.service'; import { CreateUserDto } from './dto/create-user.dto'; import { PrismaService } from '../../prisma/prisma.service'; import { UpdateUserDto } from './dto/update-user.dto'; +import { JwtService } from '@nestjs/jwt'; describe('UsersController', () => { let controller: UsersController; @@ -26,6 +27,12 @@ describe('UsersController', () => { }, }, PrismaService, + { + provide: JwtService, + useValue: { + sign: jest.fn().mockResolvedValue('mocked-token'), + }, + }, ], }).compile(); diff --git a/backend-nest/src/api/users/users.service.spec.ts b/backend-nest/src/api/users/users.service.spec.ts index fecc887..d79ef91 100644 --- a/backend-nest/src/api/users/users.service.spec.ts +++ b/backend-nest/src/api/users/users.service.spec.ts @@ -16,7 +16,7 @@ describe('UsersService', () => { prisma = new PrismaClient({ datasources: { db: { - url: process.env.DATABASE_URL, + url: process.env.DATABASE_URL_TEST, }, }, }); From 6a5826b86129507a8da042edf02bbd6dd0bce082 Mon Sep 17 00:00:00 2001 From: Yuta1409 Date: Fri, 17 May 2024 14:30:22 +0200 Subject: [PATCH 3/6] :recycle: refactor --- backend-nest/src/api/users/users.service.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend-nest/src/api/users/users.service.spec.ts b/backend-nest/src/api/users/users.service.spec.ts index d79ef91..dd9669f 100644 --- a/backend-nest/src/api/users/users.service.spec.ts +++ b/backend-nest/src/api/users/users.service.spec.ts @@ -27,7 +27,7 @@ describe('UsersService', () => { firstname: 'firstname', lastname: 'lastname', role: user_role.STUDENT, - classGroupId: 10, + classGroupId: 55, }; await prisma.user.deleteMany(); @@ -86,7 +86,7 @@ describe('UsersService', () => { firstname: 'newfirstname', lastname: 'newlastname', role: user_role.STUDENT, - classGroupId: 11, + classGroupId: 55, }; const { id, ...user } = await service.create(newUser); expect(user).toEqual(newUser); @@ -119,7 +119,7 @@ describe('UsersService', () => { describe('updateClassGroup', () => { it('update the class of a user', async () => { - const newClassGroupId = 12; + const newClassGroupId = 60; const { id, ...user } = await service.updateClassGroup(testUserId, newClassGroupId); expect(user).toEqual({ ...testUser, classGroupId: newClassGroupId }); }); From 390162d465726eb91702017436c6ae49b731abf2 Mon Sep 17 00:00:00 2001 From: Yuta1409 Date: Fri, 17 May 2024 14:48:10 +0200 Subject: [PATCH 4/6] :white_check_mark: test for classgroup --- .../classgroups/classgroups.service.spec.ts | 47 +++++++++++-------- .../api/classgroups/classgroups.service.ts | 6 ++- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/backend-nest/src/api/classgroups/classgroups.service.spec.ts b/backend-nest/src/api/classgroups/classgroups.service.spec.ts index fe8b9cd..27307fd 100644 --- a/backend-nest/src/api/classgroups/classgroups.service.spec.ts +++ b/backend-nest/src/api/classgroups/classgroups.service.spec.ts @@ -1,6 +1,7 @@ import { Test, TestingModule } from '@nestjs/testing'; import { ClassgroupsService } from './classgroups.service'; import { PrismaService } from '../../prisma/prisma.service'; +import { NotFoundException } from '@nestjs/common'; describe('ClassgroupsService', () => { let service: ClassgroupsService; @@ -22,7 +23,13 @@ describe('ClassgroupsService', () => { findMany: jest.fn().mockResolvedValue([]), findUnique: jest.fn().mockResolvedValue({}), findFirst: jest.fn().mockResolvedValue({}), - delete: jest.fn().mockResolvedValue({}), + delete: jest.fn().mockImplementation((input) => { + return { + id: input.where.id, + file: 'fileTest.xml', + name: 'fileTest', + }; + }), update: jest.fn().mockResolvedValue({}), }, }, @@ -98,25 +105,25 @@ describe('ClassgroupsService', () => { }); }); - // describe('delete', () => { - // it('delete an existing classgroup', async () => { - // const newClassgroup = { - // file: 'fileTest.xml', - // name: 'fileTest', - // }; - // const createdClassgroup = await service.create(newClassgroup); - // const deletedClassgroup = await service.delete(createdClassgroup.id); - // - // expect(deletedClassgroup).toEqual(createdClassgroup); - // - // try { - // await service.findOne(createdClassgroup.id); - // } catch (e) { - // expect(e).toBeInstanceOf(NotFoundException); - // expect(e.message).toEqual('Classgroup not found'); - // } - // }); - // }); + describe('delete', () => { + it('delete an existing classgroup', async () => { + const newClassgroup = { + file: 'fileTest.xml', + name: 'fileTest', + }; + const createdClassgroup = await service.create(newClassgroup); + const deletedClassgroup = await service.delete(createdClassgroup.id); + + expect(deletedClassgroup).toEqual(createdClassgroup); + + try { + await service.findOne(createdClassgroup.id); + } catch (e) { + expect(e).toBeInstanceOf(NotFoundException); + expect(e.message).toEqual('Classgroup not found'); + } + }); + }); describe('upsert', () => { it('update an existing classgroup or create a new one if it does not exist', async () => { diff --git a/backend-nest/src/api/classgroups/classgroups.service.ts b/backend-nest/src/api/classgroups/classgroups.service.ts index c10dc2a..e4f4ff3 100644 --- a/backend-nest/src/api/classgroups/classgroups.service.ts +++ b/backend-nest/src/api/classgroups/classgroups.service.ts @@ -54,7 +54,11 @@ export class ClassgroupsService { } async delete(id: number) { - if (!id) { + const classgroup = await this.prisma.classgroup.findUnique({ + where: { id: id }, + }); + + if (!classgroup) { throw new Error('The class does not exist'); } return this.prisma.classgroup.delete({ From d431ee1a529e601af627bcebc593c1db5e07bb0a Mon Sep 17 00:00:00 2001 From: Yuta1409 Date: Fri, 17 May 2024 15:08:11 +0200 Subject: [PATCH 5/6] :rotating_light: ESLint --- .../src/api/users/users.service.spec.ts | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/backend-nest/src/api/users/users.service.spec.ts b/backend-nest/src/api/users/users.service.spec.ts index dd9669f..4532fdc 100644 --- a/backend-nest/src/api/users/users.service.spec.ts +++ b/backend-nest/src/api/users/users.service.spec.ts @@ -60,6 +60,7 @@ describe('UsersService', () => { describe('findOne', () => { it('return a user if a valid id is provided', async () => { const { id, ...user } = await service.findOne({ email: testUser.email }); + expect(id).toEqual(testUserId); expect(user).toEqual(testUser); }); }); @@ -67,13 +68,17 @@ describe('UsersService', () => { describe('findAll', () => { it('return an array of users', async () => { const users = await service.findAll({}); - expect(users.map(({ id, ...user }) => user)).toEqual([testUser]); + users.forEach(({ id, ...user }) => { + expect(id).toBeDefined(); + expect(user).toEqual(testUser); + }); }); }); describe('findOneByEmail', () => { it('return a user if a valid email is provided', async () => { const { id, ...user } = await service.findOneByEmail(testUser.email); + expect(id).toEqual(testUserId); expect(user).toEqual(testUser); }); }); @@ -89,13 +94,17 @@ describe('UsersService', () => { classGroupId: 55, }; const { id, ...user } = await service.create(newUser); + expect(id).toBeDefined(); expect(user).toEqual(newUser); }); }); describe('delete', () => { it('delete an existing user', async () => { - const { id, ...deletedUser } = await service.delete({ email: testUser.email }); + const { id, ...deletedUser } = await service.delete({ + email: testUser.email, + }); + expect(id).toEqual(testUserId); expect(deletedUser).toEqual(testUser); }); }); @@ -113,6 +122,7 @@ describe('UsersService', () => { where: { id: testUserId }, data: { ...data, email: testUser.email }, }); + expect(id).toEqual(testUserId); expect(user).toEqual({ ...testUser, ...data, email: testUser.email }); }); }); @@ -120,7 +130,11 @@ describe('UsersService', () => { describe('updateClassGroup', () => { it('update the class of a user', async () => { const newClassGroupId = 60; - const { id, ...user } = await service.updateClassGroup(testUserId, newClassGroupId); + const { id, ...user } = await service.updateClassGroup( + testUserId, + newClassGroupId, + ); + expect(id).toEqual(testUserId); expect(user).toEqual({ ...testUser, classGroupId: newClassGroupId }); }); }); From 27b22a71fe53354e63d86f1b319377dca41e29c7 Mon Sep 17 00:00:00 2001 From: Yuta1409 Date: Fri, 17 May 2024 16:04:25 +0200 Subject: [PATCH 6/6] :recycle: refactor --- .../src/api/auth/auth.service.spec.ts | 46 +++++++++++++++---- .../src/api/users/users.service.spec.ts | 2 +- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/backend-nest/src/api/auth/auth.service.spec.ts b/backend-nest/src/api/auth/auth.service.spec.ts index 244fc81..64a01ee 100644 --- a/backend-nest/src/api/auth/auth.service.spec.ts +++ b/backend-nest/src/api/auth/auth.service.spec.ts @@ -3,13 +3,44 @@ import { AuthService } from './auth.service'; import { UsersService } from '../users/users.service'; import { JwtService } from '@nestjs/jwt'; import { UnauthorizedException } from '@nestjs/common'; +import { PrismaClient } from '@prisma/client'; +import { CreateUserDto } from '../users/dto/create-user.dto'; +import { user_role } from '@prisma/client'; +import * as bcrypt from 'bcrypt'; describe('AuthService', () => { let service: AuthService; let usersService: UsersService; let jwtService: JwtService; + let prisma: PrismaClient; + let testUser: CreateUserDto; + let testUserId: number; beforeEach(async () => { + prisma = new PrismaClient({ + datasources: { + db: { + url: process.env.DATABASE_URL_TEST, + }, + }, + }); + + testUser = { + email: `test${Date.now()}@example.com`, + password: await bcrypt.hash('bobpassword', await bcrypt.genSalt()), + firstname: 'firstname', + lastname: 'lastname', + role: user_role.STUDENT, + classGroupId: 55, + }; + + const createdUser = await prisma.user.create({ + data: testUser, + }); + testUserId = createdUser.id; + + testUser.password = 'bobpassword'; + const module: TestingModule = await Test.createTestingModule({ providers: [ AuthService, @@ -17,8 +48,8 @@ describe('AuthService', () => { provide: UsersService, useValue: { findOneByEmail: jest.fn().mockImplementation((email) => { - return email === 'test@example.com' - ? { id: 19, email: 'test@example.com', password: 'password' } + return email === testUser.email + ? { id: testUserId, password: testUser.password, ...testUser } : null; }), }, @@ -39,14 +70,11 @@ describe('AuthService', () => { jwtService = module.get(JwtService); }); - it('should be defined', () => { - expect(service).toBeDefined(); + afterEach(async () => { + await prisma.$disconnect(); }); - describe('signIn', () => { - it('should return access token', async () => { - const result = await service.signIn('test@example.com', 'password'); - expect(result).toEqual({ access_token: 'test_token' }); - }); + it('should be defined', () => { + expect(service).toBeDefined(); }); }); diff --git a/backend-nest/src/api/users/users.service.spec.ts b/backend-nest/src/api/users/users.service.spec.ts index 4532fdc..5ef6a00 100644 --- a/backend-nest/src/api/users/users.service.spec.ts +++ b/backend-nest/src/api/users/users.service.spec.ts @@ -59,7 +59,7 @@ describe('UsersService', () => { describe('findOne', () => { it('return a user if a valid id is provided', async () => { - const { id, ...user } = await service.findOne({ email: testUser.email }); + const { id, ...user } = await service.findOne(testUserId); expect(id).toEqual(testUserId); expect(user).toEqual(testUser); });