Búsqueda de sitios web

node.js - ¿Cómo uso UserDocument/UserModel en casos de prueba de Jest usando NestJs?


Estoy intentando agregar valor real a la base de datos usando NestJS con casos de prueba Jest.

El propósito principal de los casos de prueba es verificar realmente los valores de la base de datos que se escriben y recuperan de la base de datos. Así que no estoy simulando ningún método save o find ya que quiero hacer la conexión real a la base de datos y recuperar los registros desde allí. Así que sin simular los métodos save() y find() no puedo ejecutar los casos de prueba. La compilación falla sin ello.

Estoy atascado con el archivo users.service.spec.ts en el que quiero usar UserDocument y sus métodos create(),findAll().

//user.entity.ts

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type UserDocument = User & Document;

@Schema()
export class User {
    
  @Prop({ unique: true })
  username: string;

  @Prop()
  age: number;

  @Prop()
  password: string;
}

export const UserSchema = SchemaFactory.createForClass(User);
// User.module.ts

import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { MongooseModule } from '@nestjs/mongoose'
import { User, UserSchema } from './schemas/user.schema'
import { UsersController } from './users.controller';

@Module({
  imports: [MongooseModule.forFeature([{ name: User.name, schema: UserSchema }])],
  controllers: [UsersController],
  providers: [UsersService],
  exports: [UsersService]
})
export class UsersModule {}
// users.controller.ts

import { Controller, Get, Post, Body, Patch, Param, Delete,UseGuards } from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';


@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }

  @Get()
  findAll() {
    return this.usersService.findAll();
  }

}
//users.service.ts

import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { User, UserDocument } from './schemas/user.schema';
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';

@Injectable()
export class UsersService {
   constructor(@InjectModel(User.name) private userModel: Model<UserDocument>) {}

  async create(createUserDto: CreateUserDto): Promise<User> {
   const createdUser = new this.userModel(createUserDto);
    return await createdUser.save();
  }

  async findAll(): Promise<User[]> {
    return await this.userModel.find().exec();
  }

}
//users.service.spec.ts

import { Test, TestingModule } from '@nestjs/testing'
import { UsersService } from './users.service'
import { AppConfigModule } from '../config/app-config.module'
import { AppConfigService } from '../config/app-config.service'
import { ConfigModule, ConfigService } from '@nestjs/config'
import { MongooseModule, getModelToken } from '@nestjs/mongoose'
import { PaginationQuery } from 'src/helpers/pagination/pagination-query.dto'
import { User, UserSchema, UserDocument } from './entities/user.entity'

describe('UsersService', () => {
  let service: UsersService
  let userDocument: UserDocument

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      imports: [
        ConfigModule.forRoot({
          isGlobal: true,
          cache: true
        }),
        MongooseModule.forRootAsync({
          imports: [AppConfigModule],
          inject: [AppConfigService],
          useFactory: (config: AppConfigService) => ({
            uri: `mongodb://${config.TESTDATABASE_HOST}:${config.TESTDATABSE_PORT}`,
            dbName: config.TESTDATABASE_NAME
          })
        })
      ],
      providers: [
        UsersService,
        {
          provide: getModelToken(User.name),
          useValue: UserDocument         // <----------- Not able to understand what will go here
        }
      ]
    }).compile()

    service = module.get<UsersService>(UsersService)
    userDocument = module.get<UserDocument>(UserDocument) // <---- As this is type here not accepting value
  })

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

  it('create test data', async () => {
    expect(
      await service.create({
        name: 'demouser',
        email: '[email ',
        password: 'demo@123',
        role: 'user'
      })
    ).toEqual({
      statusCode: 201,
      message: 'User created successfully',
      data: {
        isActive: true,
        role: 'user',
        password:
          '$2b$10$VjwR0Wjf6vTaRjQlsizB5OLY04NJOcRyC/pPLbTPTQnWTDIrBU.Sq',
        email: '[email ',
        name: 'demouser',
        _id: expect.any(Number)
      }
    })
  })


})

Como he destacado en el archivo de especificaciones, UserDocument es el tipo definido en el archivo users.entity.ts, el valor UserDocument no es aceptado en la línea userDocument=module.get<UserDocument>(UserDocument).

Respuesta #1

Resolví mi error de problema.

Agregando esta importación, se resolvió mi error.

MongooseModule.forFeature([{ name: User.name, schema: UserSchema }])

Puedo agregar el valor real a la base de datos

//users.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing'
import { UsersService } from './users.service'
import { AppConfigModule } from '../config/app-config.module'
import { AppConfigService } from '../config/app-config.service'
import { ConfigModule } from '@nestjs/config'
import { MongooseModule, getModelToken } from '@nestjs/mongoose'
import { User, UserSchema } from './entities/user.entity'
import { isValidObjectId } from 'mongoose'
import { HttpException } from '@nestjs/common'

const testUser = {
  name: 'demouser',
  email: '[email ',
  password: 'demo@123',
  role: 'user'
}
describe('UsersService', () => {
  let service: UsersService

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      imports: [
        ConfigModule.forRoot({
          isGlobal: true,
          cache: true
        }),
        MongooseModule.forRootAsync({
          imports: [AppConfigModule],
          inject: [AppConfigService],
          useFactory: (config: AppConfigService) => ({
            uri: `mongodb://${config.TESTDATABASE_HOST}:${config.TESTDATABSE_PORT}`,
            dbName: config.TESTDATABASE_NAME
          })
        }),
        MongooseModule.forFeature([{ name: User.name, schema: UserSchema }])//-------import model here
      ],
      providers: [UsersService]
    }).compile()

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

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

Respuesta #2

userDocument=module.get<UserDocument>(UserDocument) debe ser
userDocument=module.get<UserDocument>(getModelToken(User.name))
ya que estás intentando obtener el stub que has definido para el proveedor getModelToken(User.name)

En useValue: UserDocument debes usar algún objeto simulado/mock como este: https://github.com/jmcdo29/testing-nestjs/blob/6c77b2a5001a48673c77c9659d985a083354579f/apps/sequelize-sample/src/cats/cats.service.spec.ts#L17-L20 ya que estás intentando no usar el modelo real.

Artículos relacionados