简体   繁体   English

无法在 NestJs 服务上创建 Jest 测试模块。 获取 Nest 无法解析 UsersService (?, ConfigService) 的依赖关系

[英]Unable to create Jest testing module on NestJs service. Geting Nest can't resolve dependencies of the UsersService (?, ConfigService)

it's my first time making questions on stackoverflow:).这是我第一次在 stackoverflow 上提出问题:)。

So I'm developing a test / learning application to learn how to use NestJS and Vue.所以我正在开发一个测试/学习应用程序来学习如何使用 NestJS 和 Vue。 I am was currently trying to implement several server-side unit tests (using Jest).我目前正在尝试实现几个服务器端单元测试(使用 Jest)。 When trying to create a testingmodule from my UsersService I get the error below on running "npm test users.service.spec"尝试从我的 UsersService 创建测试模块时,我在运行“npm test users.service.spec”时收到以下错误

Nest can't resolve dependencies of the UsersService (?, ConfigService). Nest 无法解析 UsersService (?, ConfigService) 的依赖关系。 Please make sure that the argument at index [0] is available in the _RootTestModule context.请确保索引 [0] 处的参数在 _RootTestModule 上下文中可用。

at Injector.lookupComponentInExports (../node_modules/@nestjs/core/injector/injector.js:183:19)在 Injector.lookupComponentInExports (../node_modules/@nestjs/core/injector/injector.js:183:19)

I am not sure if I am incorrectly instantiating the test model, or misconceived the injection of config.service, the code itself works, but may be implemented incorrectly.我不确定是我错误地实例化了测试model,还是误解了config.service的注入,代码本身可以工作,但可能实现不正确。 Does anyone have any ideas how to solve this problem?有谁知道如何解决这个问题?

Git link: https://github.com/Lindul/FuelTracker_NestJs_MySql_Vue.git Git 链接: https://github.com/Lindul/FuelTracker_NestJs_MySql_Vue.git

users.service.spec.ts users.service.spec.ts

import { Test } from '@nestjs/testing';
import { UsersService } from './users.service';
import { UserDto } from './dto/user.dto';
import { UserLoginRegRequestDto } from './dto/user-login-reg-request.dto';
import { ConfigService } from '../shared/config/config.service';
describe('User Service Tests', () => {

    let loginTeste: UserLoginRegRequestDto = {
        login: 'LoginJestTeste',
        password: 'PassJestTeste',
    }

    const userMock: UserDto = {
        id: 1,
        login: 'hugombsantos',
        password: 'wefewkfnwekfnwekjnf',
        isActive: true,
        needChangePass: false,
        userType: 0,

    };

    const dataFindAllMock: UserDto[] = [{
        id: 1,
        login: 'hugombsantos',
        password: 'wefewkfnwekfnwekjnf',
        isActive: true,
        needChangePass: false,
        userType: 0,

    }, {
        id: 2,
        login: 'user2',
        password: 'sdgsdgdsgsdgsgsdg',
        isActive: true,
        needChangePass: false,
        userType: 0,
    }];

    let service: UsersService;
    beforeEach(async () => {

        const module = await Test.createTestingModule({
            providers: [
                ConfigService,
                UsersService,
            ],
        }).compile();

        service = module.get<UsersService>(UsersService);
    });


    it('UsersService está defenido', () => {
        expect(service).toBeDefined();
    });   

});

user.service.ts用户服务.ts

import { Injectable, Inject, HttpException, HttpStatus } from '@nestjs/common';
import { Users } from '../models/users.schema';
import { UserDto } from './dto/user.dto';
import { UserLoginRegRequestDto } from './dto/user-login-reg-request.dto';
import { UserLoginResponseDto } from './dto/user-login-response.dto';
import { sign } from 'jsonwebtoken';
import { ConfigService } from '../shared/config/config.service';
import { JwtPayload } from './auth/jwt-payload.model';
import { ErroMessageDto } from '../shared/config/dto/erro-message.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import bcrypt = require('bcrypt-nodejs');
const SALT_FACTOR = 8;

@Injectable()
export class UsersService {

    constructor(
        @Inject('UsersRepository') private usersRepository: typeof Users,
        private readonly configService: ConfigService,
    ) { }

    /* istanbul ignore next */
    async findAll(): Promise<UserDto[]> {
        const users = await this.usersRepository.findAll<Users>();
        return users.map(user => {
            return new UserDto(user);
        });
    }
    /* istanbul ignore next */
    async findUser(id: number): Promise<Users> {
        const user = await this.usersRepository.findOne<Users>({
            where: { id },
        });
        return user;
    }
    /* istanbul ignore next */
    async findUserformLogin(login: string): Promise<UserDto> {
        return await this.usersRepository.findOne<Users>({
            where: { login },
        });
    }
    /* istanbul ignore next */
    async findUserforLogin(id: number, login: string): Promise<Users> {
        return await this.usersRepository.findOne<Users>({
            where: { id, login },
        });
    }
    /* istanbul ignore next */
    async creatUserOnDb(createUser: UserLoginRegRequestDto): Promise<Users> {
        try {
            const user = new Users();
            user.login = createUser.login;
            user.password = await this.hashPass(createUser.password);
            return await user.save();
        } catch (err) {
            if (err.original.code === 'ER_DUP_ENTRY') {
                throw new HttpException(
                    new ErroMessageDto(
                        HttpStatus.CONFLICT,
                        `Login '${err.errors[0].value}' already exists`),
                    HttpStatus.CONFLICT,
                );
            }
            throw new HttpException(
                new ErroMessageDto(
                    HttpStatus.INTERNAL_SERVER_ERROR,
                    err),
                HttpStatus.INTERNAL_SERVER_ERROR,
            );
        }
    }
    /* istanbul ignore next */
    async updateUserOnDb(user: Users): Promise<Users> {
        try {
            return await user.save();
        } catch (err) {
            if (err.original.code === 'ER_DUP_ENTRY') {
                throw new HttpException(
                    new ErroMessageDto(
                        HttpStatus.CONFLICT,
                        `Login '${err.errors[0].value}' already exists`),
                    HttpStatus.CONFLICT,
                );
            }
            throw new HttpException(
                new ErroMessageDto(
                    HttpStatus.INTERNAL_SERVER_ERROR,
                    err),
                HttpStatus.INTERNAL_SERVER_ERROR,
            );
        }
    }

    /* istanbul ignore next */
    async delete(id: number): Promise<UserDto> {
        const user = await this.findUser(+id);
        await user.destroy();
        return new UserDto(user);
    }

    async login(
        userLoginRequestDto: UserLoginRegRequestDto,
    ): Promise<UserLoginResponseDto> {

        const login = userLoginRequestDto.login;
        const password = userLoginRequestDto.password;
        const user = await this.findUserformLogin(login);

        if (!user) {
            throw new HttpException(
                new ErroMessageDto(
                    HttpStatus.UNAUTHORIZED,
                    'Invalid login or password.'),
                HttpStatus.UNAUTHORIZED,
            );
        }

        const isMatch = await this.comparePass(password, user.password);

        if (!isMatch) {
            throw new HttpException(
                new ErroMessageDto(
                    HttpStatus.UNAUTHORIZED,
                    'Invalid login or password.'),
                HttpStatus.UNAUTHORIZED,
            );
        }

        const token = await this.signToken(user);

        return new UserLoginResponseDto(token);
    }

    async create(createUser: UserLoginRegRequestDto): Promise<UserLoginResponseDto> {

        const userData = await this.creatUserOnDb(createUser);

        // when registering then log user in automatically by returning a token
        const token = await this.signToken(userData);

        return new UserLoginResponseDto(token);

    }

    async updateUser(id: number | string, updateUserDto: UpdateUserDto): Promise<UserLoginResponseDto> {

        const user = await this.findUser(+id);

        if (!user) {
            throw new HttpException(
                new ErroMessageDto(
                    HttpStatus.NOT_FOUND,
                    'User not found.'),
                HttpStatus.NOT_FOUND,
            );
        }

        user.login = updateUserDto.login || user.login;
        user.userType = updateUserDto.userType || user.userType;
        user.needChangePass = false;

        const isMatch = await this.comparePass(updateUserDto.password, user.password);
        if (updateUserDto.password && !isMatch) {
            user.password = await this.hashPass(updateUserDto.password);
        } else {
            user.password = user.password;
        }

        const userData = await this.updateUserOnDb(user);
        const token = await this.signToken(userData);

        return new UserLoginResponseDto(token);

    }

    async signToken(user: UserDto): Promise<string> {

        const payload: JwtPayload = {
            id: user.id,
            login: user.login,
        };
        const token = sign(payload, this.configService.jwtConfig.jwtPrivateKey,
            {
                expiresIn: this.configService.jwtConfig.valideTime,
            });
        return token;
    }

    async hashPass(passToHash: string): Promise<string> {
        const saltValue = await bcrypt.genSaltSync(SALT_FACTOR);
        return await bcrypt.hashSync(passToHash, saltValue);
    }

    async comparePass(passToCheck: string, correntPass: string) {
        return await bcrypt.compareSync(passToCheck, correntPass);
    }
}

users.modules.ts users.modules.ts

import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import {userProviders} from './users.providers';
import { DatabaseModule } from '../database/database.module';
import { JwtStrategy } from './auth/jwt-strategy';
import { ConfigService } from '../shared/config/config.service';

@Module({
  imports: [DatabaseModule, ConfigService],
  controllers: [UsersController],
  providers: [UsersService,
    ...userProviders, JwtStrategy],
  exports: [UsersService],

})

export class UsersModule {}

config.service.ts配置服务.ts

import { Injectable } from '@nestjs/common';
import { JwtConfig } from './interfaces/jwt-config.interface';
import { config } from '../../../config/config.JwT';
import { config as dbConfigData } from '../../../config/config.db';
import { SequelizeOrmConfig } from './interfaces/sequelize-orm-config.interface';

@Injectable()
export class ConfigService {
    get sequelizeOrmConfig(): SequelizeOrmConfig {
        return dbConfigData.databaseOpt;
    }

    get jwtConfig(): JwtConfig {
        return {
            jwtPrivateKey: config.jwtPrivateKey,
            valideTime: config.valideTime,
        };
    }
}

You need to provide some value for Nest to inject for your UserRepository .您需要为 Nest 提供一些值,以便为您的UserRepository注入。 It looks like you are using the TypeORM @InjectRepository() decorator, so in your testing module you'll need to add something like this under your providers看起来您正在使用 TypeORM @InjectRepository()装饰器,因此在您的测试模块中,您需要在您的提供程序下添加类似这样的内容

{
  provide: getRepositoryToken('UsersRepository'),
  useValue: MyMockUserRepo,
}

So that Nest can know what value to inject for that string.这样 Nest 就可以知道为该字符串注入什么值。 MyMockUserRepo would be your mock repository functionality, so that you aren't making actual database calls to your backend MyMockUserRepo将是您的模拟存储库功能,因此您不会对后端进行实际的数据库调用

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM