D
D
dimasik24na72021-08-05 10:49:25
Node.js
dimasik24na7, 2021-08-05 10:49:25

NestJS. Why are my controller tests not working correctly?

I'm a front-end developer, trying to write unit tests in NestJS, got to the stage where they can already run, but give the wrong result (all the time they pass without errors).
For example, I pass data to the create method: , as a result I should get the same result (just for example), but in the test I pass this data

{ login: 'ffff', password: 'fafa4636fwafw' }

{ id:1, login: 'ffff', password: 'fafa4636fwafw' roles:[]}

, but I pass a completely different one to the result for comparison:

login: 'ffff',
password: 'fafa4636',
roles: [],
id: 1,

and the test passes without errors.
I think the problem is in the mock service, but I don't know how to solve it .
Here is the code:

import { Test, TestingModule } from '@nestjs/testing';
import { CreateUserPayload } from 'src/modules/user/user.payload';
import { User } from '../entities/user.entity';
import { UserController } from '../modules/user/user.controller';
import { UserService } from '../modules/user/user.service';

describe('UserController', () => {
  let userController: UserController;
  let userService: UserService;

  class MockUserService {
    create(payload: CreateUserPayload) {
      return { ...payload, id: 1, roles:[] };
    }
  }

  beforeEach(async () => {
    const moduleRef = await Test.createTestingModule({
      controllers: [UserController],
      providers: [UserService],
    })
      .overrideProvider(UserService)
      .useClass(MockUserService)
      .compile();

    userService = moduleRef.get<UserService>(UserService);
    userController = moduleRef.get<UserController>(UserController);
  });

  describe('create', () => {
    it('should create new user repository', async () => {
      const result: User = {
        login: 'ffff',
        password: 'fafa4636',
        roles: [],
        id: 1,
      };

      jest.spyOn(userService, 'create').mockImplementation(async (payload) => {
        console.log('pay', payload);
        console.log('res', result);
        return result;
      });

      expect(await userController.create({ login: 'ffff', password: 'fafa4636fwafw' }).catch((e) => expect(e).toEqual(result)));
    });
  });
});

Execution result: 610b96e31f06d502383075.png

Fragments of the user module:

user.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserController } from './user.controller';
import { User } from '../../entities/user.entity';
import { UserService } from './user.service';
import { Role } from 'src/entities/role.entity';

@Module({
  imports: [TypeOrmModule.forFeature([User, Role])],
  controllers: [UserController],
  providers: [UserService],
})
export class UserModule {}


user.controller.ts
import { Body, Controller, Delete, Get, Param, Post, Put } from '@nestjs/common';
import { CreateUserPayload, UpdateUserPayload } from './user.payload';
import { UserService } from './user.service';

@Controller('/api/users')
export class UserController {
  constructor(private userService: UserService) {}

  @Post()
  create(@Body() payload: CreateUserPayload) {
    return this.userService.create(payload);
  }
}


user.service.ts
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { CreateUserPayload, UpdateUserPayload } from './user.payload';
import { User } from '../../entities/user.entity';
import { Role } from '../../entities/role.entity';

@Injectable()
export class UserService {
  constructor(private userRepository: Repository<User>) {}

  async create(payload: CreateUserPayload): Promise<User> {
    const errors = [];
    let response: Object = { success: true };

    if (!payload.login || payload?.login?.trim() === '') {
      errors.push('login was not provided');
    }

    if (payload.password && payload?.password?.trim() !== '') {
      if (!payload.password.match(/\d+/g)) {
        errors.push('password must contains at least one numeric character');
      }
      if (!payload.password.match(/[A-Z]/g)) {
        errors.push('password must contains at least one capital letter');
      }
    } else {
      errors.push('password was not provided');
    }

    if (errors.length) {
      response = { ...response, success: false, status: HttpStatus.BAD_REQUEST, errors };
      throw new HttpException(response, HttpStatus.BAD_REQUEST);
    }

    const user = this.userRepository.create({ ...payload, roles: [] });
    await this.userRepository.save(user);
    return { ...user, ...response };
  }
}


user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, OneToMany, JoinColumn, ManyToOne, ManyToMany, JoinTable } from 'typeorm';
import { Role } from './role.entity';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  login: string;

  @Column()
  password: string;

  @ManyToMany((type) => Role, (role) => role.users)
  @JoinTable({
    name: 'user_role',
    joinColumns: [{ name: 'user_id' }],
    inverseJoinColumns: [{ name: 'role_id' }],
  })
  roles: Role[];
}


user.payload.ts
export class CreateUserPayload {
  readonly login: string;
  readonly password: string;
}

export class UpdateUserPayload {
  readonly login?: string;
  readonly password?: string;
  readonly roles?: string[];
}

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question