chore: clean codes

This commit is contained in:
hantsy 2025-08-05 10:45:51 +08:00
parent 950543d80c
commit 2a47710c8b
18 changed files with 173 additions and 185 deletions

View File

@ -14,12 +14,11 @@ describe('AppService', () => {
provide: 'LoggerServiceAppService', provide: 'LoggerServiceAppService',
useValue: { useValue: {
constructor: jest.fn(), constructor: jest.fn(),
log: jest.fn() log: jest.fn(),
} },
} },
], ],
}) }).compile();
.compile();
service = app.get<AppService>(AppService); service = app.get<AppService>(AppService);
logger = app.get<LoggerService>('LoggerServiceAppService'); logger = app.get<LoggerService>('LoggerServiceAppService');
@ -29,11 +28,11 @@ describe('AppService', () => {
}); });
it('getHello', async () => { it('getHello', async () => {
jest.spyOn(logger, "log").mockImplementation((message: string) => { jest.spyOn(logger, 'log').mockImplementation((message: string) => {
console.log(message); console.log(message);
}) });
const result = service.getHello(); const result = service.getHello();
expect(result).toEqual('Hello World!'); expect(result).toEqual('Hello World!');
expect(logger.log).toBeCalledWith("Hello World"); expect(logger.log).toHaveBeenCalledWith('Hello World');
}) });
}); });

View File

@ -4,7 +4,7 @@ import { LoggerService } from './logger/logger.service';
@Injectable() @Injectable()
export class AppService { export class AppService {
constructor(@Logger('AppService') private logger: LoggerService) {} constructor(@Logger('AppService') private readonly logger: LoggerService) {}
getHello(): string { getHello(): string {
this.logger.log('Hello World'); this.logger.log('Hello World');

View File

@ -47,7 +47,7 @@ describe('AuthController', () => {
), ),
); );
expect(token).toBeTruthy(); expect(token).toBeTruthy();
expect(authService.login).toBeCalled(); expect(authService.login).toHaveBeenCalled();
}); });
}); });
}); });

View File

@ -51,7 +51,7 @@ describe('AuthService', () => {
password: 'password', password: 'password',
email: 'hantsy@example.com', email: 'hantsy@example.com',
roles: [RoleType.USER], roles: [RoleType.USER],
comparePassword: (password: string) => of(true) comparePassword: (password: string) => of(true),
} as User); } as User);
}); });
@ -63,8 +63,8 @@ describe('AuthService', () => {
expect(data.roles).toEqual([RoleType.USER]); expect(data.roles).toEqual([RoleType.USER]);
//verify //verify
expect(userService.findByUsername).toBeCalledTimes(1); expect(userService.findByUsername).toHaveBeenCalledTimes(1);
expect(userService.findByUsername).toBeCalledWith('test'); expect(userService.findByUsername).toHaveBeenCalledWith('test');
}, },
}); });
}); });
@ -78,16 +78,14 @@ describe('AuthService', () => {
password: 'password', password: 'password',
email: 'hantsy@example.com', email: 'hantsy@example.com',
roles: [RoleType.USER], roles: [RoleType.USER],
comparePassword: (password: string) => of(false) comparePassword: (password: string) => of(false),
} as User); } as User);
}); });
service service.validateUser('test', 'password001').subscribe({
.validateUser('test', 'password001') next: (data) => console.log(data),
.subscribe({ error: (error) => expect(error).toBeDefined(),
next: (data) => console.log(data), });
error: error => expect(error).toBeDefined()
});
}); });
it('if user is not found', async () => { it('if user is not found', async () => {
@ -97,13 +95,10 @@ describe('AuthService', () => {
return of(null as User); return of(null as User);
}); });
service.validateUser('test', 'password001').subscribe({
service next: (data) => console.log(data),
.validateUser('test', 'password001') error: (error) => expect(error).toBeDefined(),
.subscribe({ });
next: (data) => console.log(data),
error: error => expect(error).toBeDefined()
});
}); });
}); });
@ -121,8 +116,8 @@ describe('AuthService', () => {
.subscribe({ .subscribe({
next: (data) => { next: (data) => {
expect(data.access_token).toBe('test'); expect(data.access_token).toBe('test');
expect(jwtService.signAsync).toBeCalledTimes(1); expect(jwtService.signAsync).toHaveBeenCalledTimes(1);
expect(jwtService.signAsync).toBeCalledWith({ expect(jwtService.signAsync).toHaveBeenCalledWith({
upn: 'test', upn: 'test',
sub: '_id', sub: '_id',
email: 'hantsy@example.com', email: 'hantsy@example.com',

View File

@ -45,7 +45,7 @@ describe('RolesGuard', () => {
const result = await guard.canActivate(context); const result = await guard.canActivate(context);
expect(result).toBeTruthy(); expect(result).toBeTruthy();
expect(reflector.get).toBeCalled(); expect(reflector.get).toHaveBeenCalled();
}); });
it('should return true if the `HasRoles` decorator is set', async () => { it('should return true if the `HasRoles` decorator is set', async () => {
@ -63,7 +63,7 @@ describe('RolesGuard', () => {
const result = await guard.canActivate(context); const result = await guard.canActivate(context);
expect(result).toBeTruthy(); expect(result).toBeTruthy();
expect(reflector.get).toBeCalled(); expect(reflector.get).toHaveBeenCalled();
}); });
it('should return false if the `HasRoles` decorator is set but role is not allowed', async () => { it('should return false if the `HasRoles` decorator is set but role is not allowed', async () => {
@ -79,7 +79,7 @@ describe('RolesGuard', () => {
const result = await guard.canActivate(context); const result = await guard.canActivate(context);
expect(result).toBeFalsy(); expect(result).toBeFalsy();
expect(reflector.get).toBeCalled(); expect(reflector.get).toHaveBeenCalled();
}); });
}); });
@ -189,7 +189,7 @@ describe('RoelsGuard(jest-mock-extended)', () => {
const result = await guard.canActivate(context); const result = await guard.canActivate(context);
expect(result).toBeTruthy(); expect(result).toBeTruthy();
expect(reflecter.get).toBeCalledTimes(1); expect(reflecter.get).toHaveBeenCalledTimes(1);
}); });
it('should return true if the `HasRoles` decorator is set', async () => { it('should return true if the `HasRoles` decorator is set', async () => {
@ -210,7 +210,7 @@ describe('RoelsGuard(jest-mock-extended)', () => {
const result = await guard.canActivate(context); const result = await guard.canActivate(context);
expect(result).toBeTruthy(); expect(result).toBeTruthy();
expect(reflecter.get).toBeCalledTimes(1); expect(reflecter.get).toHaveBeenCalledTimes(1);
}); });
it('should return false if the `HasRoles` decorator is set but role is not allowed', async () => { it('should return false if the `HasRoles` decorator is set but role is not allowed', async () => {
@ -233,6 +233,6 @@ describe('RoelsGuard(jest-mock-extended)', () => {
const result = await guard.canActivate(context); const result = await guard.canActivate(context);
expect(result).toBeFalsy(); expect(result).toBeFalsy();
expect(reflecter.get).toBeCalledTimes(1); expect(reflecter.get).toHaveBeenCalledTimes(1);
}); });
}); });

View File

@ -15,13 +15,12 @@ describe('JwtStrategy', () => {
{ {
provide: jwtConfig.KEY, provide: jwtConfig.KEY,
useValue: { useValue: {
secretKey: "test", secretKey: 'test',
expiresIn:'100s' expiresIn: '100s',
}, },
}, },
], ],
}) }).compile();
.compile();
strategy = app.get<JwtStrategy>(JwtStrategy); strategy = app.get<JwtStrategy>(JwtStrategy);
config = app.get<ConfigType<typeof jwtConfig>>(jwtConfig.KEY); config = app.get<ConfigType<typeof jwtConfig>>(jwtConfig.KEY);
@ -29,13 +28,13 @@ describe('JwtStrategy', () => {
describe('validate', () => { describe('validate', () => {
it('should return user principal if user and password is provided ', async () => { it('should return user principal if user and password is provided ', async () => {
expect(config.secretKey).toBe('test') expect(config.secretKey).toBe('test');
expect(config.expiresIn).toBe('100s') expect(config.expiresIn).toBe('100s');
const user = await strategy.validate({ const user = strategy.validate({
upn: "test", upn: 'test',
sub: 'testid', sub: 'testid',
email: "test@example.com", email: 'test@example.com',
roles: [RoleType.USER] roles: [RoleType.USER],
}); });
expect(user.username).toEqual('test'); expect(user.username).toEqual('test');
expect(user.id).toEqual('testid'); expect(user.id).toEqual('testid');
@ -59,13 +58,12 @@ describe('JwtStrategy(call supper)', () => {
it('call super', () => { it('call super', () => {
const config = mock<ConfigType<typeof jwtConfig>>(); const config = mock<ConfigType<typeof jwtConfig>>();
config.secretKey="test"; config.secretKey = 'test';
new JwtStrategy(config); new JwtStrategy(config);
expect(parentMock.mock.calls.length).toBe(1); expect(parentMock.mock.calls.length).toBe(1);
expect(parentMock.mock.calls[0][0].jwtFromRequest).toBeDefined(); expect(parentMock.mock.calls[0][0].jwtFromRequest).toBeDefined();
expect(parentMock.mock.calls[0][0].ignoreExpiration).toBeFalsy(); expect(parentMock.mock.calls[0][0].ignoreExpiration).toBeFalsy();
expect(parentMock.mock.calls[0][0].secretOrKey).toEqual("test"); expect(parentMock.mock.calls[0][0].secretOrKey).toEqual('test');
});
})
}); });

View File

@ -17,7 +17,7 @@ describe('LocalStrategy', () => {
useValue: { useValue: {
constructor: jest.fn(), constructor: jest.fn(),
login: jest.fn(), login: jest.fn(),
validateUser: jest.fn() validateUser: jest.fn(),
}, },
}, },
], ],
@ -41,7 +41,7 @@ describe('LocalStrategy', () => {
}); });
const user = await strategy.validate('test', 'pass'); const user = await strategy.validate('test', 'pass');
expect(user.username).toEqual('test'); expect(user.username).toEqual('test');
expect(authService.validateUser).toBeCalledWith('test', 'pass'); expect(authService.validateUser).toHaveBeenCalledWith('test', 'pass');
}); });
it('should throw UnauthorizedException if user is not valid ', async () => { it('should throw UnauthorizedException if user is not valid ', async () => {
@ -55,9 +55,9 @@ describe('LocalStrategy', () => {
const user = await strategy.validate('test', 'pass'); const user = await strategy.validate('test', 'pass');
} catch (e) { } catch (e) {
//console.log(e) //console.log(e)
expect(e).toBeDefined() expect(e).toBeDefined();
} }
expect(authService.validateUser).toBeCalledWith('test', 'pass'); expect(authService.validateUser).toHaveBeenCalledWith('test', 'pass');
}); });
}); });
}); });
@ -79,9 +79,9 @@ describe('LocalStrategy(call supper)', () => {
it('call super', () => { it('call super', () => {
new LocalStrategy(mock<AuthService>()); new LocalStrategy(mock<AuthService>());
expect(parentMock.mock.calls.length).toBe(1); expect(parentMock.mock.calls.length).toBe(1);
expect(parentMock).toBeCalledWith({ expect(parentMock).toHaveBeenCalledWith({
usernameField: 'username', usernameField: 'username',
passwordField: 'password', passwordField: 'password',
}); });
}) });
}); });

View File

@ -31,16 +31,16 @@ describe('UserSchema', () => {
it('should called Schame.virtual ', () => { it('should called Schame.virtual ', () => {
expect(UserSchema).toBeDefined(); expect(UserSchema).toBeDefined();
expect(getMock).toBeCalled(); expect(getMock).toHaveBeenCalled();
expect(getMock).toBeCalledWith(anyFunction()); expect(getMock).toHaveBeenCalledWith(anyFunction());
expect(virtualMock).toBeCalled(); expect(virtualMock).toHaveBeenCalled();
expect(virtualMock).toHaveBeenNthCalledWith(1, 'name'); expect(virtualMock).toHaveBeenNthCalledWith(1, 'name');
expect(virtualMock).toHaveBeenNthCalledWith(2, 'posts', { expect(virtualMock).toHaveBeenNthCalledWith(2, 'posts', {
foreignField: 'createdBy', foreignField: 'createdBy',
localField: '_id', localField: '_id',
ref: 'Post', ref: 'Post',
}); });
expect(virtualMock).toBeCalledTimes(2); expect(virtualMock).toHaveBeenCalledTimes(2);
}); });
}); });
@ -53,8 +53,8 @@ describe('preSaveHook', () => {
}; };
contextMock.isModified.mockReturnValueOnce(false); contextMock.isModified.mockReturnValueOnce(false);
await preSaveHook.call(contextMock, nextMock); await preSaveHook.call(contextMock, nextMock);
expect(contextMock.isModified).toBeCalledWith('password'); expect(contextMock.isModified).toHaveBeenCalledWith('password');
expect(nextMock).toBeCalledTimes(1); expect(nextMock).toHaveBeenCalledTimes(1);
}); });
test('should set password when password is modified', async () => { test('should set password when password is modified', async () => {
@ -66,9 +66,9 @@ describe('preSaveHook', () => {
}; };
contextMock.isModified.mockReturnValueOnce(true); contextMock.isModified.mockReturnValueOnce(true);
await preSaveHook.call(contextMock, nextMock); await preSaveHook.call(contextMock, nextMock);
expect(contextMock.isModified).toBeCalledWith('password'); expect(contextMock.isModified).toHaveBeenCalledWith('password');
expect(nextMock).toBeCalledTimes(1); expect(nextMock).toHaveBeenCalledTimes(1);
expect(contextMock.set).toBeCalledTimes(1); expect(contextMock.set).toHaveBeenCalledTimes(1);
}); });
}); });

View File

@ -18,14 +18,14 @@ describe('LoggerService', () => {
it('log', () => { it('log', () => {
const consoleSpy = jest.spyOn(global.console, 'log'); const consoleSpy = jest.spyOn(global.console, 'log');
service.log("hello"); service.log('hello');
expect(consoleSpy).toBeCalledWith('hello'); expect(consoleSpy).toHaveBeenCalledWith('hello');
}); });
it('log with prefix', () => { it('log with prefix', () => {
const consoleSpy = jest.spyOn(global.console, 'log'); const consoleSpy = jest.spyOn(global.console, 'log');
service.setPrefix("H") service.setPrefix('H');
service.log("hello"); service.log('hello');
expect(consoleSpy).toBeCalledWith('[H] hello'); expect(consoleSpy).toHaveBeenCalledWith('[H] hello');
}); });
}); });

View File

@ -207,8 +207,8 @@ describe('Post Controller', () => {
it('should get all posts(useValue: jest mocking)', async () => { it('should get all posts(useValue: jest mocking)', async () => {
const result = await lastValueFrom(controller.getAllPosts('test', 10, 0)); const result = await lastValueFrom(controller.getAllPosts('test', 10, 0));
expect(result[0]._id).toEqual('testid'); expect(result[0]._id).toEqual('testid');
expect(postService.findAll).toBeCalled(); expect(postService.findAll).toHaveBeenCalled();
expect(postService.findAll).lastCalledWith('test', 0, 10); expect(postService.findAll).toHaveBeenLastCalledWith('test', 0, 10);
}); });
}); });

View File

@ -112,7 +112,7 @@ describe('PostService', () => {
const result = await lastValueFrom(service.findAll('Generate', 0, 10)); const result = await lastValueFrom(service.findAll('Generate', 0, 10));
expect(result.length).toBe(1); expect(result.length).toBe(1);
expect(model.find).lastCalledWith({ expect(model.find).toHaveBeenLastCalledWith({
title: { $regex: '.*' + 'Generate' + '.*' }, title: { $regex: '.*' + 'Generate' + '.*' },
}); });
}); });
@ -173,13 +173,13 @@ describe('PostService', () => {
const data = await lastValueFrom(service.save(toCreated)); const data = await lastValueFrom(service.save(toCreated));
expect(data[0]._id).toBe('5ee49c3115a4e75254bb732e'); expect(data[0]._id).toBe('5ee49c3115a4e75254bb732e');
expect(model.create).toBeCalledWith({ expect(model.create).toHaveBeenCalledWith({
...toCreated, ...toCreated,
createdBy: { createdBy: {
_id: 'dummyId', _id: 'dummyId',
}, },
}); });
expect(model.create).toBeCalledTimes(1); expect(model.create).toHaveBeenCalledTimes(1);
}); });
describe('update', () => { describe('update', () => {
@ -197,7 +197,7 @@ describe('PostService', () => {
service.update('5ee49c3115a4e75254bb732e', toUpdated).subscribe({ service.update('5ee49c3115a4e75254bb732e', toUpdated).subscribe({
next: (data) => { next: (data) => {
expect(data).toBeTruthy(); expect(data).toBeTruthy();
expect(model.findOneAndUpdate).toBeCalled(); expect(model.findOneAndUpdate).toHaveBeenCalled();
}, },
error: (error) => console.log(error), error: (error) => console.log(error),
complete: done(), complete: done(),
@ -238,7 +238,7 @@ describe('PostService', () => {
service.deleteById('anystring').subscribe({ service.deleteById('anystring').subscribe({
next: (data) => { next: (data) => {
expect(data).toBeTruthy(); expect(data).toBeTruthy();
expect(model.findOneAndDelete).toBeCalled(); expect(model.findOneAndDelete).toHaveBeenCalled();
}, },
error: (error) => console.log(error), error: (error) => console.log(error),
complete: done(), complete: done(),
@ -252,7 +252,7 @@ describe('PostService', () => {
service.deleteById('anystring').subscribe({ service.deleteById('anystring').subscribe({
error: (error) => { error: (error) => {
expect(error).toBeDefined(); expect(error).toBeDefined();
expect(model.findOneAndDelete).toBeCalledTimes(1); expect(model.findOneAndDelete).toHaveBeenCalledTimes(1);
}, },
complete: done(), complete: done(),
}); });
@ -286,7 +286,7 @@ describe('PostService', () => {
service.createCommentFor('test', comment), service.createCommentFor('test', comment),
); );
expect(result.content).toEqual('test'); expect(result.content).toEqual('test');
expect(commentModel.create).toBeCalledWith({ expect(commentModel.create).toHaveBeenCalledWith({
...comment, ...comment,
post: { _id: 'test' }, post: { _id: 'test' },
createdBy: { _id: 'dummyId' }, createdBy: { _id: 'dummyId' },
@ -311,6 +311,6 @@ describe('PostService', () => {
const result = await lastValueFrom(service.commentsOf('test')); const result = await lastValueFrom(service.commentsOf('test'));
expect(result.length).toBe(1); expect(result.length).toBe(1);
expect(result[0].content).toEqual('content'); expect(result[0].content).toEqual('content');
expect(commentModel.find).toBeCalledWith({ post: { _id: 'test' } }); expect(commentModel.find).toHaveBeenCalledWith({ post: { _id: 'test' } });
}); });
}); });

View File

@ -47,7 +47,7 @@ describe('SendgridService', () => {
.mockResolvedValue({} as any); .mockResolvedValue({} as any);
await lastValueFrom(service.send(msg)); await lastValueFrom(service.send(msg));
expect(sendSpy).toBeCalledTimes(1); expect(sendSpy).toHaveBeenCalledTimes(1);
expect(sendSpy).toBeCalledWith(msg, false); expect(sendSpy).toHaveBeenCalledWith(msg, false);
}); });
}); });

View File

@ -1,7 +1,7 @@
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
import { RegisterController } from './register.controller'; import { RegisterController } from './register.controller';
import { UserService } from './user.service'; import { UserService } from './user.service';
import { of, lastValueFrom } from 'rxjs'; import { of } from 'rxjs';
import { User } from 'database/user.model'; import { User } from 'database/user.model';
import { RegisterDto } from './register.dto'; import { RegisterDto } from './register.dto';
@ -50,17 +50,15 @@ describe('Register Controller', () => {
send: jest.fn().mockReturnThis(), send: jest.fn().mockReturnThis(),
} as any; } as any;
try { try {
await lastValueFrom( await controller.register(
controller.register( { username: 'hantsy' } as RegisterDto,
{ username: 'hantsy' } as RegisterDto, responseMock,
responseMock,
),
); );
} catch (e) { } catch (e) {
expect(e).toBeDefined(); expect(e).toBeDefined();
expect(existsByUsernameSpy).toBeCalledWith('hantsy'); expect(existsByUsernameSpy).toHaveBeenCalledWith('hantsy');
expect(existsByEmailSpy).toBeCalledTimes(0); expect(existsByEmailSpy).toHaveBeenCalledTimes(0);
expect(saveSpy).toBeCalledTimes(0); expect(saveSpy).toHaveBeenCalledTimes(0);
} }
}); });
@ -81,17 +79,15 @@ describe('Register Controller', () => {
send: jest.fn().mockReturnThis(), send: jest.fn().mockReturnThis(),
} as any; } as any;
try { try {
await lastValueFrom( await controller.register(
controller.register( { username: 'hantsy', email: 'hantsy@example.com' } as RegisterDto,
{ username: 'hantsy', email: 'hantsy@example.com' } as RegisterDto, responseMock,
responseMock,
),
); );
} catch (e) { } catch (e) {
expect(e).toBeDefined(); expect(e).toBeDefined();
expect(existsByUsernameSpy).toBeCalledWith('hantsy'); expect(existsByUsernameSpy).toHaveBeenCalledWith('hantsy');
expect(existsByEmailSpy).toBeCalledWith('hantsy@example.com'); expect(existsByEmailSpy).toHaveBeenCalledWith('hantsy@example.com');
expect(saveSpy).toBeCalledTimes(0); expect(saveSpy).toHaveBeenCalledTimes(0);
} }
}); });
@ -116,19 +112,17 @@ describe('Register Controller', () => {
const statusSpy = jest.spyOn(responseMock, 'status'); const statusSpy = jest.spyOn(responseMock, 'status');
const sendSpy = jest.spyOn(responseMock, 'send'); const sendSpy = jest.spyOn(responseMock, 'send');
await lastValueFrom( await controller.register(
controller.register( { username: 'hantsy', email: 'hantsy@example.com' } as RegisterDto,
{ username: 'hantsy', email: 'hantsy@example.com' } as RegisterDto, responseMock,
responseMock,
),
); );
expect(existsByUsernameSpy).toBeCalledWith('hantsy'); expect(existsByUsernameSpy).toHaveBeenCalledWith('hantsy');
expect(existsByEmailSpy).toBeCalledWith('hantsy@example.com'); expect(existsByEmailSpy).toHaveBeenCalledWith('hantsy@example.com');
expect(saveSpy).toBeCalledTimes(1); expect(saveSpy).toHaveBeenCalledTimes(1);
expect(locationSpy).toBeCalled(); expect(locationSpy).toHaveBeenCalled();
expect(statusSpy).toBeCalled(); expect(statusSpy).toHaveBeenCalled();
expect(sendSpy).toBeCalled(); expect(sendSpy).toHaveBeenCalled();
}); });
}); });
}); });

View File

@ -1,45 +1,38 @@
import { Body, ConflictException, Controller, Post, Res } from '@nestjs/common'; import { Body, ConflictException, Controller, Post, Res } from '@nestjs/common';
import { Response } from 'express'; import { Response } from 'express';
import { Observable } from 'rxjs'; import { lastValueFrom } from 'rxjs';
import { mergeMap, map } from 'rxjs/operators';
import { RegisterDto } from './register.dto'; import { RegisterDto } from './register.dto';
import { UserService } from './user.service'; import { UserService } from './user.service';
@Controller('register') @Controller('register')
export class RegisterController { export class RegisterController {
constructor(private userService: UserService) { } constructor(private readonly userService: UserService) {}
@Post() @Post()
register( async register(
@Body() registerDto: RegisterDto, @Body() registerDto: RegisterDto,
@Res() res: Response): Observable<Response> { @Res() res: Response,
const username = registerDto.username; ): Promise<Response> {
const { username, email } = registerDto;
return this.userService.existsByUsername(username).pipe( const existsByUsername = await lastValueFrom(
mergeMap(exists => { this.userService.existsByUsername(username),
if (exists) { );
throw new ConflictException(`username:${username} is existed`) if (existsByUsername) {
} throw new ConflictException(`username:${username} is existed`);
else {
const email = registerDto.email;
return this.userService.existsByEmail(email).pipe(
mergeMap(exists => {
if (exists) {
throw new ConflictException(`email:${email} is existed`)
}
else {
return this.userService.register(registerDto).pipe(
map(user =>
res.location('/users/' + user.id)
.status(201)
.send()
)
);
}
})
);
}
})
);
} }
const existsByEmail = await lastValueFrom(
this.userService.existsByEmail(email),
);
if (existsByEmail) {
throw new ConflictException(`email:${email} is existed`);
}
const user = await lastValueFrom(this.userService.register(registerDto));
return res
.location('/users/' + user.id)
.status(201)
.send();
}
} }

View File

@ -42,6 +42,6 @@ describe('UserController', () => {
const user = await lastValueFrom(controller.getUser('id', false)); const user = await lastValueFrom(controller.getUser('id', false));
expect(user.firstName).toBe('hantsy'); expect(user.firstName).toBe('hantsy');
expect(user.lastName).toBe('bai'); expect(user.lastName).toBe('bai');
expect(service.findById).toBeCalledWith('id', false); expect(service.findById).toHaveBeenCalledWith('id', false);
}); });
}); });

View File

@ -1,18 +1,23 @@
import { Controller, DefaultValuePipe, Get, Param, Query } from '@nestjs/common'; import {
Controller,
DefaultValuePipe,
Get,
Param,
Query,
} from '@nestjs/common';
import { User } from 'database/user.model'; import { User } from 'database/user.model';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { ParseObjectIdPipe } from '../shared/pipe/parse-object-id.pipe'; import { ParseObjectIdPipe } from '../shared/pipe/parse-object-id.pipe';
import { UserService } from './user.service'; import { UserService } from './user.service';
@Controller({ path: "/users" }) @Controller({ path: '/users' })
export class UserController { export class UserController {
constructor(private readonly userService: UserService) {}
constructor(private userService: UserService) { }
@Get(':id') @Get(':id')
getUser( getUser(
@Param('id', ParseObjectIdPipe) id: string, @Param('id', ParseObjectIdPipe) id: string,
@Query('withPosts', new DefaultValuePipe(false)) withPosts?: boolean @Query('withPosts', new DefaultValuePipe(false)) withPosts?: boolean,
): Observable<Partial<User>> { ): Observable<Partial<User>> {
return this.userService.findById(id, withPosts); return this.userService.findById(id, withPosts);
} }

View File

@ -84,7 +84,10 @@ describe('UserService', () => {
}); });
const result = await lastValueFrom(service.register(sampleData)); const result = await lastValueFrom(service.register(sampleData));
expect(saveSpy).toBeCalledWith({ ...sampleData, roles: [RoleType.USER] }); expect(saveSpy).toHaveBeenCalledWith({
...sampleData,
roles: [RoleType.USER],
});
expect(result._id).toBeDefined(); expect(result._id).toBeDefined();
//expect(sendSpy).toBeCalledWith(msg); //expect(sendSpy).toBeCalledWith(msg);
//expect(pipeSpy).toBeCalled(); //expect(pipeSpy).toBeCalled();
@ -98,7 +101,7 @@ describe('UserService', () => {
username: 'hantsy', username: 'hantsy',
email: 'hantsy@example.com', email: 'hantsy@example.com',
} as User), } as User),
} as any), }) as any,
); );
const foundUser = await lastValueFrom(service.findByUsername('hantsy')); const foundUser = await lastValueFrom(service.findByUsername('hantsy'));
@ -106,21 +109,20 @@ describe('UserService', () => {
username: 'hantsy', username: 'hantsy',
email: 'hantsy@example.com', email: 'hantsy@example.com',
}); });
expect(model.findOne).lastCalledWith({ username: 'hantsy' }); expect(model.findOne).toHaveBeenLastCalledWith({ username: 'hantsy' });
expect(model.findOne).toBeCalledTimes(1); expect(model.findOne).toHaveBeenCalledTimes(1);
}); });
describe('findById', () => { describe('findById', () => {
it('return one result', async () => { it('return one result', async () => {
jest.spyOn(model, 'findOne') jest.spyOn(model, 'findOne').mockImplementation(
.mockImplementation(
(filter?: FilterQuery<User>) => (filter?: FilterQuery<User>) =>
({ ({
exec: jest.fn().mockResolvedValue({ exec: jest.fn().mockResolvedValue({
username: 'hantsy', username: 'hantsy',
email: 'hantsy@example.com', email: 'hantsy@example.com',
} as User), } as User),
} as any), }) as any,
); );
const foundUser = await lastValueFrom(service.findById('hantsy')); const foundUser = await lastValueFrom(service.findById('hantsy'));
@ -128,16 +130,17 @@ describe('UserService', () => {
username: 'hantsy', username: 'hantsy',
email: 'hantsy@example.com', email: 'hantsy@example.com',
}); });
expect(model.findOne).lastCalledWith({ _id: 'hantsy' }); expect(model.findOne).toHaveBeenLastCalledWith({ _id: 'hantsy' });
expect(model.findOne).toBeCalledTimes(1); expect(model.findOne).toHaveBeenCalledTimes(1);
}); });
it('return a null result', async () => { it('return a null result', async () => {
jest jest.spyOn(model, 'findOne').mockImplementation(
.spyOn(model, 'findOne') (filter?: FilterQuery<User>) =>
.mockImplementation((filter?: FilterQuery<User>) => ({ ({
exec: jest.fn().mockResolvedValue(null) as any, exec: jest.fn().mockResolvedValue(null) as any,
} as any)); }) as any,
);
try { try {
const foundUser = await lastValueFrom(service.findById('hantsy')); const foundUser = await lastValueFrom(service.findById('hantsy'));
@ -147,23 +150,24 @@ describe('UserService', () => {
}); });
it('parameter withPosts=true', async () => { it('parameter withPosts=true', async () => {
jest jest.spyOn(model, 'findOne').mockImplementation(
.spyOn(model, 'findOne') (filter?: FilterQuery<User>) =>
.mockImplementation((filter?: FilterQuery<User>) => ({ ({
populate: jest.fn().mockReturnThis(), populate: jest.fn().mockReturnThis(),
exec: jest.fn().mockResolvedValue({ exec: jest.fn().mockResolvedValue({
username: 'hantsy', username: 'hantsy',
email: 'hantsy@example.com', email: 'hantsy@example.com',
} as User), } as User),
} as any)); }) as any,
);
const foundUser = await lastValueFrom(service.findById('hantsy', true)); const foundUser = await lastValueFrom(service.findById('hantsy', true));
expect(foundUser).toEqual({ expect(foundUser).toEqual({
username: 'hantsy', username: 'hantsy',
email: 'hantsy@example.com', email: 'hantsy@example.com',
}); });
expect(model.findOne).lastCalledWith({ _id: 'hantsy' }); expect(model.findOne).toHaveBeenLastCalledWith({ _id: 'hantsy' });
expect(model.findOne).toBeCalledTimes(1); expect(model.findOne).toHaveBeenCalledTimes(1);
}); });
}); });
@ -180,8 +184,8 @@ describe('UserService', () => {
}); });
const result = await lastValueFrom(service.existsByUsername('hantsy')); const result = await lastValueFrom(service.existsByUsername('hantsy'));
expect(existsSpy).toBeCalledWith({ username: 'hantsy' }); expect(existsSpy).toHaveBeenCalledWith({ username: 'hantsy' });
expect(existsSpy).toBeCalledTimes(1); expect(existsSpy).toHaveBeenCalledTimes(1);
expect(result).toBeTruthy(); expect(result).toBeTruthy();
}); });
@ -195,8 +199,8 @@ describe('UserService', () => {
}); });
const result = await lastValueFrom(service.existsByUsername('hantsy')); const result = await lastValueFrom(service.existsByUsername('hantsy'));
expect(existsSpy).toBeCalledWith({ username: 'hantsy' }); expect(existsSpy).toHaveBeenCalledWith({ username: 'hantsy' });
expect(existsSpy).toBeCalledTimes(1); expect(existsSpy).toHaveBeenCalledTimes(1);
expect(result).toBeFalsy(); expect(result).toBeFalsy();
}); });
}); });
@ -216,8 +220,8 @@ describe('UserService', () => {
service.existsByEmail('hantsy@example.com'), service.existsByEmail('hantsy@example.com'),
); );
expect(existsSpy).toBeCalledWith({ email: 'hantsy@example.com' }); expect(existsSpy).toHaveBeenCalledWith({ email: 'hantsy@example.com' });
expect(existsSpy).toBeCalledTimes(1); expect(existsSpy).toHaveBeenCalledTimes(1);
expect(result).toBeTruthy(); expect(result).toBeTruthy();
}); });
@ -233,8 +237,8 @@ describe('UserService', () => {
service.existsByEmail('hantsy@example.com'), service.existsByEmail('hantsy@example.com'),
); );
expect(existsSpy).toBeCalledWith({ email: 'hantsy@example.com' }); expect(existsSpy).toHaveBeenCalledWith({ email: 'hantsy@example.com' });
expect(existsSpy).toBeCalledTimes(1); expect(existsSpy).toHaveBeenCalledTimes(1);
expect(result).toBeFalsy(); expect(result).toBeFalsy();
}); });
}); });

View File

@ -10,8 +10,8 @@ import { RegisterDto } from './register.dto';
@Injectable() @Injectable()
export class UserService { export class UserService {
constructor( constructor(
@Inject(USER_MODEL) private userModel: UserModel, @Inject(USER_MODEL) private readonly userModel: UserModel,
private sendgridService: SendgridService, private readonly sendgridService: SendgridService,
) {} ) {}
findByUsername(username: string): Observable<User> { findByUsername(username: string): Observable<User> {