Skip to content

Commit

Permalink
Merge pull request #642 from project-violet/server-tests
Browse files Browse the repository at this point in the history
Add violet-server tests
  • Loading branch information
violet-dev authored Feb 15, 2025
2 parents 5762c30 + d35d459 commit 3576475
Show file tree
Hide file tree
Showing 3 changed files with 344 additions and 38 deletions.
166 changes: 133 additions & 33 deletions violet-server/src/auth/auth.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,149 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { ConfigModule } from '@nestjs/config';
import { HmacAuthGuard } from './guards/hmac.guard';
import { JwtModule } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import { UserRepository } from 'src/user/user.repository';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserModule } from 'src/user/user.module';
import { MySQLConfigModule } from 'src/config/config.module';
import { MySQLConfigService } from 'src/config/config.service';
import { envValidationSchema } from 'src/app.module';
import { BadRequestException, HttpException } from '@nestjs/common';
import { User } from 'src/user/entity/user.entity';

describe('AuthService', () => {
let service: AuthService;
let controller: AuthController;
let userRepository: UserRepository;
let jwtService: JwtService;
let configService: ConfigService;

const mockUserRepository = {
findOneBy: jest.fn(),
update: jest.fn(),
};

const mockJwtService = {
sign: jest.fn(),
signAsync: jest.fn(),
};

const mockConfigService = {
get: jest.fn(),
};


beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [UserRepository, AuthService],
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: '.test.env',
validationSchema: envValidationSchema,
}),
JwtModule.register({}),
UserModule,
TypeOrmModule.forRootAsync({
imports: [MySQLConfigModule],
useClass: MySQLConfigService,
inject: [MySQLConfigService],
}),
providers: [
AuthService,
{
provide: UserRepository,
useValue: mockUserRepository,
},
{
provide: JwtService,
useValue: mockJwtService,
},
{
provide: ConfigService,
useValue: mockConfigService,
},
],
controllers: [AuthController],
})
.overrideGuard(HmacAuthGuard)
.useValue({ canActivate: jest.fn(() => true) })
.compile();
}).compile();

service = module.get<AuthService>(AuthService);
controller = module.get<AuthController>(AuthController);
userRepository = module.get<UserRepository>(UserRepository);
jwtService = module.get<JwtService>(JwtService);
configService = module.get<ConfigService>(ConfigService);
});

afterEach(() => {
jest.clearAllMocks();
});

describe('verifyUserAndSignJWT', () => {
const mockUserDto = { userAppId: 'test123' };
const mockUser = { userAppId: 'test123' } as User;
const mockTokens = {
accessToken: 'access-token',
refreshToken: 'refresh-token',
};

it('사용자 검증 및 JWT 발급에 성공해야 합니다', async () => {
mockUserRepository.findOneBy.mockResolvedValue(mockUser);
jest.spyOn(service, 'createJWT').mockResolvedValue(mockTokens);
jest.spyOn(service, 'updateRefreshToken').mockResolvedValue(undefined);

const result = await service.verifyUserAndSignJWT(mockUserDto);

expect(result).toEqual({ user: mockUser, tokens: mockTokens });
expect(mockUserRepository.findOneBy).toHaveBeenCalledWith({
userAppId: mockUserDto.userAppId,
});
});

it('존재하지 않는 사용자일 경우 BadRequestException을 발생시켜야 합니다', async () => {
mockUserRepository.findOneBy.mockResolvedValue(null);

await expect(service.verifyUserAndSignJWT(mockUserDto)).rejects.toThrow(
BadRequestException,
);
});
});

it('should be defined', () => {
expect(service).toBeDefined();
expect(controller).toBeDefined();
describe('refreshTokens', () => {
const mockRefreshToken = 'refresh-token';
const mockUser = { userAppId: 'test123' } as User;
const mockTokens = {
accessToken: 'new-access-token',
refreshToken: 'new-refresh-token',
};

it('리프레시 토큰으로 새로운 토큰 발급에 성공해야 합니다', async () => {
mockUserRepository.findOneBy.mockResolvedValue(mockUser);
jest.spyOn(service, 'createJWT').mockResolvedValue(mockTokens);
jest.spyOn(service, 'updateRefreshToken').mockResolvedValue(undefined);

const result = await service.refreshTokens(mockRefreshToken);

expect(result).toEqual({ tokens: mockTokens, user: mockUser });
expect(mockUserRepository.findOneBy).toHaveBeenCalledWith({
refreshToken: mockRefreshToken,
});
});

it('유효하지 않은 리프레시 토큰일 경우 HttpException을 발생시켜야 합니다', async () => {
mockUserRepository.findOneBy.mockResolvedValue(null);

await expect(service.refreshTokens(mockRefreshToken)).rejects.toThrow(
HttpException,
);
});
});

describe('updateDiscordInfo', () => {
const mockUser = {
userAppId: 'test123',
discordId: 'discord123',
avatar: 'avatar.png',
} as User;

it('디스코드 정보 업데이트에 성공해야 합니다', async () => {
mockUserRepository.update.mockResolvedValue({ affected: 1 });

const result = await service.updateDiscordInfo(mockUser);

expect(result).toEqual({ ok: true });
expect(mockUserRepository.update).toHaveBeenCalledWith(
{ userAppId: mockUser.userAppId },
{ discordId: mockUser.discordId, avatar: mockUser.avatar },
);
});

it('디스코드 정보 업데이트 실패 시 에러를 반환해야 합니다', async () => {
mockUserRepository.update.mockRejectedValue(new Error('Update failed'));

const result = await service.updateDiscordInfo(mockUser);

expect(result).toEqual({
ok: false,
error: new Error('Update failed'),
});
});
});
});
64 changes: 63 additions & 1 deletion violet-server/src/user/user.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,80 @@
import { Test, TestingModule } from '@nestjs/testing';
import { UserService } from './user.service';
import { UserRepository } from './user.repository';
import { UnauthorizedException } from '@nestjs/common';
import { UserRegisterDTO } from './dtos/user-register.dto';

describe('UserService', () => {
let service: UserService;
let repository: UserRepository;

const mockUserRepository = {
isUserExists: jest.fn(),
createUser: jest.fn(),
};

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [UserService],
providers: [
UserService,
{
provide: UserRepository,
useValue: mockUserRepository,
},
],
}).compile();

service = module.get<UserService>(UserService);
repository = module.get<UserRepository>(UserRepository);
});

it('should be defined', () => {
expect(service).toBeDefined();
});

describe('registerUser', () => {
const mockUserRegisterDTO: UserRegisterDTO = {
userAppId: 'test-user-id',
};

it('유저 등록에 성공해야 합니다', async () => {
// Arrange
mockUserRepository.isUserExists.mockResolvedValue(false);
mockUserRepository.createUser.mockResolvedValue(undefined);

// Act
const result = await service.registerUser(mockUserRegisterDTO);

// Assert
expect(result.ok).toBe(true);
expect(mockUserRepository.isUserExists).toHaveBeenCalledWith(mockUserRegisterDTO.userAppId);
expect(mockUserRepository.createUser).toHaveBeenCalledWith(mockUserRegisterDTO);
});

it('이미 존재하는 userAppId인 경우 UnauthorizedException을 발생시켜야 합니다', async () => {
// Arrange
mockUserRepository.isUserExists.mockResolvedValue(true);

// Act
const result = await service.registerUser(mockUserRegisterDTO);

// Assert
expect(result.ok).toBe(false);
expect(result.error).toBeInstanceOf(UnauthorizedException);
expect(mockUserRepository.createUser).toHaveBeenCalledTimes(1);
});

it('예외가 발생한 경우 에러를 포함한 실패 응답을 반환해야 합니다', async () => {
// Arrange
const testError = new Error('테스트 에러');
mockUserRepository.isUserExists.mockRejectedValue(testError);

// Act
const result = await service.registerUser(mockUserRegisterDTO);

// Assert
expect(result.ok).toBe(false);
expect(result.error).toBe(testError);
});
});
});
Loading

0 comments on commit 3576475

Please sign in to comment.