From b69ce1e2bcef54bce670683d3f43f968b05c2d9f Mon Sep 17 00:00:00 2001 From: Ian Willis Date: Mon, 15 Jan 2024 00:54:38 -0500 Subject: [PATCH] test(back): adds tests for user creation in users-service --- .../src/app/dto/queries/user-queries.dto.ts | 4 +- .../app/modules/users/users.service.spec.ts | 286 ++++++++++++++++++ 2 files changed, 288 insertions(+), 2 deletions(-) create mode 100644 apps/backend/src/app/modules/users/users.service.spec.ts diff --git a/apps/backend/src/app/dto/queries/user-queries.dto.ts b/apps/backend/src/app/dto/queries/user-queries.dto.ts index b5de014959..46d033b70a 100644 --- a/apps/backend/src/app/dto/queries/user-queries.dto.ts +++ b/apps/backend/src/app/dto/queries/user-queries.dto.ts @@ -73,7 +73,7 @@ export class UsersGetAllQueryDto }) @IsBigInt({ each: true }) @IsOptional() - readonly steamIDs: string[]; + readonly steamIDs?: string[]; @ApiPropertyOptional({ name: 'mapRank', @@ -85,7 +85,7 @@ export class UsersGetAllQueryDto @Type(() => Number) @IsInt() @IsOptional() - readonly mapRank: number; + readonly mapRank?: number; } export class UsersGetActivitiesQueryDto diff --git a/apps/backend/src/app/modules/users/users.service.spec.ts b/apps/backend/src/app/modules/users/users.service.spec.ts new file mode 100644 index 0000000000..2129ec7f2b --- /dev/null +++ b/apps/backend/src/app/modules/users/users.service.spec.ts @@ -0,0 +1,286 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { UsersService } from './users.service'; +import { mockDeep } from 'jest-mock-extended'; +import { + PRISMA_MOCK_PROVIDER, + PrismaMock +} from '../../../../test/prisma-mock.const'; +import { EXTENDED_PRISMA_SERVICE } from '../database/db.constants'; +import { UsersGetAllQueryDto } from '@momentum/backend/dto'; +import { BadRequestException } from '@nestjs/common/exceptions/bad-request.exception'; +import { + ForbiddenException, + InternalServerErrorException, + ServiceUnavailableException +} from '@nestjs/common'; +import { User } from '@prisma/client'; +import { AuthenticatedUser } from '../auth/auth.interface'; +import { SteamUserSummaryData } from '../steam/steam.interface'; + +describe('UserService', () => { + let usersService: UsersService; + let db: PrismaMock; + + beforeAll(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [UsersService, PRISMA_MOCK_PROVIDER] + }) + .useMocker(mockDeep) + .compile(); + usersService = module.get(UsersService); + db = module.get(EXTENDED_PRISMA_SERVICE); + }); + + it('should be defined', () => { + expect(usersService).toBeDefined(); + expect(db).toBeDefined(); + }); + + describe('getAll', () => { + it('should throw an error when passing both steamID and steamIDs', async () => { + const a: UsersGetAllQueryDto = { + steamID: '123456789', + steamIDs: ['123456789', '999999999'] + }; + await expect(usersService.getAll(a)).rejects.toThrow(BadRequestException); + }); + }); + + describe('findOrCreateFromGame', () => { + it("should throw an error when the steamid's don't match", async () => { + const steamUserSummaryData: SteamUserSummaryData = { + avatar: '', + avatarfull: '', + avatarhash: '', + avatarmedium: '', + communityvisibilitystate: 0, + lastlogoff: 0, + loccountrycode: '', + personaname: '', + personastate: 0, + personastateflags: 0, + primaryclanid: '', + profilestate: 0, + profileurl: '', + realname: '', + timecreated: 0, + steamid: '123456789' + }; + jest + .spyOn(usersService['steamService'], 'getSteamUserSummaryData') + .mockImplementationOnce(() => Promise.resolve(steamUserSummaryData)); + await expect( + usersService.findOrCreateFromGame(BigInt(999999999)) + ).rejects.toThrow(BadRequestException); + }); + it('should throw an error when getSteamUserSummaryData throws and error', async () => { + jest + .spyOn(usersService['steamService'], 'getSteamUserSummaryData') + .mockImplementationOnce(() => Promise.reject('failed to start')); + await expect( + usersService.findOrCreateFromGame(BigInt(123456789)) + ).rejects.toThrow(ServiceUnavailableException); + }); + it('should call findOrCreateUser', async () => { + const steamUserSummaryData: SteamUserSummaryData = { + avatar: '', + avatarfull: '', + avatarhash: '', + avatarmedium: '', + communityvisibilitystate: 0, + lastlogoff: 0, + loccountrycode: '', + personaname: '', + personastate: 0, + personastateflags: 0, + primaryclanid: '', + profilestate: 0, + profileurl: '', + realname: '', + timecreated: 0, + steamid: '123456789' + }; + jest + .spyOn(usersService['steamService'], 'getSteamUserSummaryData') + .mockImplementationOnce(() => Promise.resolve(steamUserSummaryData)); + const spy = jest.spyOn(usersService, 'findOrCreateUser'); + await usersService.findOrCreateFromGame(BigInt(123456789)); + expect(spy).toHaveBeenCalled(); + }); + }); + + describe('findOrCreateFromWeb', () => { + it('should error when profile state is not 1', async () => { + await expect( + usersService.findOrCreateFromWeb({ + avatar: '', + avatarfull: '', + avatarhash: '', + avatarmedium: '', + communityvisibilitystate: 0, + lastlogoff: 0, + loccountrycode: '', + personaname: '', + personastate: 0, + personastateflags: 0, + primaryclanid: '', + profilestate: 2, + profileurl: '', + realname: '', + steamid: '', + timecreated: 0 + }) + ).rejects.toThrow(ForbiddenException); + }); + it('should error when steamid is deleted', async () => { + db.deletedSteamID.findUnique.mockResolvedValueOnce({ + steamID: BigInt(123456789) + } as any); + await expect( + usersService.findOrCreateFromWeb({ + avatar: '', + avatarfull: '', + avatarhash: '', + avatarmedium: '', + communityvisibilitystate: 0, + lastlogoff: 0, + loccountrycode: '', + personaname: '', + personastate: 0, + personastateflags: 0, + primaryclanid: '', + profilestate: 1, + profileurl: '', + realname: '', + steamid: '123456789', + timecreated: 0 + }) + ).rejects.toThrow(ForbiddenException); + }); + it('should call findOrCreateUser', async () => { + const spy = jest.spyOn(usersService, 'findOrCreateUser'); + spy.mockImplementationOnce(() => + Promise.resolve({ + id: 0, + steamID: 0n + }) + ); + await usersService.findOrCreateFromWeb({ + avatar: '', + avatarfull: '', + avatarhash: '', + avatarmedium: '', + communityvisibilitystate: 0, + lastlogoff: 0, + loccountrycode: '', + personaname: '', + personastate: 0, + personastateflags: 0, + primaryclanid: '', + profilestate: 1, + profileurl: '', + realname: '', + steamid: '123456789', + timecreated: 0 + }); + expect(spy).toHaveBeenCalled(); + }); + + it('should error when no user is returned by findOrCreateUser', async () => { + const spy = jest.spyOn(usersService, 'findOrCreateUser'); + spy.mockImplementationOnce(() => Promise.resolve(undefined)); + await expect( + usersService.findOrCreateFromWeb({ + avatar: '', + avatarfull: '', + avatarhash: '', + avatarmedium: '', + communityvisibilitystate: 0, + lastlogoff: 0, + loccountrycode: '', + personaname: '', + personastate: 0, + personastateflags: 0, + primaryclanid: '', + profilestate: 1, + profileurl: '', + realname: '', + steamid: '123456789', + timecreated: 0 + }) + ).rejects.toThrow(InternalServerErrorException); + }); + }); + + describe('findOrCreateUser', () => { + it('should return an existing user', async () => { + const existingUser: User = { + id: 0, + roles: 0, + bans: 0, + steamID: BigInt(123456789), + alias: '', + avatar: '', + country: '', + createdAt: undefined + }; + db.user.findUnique.mockResolvedValueOnce(existingUser as any); + const authUser: AuthenticatedUser = { + id: 0, + steamID: 123456789n + }; + db.user.update.mockResolvedValueOnce(authUser as any); + + const userData = { + steamID: BigInt(123456789), + alias: 'new alias', + avatar: 'new avatar', + country: 'new country' + }; + const spy = jest.spyOn(db['user'], 'update'); + await usersService.findOrCreateUser(userData); + expect(spy).toHaveBeenCalled(); + }); + it('should create a new user', async () => { + const nonExistingUser: User = undefined; + db.user.findUnique.mockResolvedValueOnce(nonExistingUser as any); + + const spy = jest.spyOn(db['user'], 'create'); + + const userData = { + steamID: BigInt(123456789), + alias: '', + avatar: '', + country: '' + }; + await usersService.findOrCreateUser(userData); + + expect(spy).toHaveBeenCalled(); + }); + it('should throw error when using a limited account if the setting is on', async () => { + const nonExistingUser: User = undefined; + db.user.findUnique.mockResolvedValueOnce(nonExistingUser as any); + + jest + .spyOn(usersService['config'], 'getOrThrow') + .mockImplementationOnce(() => { + return true; + }); + jest + .spyOn(usersService['steamService'], 'isAccountLimited') + .mockImplementationOnce(() => { + return Promise.resolve(true); + }); + + const userData = { + steamID: BigInt(123456789), + alias: '', + avatar: '', + country: '' + }; + await expect(usersService.findOrCreateUser(userData)).rejects.toThrow( + ForbiddenException + ); + }); + }); +});