Help me fix the error, and if possible improve the test itself, because it will be based on further tests for services.
I hope for your help
This is my service file
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { createQueryBuilder, getConnection, getRepository, Repository, getManager, Connection } from 'typeorm';
import { Brands } from './brands/brands.entity';
import { Categories } from './categories/categories.entity';
import { Volumes } from './volumes/volumes.entity';
import { Packages } from './packages/packages.entity';
import { Tags } from './tags/tags.entity';
import { Countries } from './countries/countries.entity';
import { Sub_categories } from './sub_categories/sub_categories.entity';
import { Products } from './products.entity';
import { IProduct } from './products.interface';
import { Collections } from './collections/collections.entity';
#Injectable()
export class ProductsService {
constructor(
#InjectRepository(Products)
private productRepository: Repository<Products>,
) {}
private readonly products: IProduct[] = [];
async findAllProductsByCategory(category: string): Promise<IProduct[]> {
const qb = getRepository(Products).createQueryBuilder("products");
const subQuery: string = qb.subQuery()
.select('categories.id', 'cat_id')
.from(Categories, 'categories')
.where(`cat_id = '${ category }'`)
.getQuery()
return await this.findAllProductsByArgument( 'category_id', subQuery );
}
async findAllProductsByArgument(argumentId1: string, subQuery1: string, argumentId2?: string, subQuery2?: string): Promise<IProduct[]> {
const qb = getRepository(Products).createQueryBuilder("products");
qb
.select(
`*,
Products.brand_id AS brand_id`
)
.addSelect('brands.brand_name', 'brand_name')
.addSelect('brands.brand_id', 'brand_nameid')
.addSelect('categories.cat_name', 'cat_name')
.addSelect('categories.cat_id', 'cat_id')
.addSelect('volumes.volume_name', 'volume_name')
.addSelect('volumes.volume_id', 'volume_id')
.addSelect('tags.name', 'tag_name')
.addSelect('tags.tag_id', 'tag_nameId')
.addSelect('sub_categories.subcat_name', 'subcategory_name')
.addSelect('sub_categories.subcat_id', 'subcategory_id')
.addSelect('packages.package_name', 'package_name')
.addSelect('packages.package_id', 'package_nameId')
.addSelect('countries.country_name', 'country_name')
.addSelect('countries.country_id', 'country_nameId')
.addSelect('Products.price', 'price_by_one')
.innerJoin(Brands, 'brands', 'Products.brand_id = brands.id')
.innerJoin(Categories, 'categories', 'Products.category_id = categories.id')
.innerJoin(Volumes, 'volumes', 'Products.volume_id = volumes.id')
.innerJoin(Tags, 'tags', 'Products.tag_id = tags.id')
.innerJoin(Sub_categories, 'sub_categories', 'Products.sub_category_id = sub_categories.id')
.innerJoin(Packages, 'packages', 'Products.package_id = packages.id')
.innerJoin(Countries, 'countries', 'Products.country_id = countries.id')
.where('Products.stock > Products.pack_quantity AND isshow = true')
.andWhere(`Products.${ argumentId1 } = ${ subQuery1 }`);
if(argumentId2 && subQuery2){
qb.andWhere(`Products.${ argumentId2 } = ${ subQuery2 }`)
}
return qb.getRawMany();
}
}
I don't really understand how to mocking data and simulate functions
import { Test, TestingModule } from '#nestjs/testing';
import { getRepositoryToken } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { Products } from './products.entity';
import { ProductsService } from './products.service';
class ProductsFake {
public async find(): Promise<void> {}
}
describe('ProductsService', () => {
let service: ProductsService;
let repo: Repository<Products>;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
ProductsService,
{
provide: getRepositoryToken(Products),
useClass: ProductsFake
}
]
}).compile();
service = module.get(ProductsService);
repo = module.get(getRepositoryToken(Products));
});
describe('finding a products', () => {
it('should be defined', async () => {
expect(service).toBeDefined();
});
it('return the products list', async () => {
const product = new Products();
const mockData = {
id: 10,
brand_name: "Brewdog",
brand_nameid: "brewdog",
cat_id: "pivo"
};
Object.assign(product, mockData);
const productsRepositoryFindAll = jest
.spyOn(repo, 'find')
.mockResolvedValue([product]);
const result = await service.findAllProductsByCategory( 'pivo' );
expect(result[0]).toBe(product);
expect(productsRepositoryFindAll).toBeCalled()
});
});
});
This is an error that appears when trying to test
йййййййййййййййййййййййййййййййййййййййййййййййййййййййййййййййййййййййййййййййй
Related
In a NestJS project using Jest test the service case. I created a find method and use it in a resolver(GraphQL) function. When test the resolver, it can't find the find method in the service.
src/serivce/post.ts
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { AbstractPostRepository } from '#abstractRepository/AbstractPostRepository';
import { PostRepository } from '#repository/PostRepository';
#Injectable()
export class PostService {
constructor(
#InjectRepository(PostRepository)
private postRepo: AbstractPostRepository,
) {}
async findById(id: string) {
const posts = await this.postRepo.findById(id);
......
return posts;
}
}
src/resolver/query/post.ts
import { Args, Query, Resolver } from '#nestjs/graphql';
import { Authorized } from '#lib/auth/authorized';
import { PermissionScope } from '#lib/auth/permissionScope';
import { PostService } from '#service/postService';
#Resolver()
export class PostsResolver {
constructor(private postService: PostService) {}
#PermissionScope()
#Authorized([
PermissionEnum.READ_MANAGEMENT,
])
#Query()
async findPosts() {
return await this.postService.findById(id);
}
}
The unit test for a resolver related this service:
test/unit/resolver/post.spec.ts
import { Test, TestingModule } from '#nestjs/testing';
import { PERMISSION_MANAGER } from '#lib/auth/permissionManager.module';
import { PostsResolver } from '#resolver/query/post';
import { PostService } from '#service/postService';
describe('PostsResolver', () => {
let resolver: PostsResolver;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
PostsResolver,
{
provide: PERMISSION_MANAGER,
useValue: jest.fn(),
},
{
provide: PostService,
useFactory: () => ({
findById: jest.fn(() => [
{
id: '11111111-1111-1111-1111-111111111111',
name: 'name1',
},
]),
}),
},
],
}).compile();
resolver = module.get<PostsResolver>(PostsResolver);
});
describe('findPosts', () => {
it('should return data', async () => {
const posts = await resolver.findPosts({
id: '11111111-1111-1111-1111-111111111111',
});
const expected = [
{
id: '11111111-1111-1111-1111-111111111111',
name: 'name1',
},
];
expect(posts).toEqual(expected);
});
});
});
When run this test got error:
● PostsResolver › findPosts › should return data
TypeError: Cannot read properties of undefined (reading 'findById')
22 | { id }: FindPostsInput,
23 | ) {
> 24 | return await this.postService.findById(
| ^
25 | id,
26 | );
at PostsResolver.findPosts (src/resolver/query/post.ts:24:41)
at Object.<anonymous> (test/unit/resolver/post.spec.ts:59:42)
It seems the mock service findById in the Test.createTestingModule doesn't work. How to mock correctly? Is it related some inject reasons?
I'm struggling to mock two dependencies from my userService.
Here I have two dependencies: UserRepository and ProfileService
user.service.ts
import { Injectable, NotFoundException, BadRequestException } from '#nestjs/common';
import { UserRepository } from '../repository/user.repository';
import { userDTO } from '../typings/user.typings';
import { ProfileService } from './profile.service';
import { InjectRepository } from '#nestjs/typeorm'
#Injectable()
export class UserService {
constructor(
#InjectRepository(UserRepository)
private readonly repository: UserRepository,
private readonly profileService: ProfileService
) {
this.repository = repository;
}
async addUser(user: userDTO): Promise<userDTO> {
try {
const userCreated = await this.repository.addUser(user);
await this.profileService.createProfile(userCreated)
return userCreated
}
catch (error) {
console.log(error)
}
}
async getUser(field: string, value: string) {
const user = await this.repository.getUser(field, value);
return user
}
async deleteUser(field: string, value: string) {
await this.profileService.deleteProfile(userId)
return await this.repository.deleteUser(userId);
}
async getUserById(userId: string) {
return await this.repository.getUserById(userId);
}
async updateUser(user: userDTO, userId: string) {
return await this.repository.updateUser(user, userId);
}
}
user.service.spec.ts
import { Test, TestingModule } from "#nestjs/testing";
import { UserService } from "../../src/services/user.services";
import { ProfileService } from "../../src/services/profile.service";
import { UserRepository } from "../../src/repository/user.repository";
import { getRepositoryToken } from '#nestjs/typeorm';
describe('userService', () => {
let userService: UserService;
let mockRepository = {};
let mockProfileService = {};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
UserService,
{
provide: getRepositoryToken(UserRepository),
useValue: mockRepository
},
{
provide: ProfileService,
useValue: mockProfileService
},
],
})
.compile();
userService = module.get<UserService>(UserService);
});
it('Should be defined', () => {
expect(userService).toBeDefined();
});
});
The test works fine when I only use UserRepository, but when I tried to mock the second repository it fails with this message
FAIL tests/services/user.service.spec.ts
● Test suite failed to run
Cannot find module 'src/models/profile.models' from '../src/repository/profile.repository.ts'
Can someone explain me how to mock 2 dependencies(a repository and a service).
I have a basic serverless application below, I want to test using Jest if getUserById method is called. I am also using inversifyjs. Now when I run my test I am getting an error TypeError: Reflect.hasOwnMetadata is not a function. Another thing how can I mock a response here?
handler.spec.ts
import { IUsersHandler } from './../src/IUsersHandler';
import { UsersHandler } from './../src/UsersHandler';
import { APIGatewayProxyResult } from 'aws-lambda';
let handler: IUsersHandler;
let mockResponse: APIGatewayProxyResult;
describe("UsersHandler", () => {
beforeEach(() => {
handler = new UsersHandler();
});
it("should call getUserById method", () => {
const spy = jest.spyOn(handler, 'getUserById').mockImplementation(async () => mockResponse);
expect(spy).toBeCalledTimes(1);
});
});
UsersHandler Class
import { IUsersHandler } from './IUsersHandler';
import { injectable } from "inversify";
import { APIGatewayProxyHandler, APIGatewayProxyResult, APIGatewayProxyEvent } from "aws-lambda";
#injectable()
export class UsersHandler implements IUsersHandler {
constructor() { }
public getUserById: APIGatewayProxyHandler = async (
event: APIGatewayProxyEvent
): Promise<APIGatewayProxyResult> => {
try {
return {
statusCode: 200,
body: JSON.stringify(event)
};
} catch (err) {
return {
statusCode: 500,
body: JSON.stringify(err)
};
}
};
}
User Interface
import { APIGatewayProxyHandler } from 'aws-lambda';
export interface IUsersHandler {
getUserById: APIGatewayProxyHandler;
}
export const TUsersHandler = Symbol.for('IUsersHandler');
Handler.ts
import { IUsersHandler, TUsersHandler } from './src/IUsersHandler';
import { container } from "./src/inversify.config";
import 'source-map-support/register';
export const getUserById = async function (event, context, callback) {
const handler: IUsersHandler = container.get<IUsersHandler>(TUsersHandler);
return handler.getUserById(event, context, callback);
};
Final handler.spec.ts
import "reflect-metadata";
import { IUsersHandler } from "./../src/IUsersHandler";
import { UsersHandler } from "./../src/UsersHandler";
import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda";
let handler: IUsersHandler;
let mockEvent: APIGatewayProxyEvent;
let mockResponse: APIGatewayProxyResult;
describe("UsersHandler", () => {
beforeEach(() => {
mockResponse = {
statusCode: 200,
body: "This is a test",
};
handler = new UsersHandler();
});
it("should call getUserById method", async () => {
const spy = jest
.spyOn(handler, "getUserById")
.mockImplementation(async () => mockResponse);
const response: any = await handler.getUserById(mockEvent, null, null);
expect(spy).toBeCalledTimes(1);
expect(response.body).toBe("This is a test");
expect(response.statusCode).toBe(200);
});
});
I need help adding unit test to the function below in NestJs.
I have a class with a createOrder function as shown below. the constructor of the class injects an Entity Manager. How can I test for the createOrder function in jest.
import { Injectable } from '#nestjs/common';
import * as shortId from 'shortid';
import { EntityManager, Repository } from 'typeorm';
import { HttpException, HttpStatus } from '#nestjs/common';
import { Service } from 'models/service.model';
#Injectable()
export class OrderService {
private readonly orderRepository: Repository<Service>;
constructor(private readonly entityManager: EntityManager) {
this.orderRepository = entityManager.getRepository(Service);
}
async createOrder(data) {
const orderService = new Service();
orderService.id = shortId.generate(); // just to generate a string for id
const orderServiceData = Object.assign(orderService, data);
try {
await this.orderRepository.save(orderServiceData);
return { success: true };
} catch (err) {
throw new HttpException('Post not found', HttpStatus.NOT_FOUND);
}
}
}
This is what I have tried so far. Yet it fails to call the save function
import { Test, TestingModule } from '#nestjs/testing';
import { OrderService } from './order_service.service';
import { Service } from '../../models/service.model';
import { Repository, EntityManager, getRepository } from 'typeorm';
import { getRepositoryToken } from '#nestjs/typeorm';
describe('Order Service', () => {
let orderService: OrderServiceService;
let orderRepository: Repository<Service>;
const mockOrderRepository = () => ({
save: jest.fn(),
});
const mockEntityManager = () => ({
getRepository: jest.fn(),
});
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
OrderService,
{
provide: EntityManager,
useFactory: mockEntityManager,
},
{
provide: getRepositoryToken(Service),
useFactory: mockOrderRepository,
},
],
}).compile();
orderService = await module.get<OrderService>(
OrderService,
);
orderRepository = await module.get(getRepositoryToken(Service));
});
it('should check that order service is defined', () => {
expect(orderService).toBeDefined();
});
describe('Create order service', () => {
it('should create an order service', () => {
expect(orderRepository.save).not.toHaveBeenCalled();
const data = {
name: 'Gucci Cloths',
type: 'Cloths',
};
orderService.createOrder(data);
expect(orderRepository.save).toHaveBeenCalled();
});
});
});
What you can do is mocking the save function of the orderRepository:
const mockRepository = {
save: jest.fn(),
}
const mockEntityManager = () => ({
getRepository: () => mockRepository,
});
This way you can test the function and also check that the save function has been called with the right parameters.
So, I want to test a Controller, but I always get the same error, and I not really familiarized with Jest.
I work with php and I already did some unit tests in phpUnit, but with Jest I'm really having some trouble to understand how to do.
Here is my error message
● Test suite failed to run
SyntaxError: /home/webjump-nb103/Projects/development/workspace/stare/customer/src/customer/customer.controller.spec.ts: Unexpected token, expected ";" (13:26)
11 |
12 | describe('Customer Controller', () => {
> 13 | let customerController: CustomerController;
| ^
14 | let customerService: CustomerService;
15 |
16 | beforeAll(async () => {
at Parser.raise (node_modules/#babel/parser/src/parser/location.js:41:63)
at Parser.unexpected (node_modules/#babel/parser/src/parser/util.js:150:16)
at Parser.semicolon (node_modules/#babel/parser/src/parser/util.js:123:40)
at Parser.parseVarStatement (node_modules/#babel/parser/src/parser/statement.js:703:10)
at Parser.parseStatementContent (node_modules/#babel/parser/src/parser/statement.js:216:21)
at Parser.parseStatement (node_modules/#babel/parser/src/parser/statement.js:146:17)
at Parser.parseBlockOrModuleBlockBody (node_modules/#babel/parser/src/parser/statement.js:865:25)
at Parser.parseBlockBody (node_modules/#babel/parser/src/parser/statement.js:841:10)
at Parser.parseBlock (node_modules/#babel/parser/src/parser/statement.js:818:10)
at Parser.parseFunctionBody (node_modules/#babel/parser/src/parser/expression.js:1964:24)
My controller
import {Controller, HttpStatus, Post, Res, Body, ValidationPipe, Put, Param, Get} from '#nestjs/common';
import {CreateCustomerDto} from './dto/customer/customer.dto';
import {CustomerService} from './customer.service';
#Controller('customer')
export class CustomerController {
constructor(private readonly customerService: CustomerService) { }
#Post()
async createPost(#Res() res, #Body(ValidationPipe) createCustomerDto: CreateCustomerDto ) {
const customer = await this.customerService.createCustomer(createCustomerDto);
return res.status(HttpStatus.OK).json({
customer: customer
});
}
#Put('update/:id')
async createUpdate(#Param('id') id: string, #Res() res, #Body(ValidationPipe) createCustomerDto: CreateCustomerDto) {
const customer = await this.customerService.updateCustomer(createCustomerDto, id);
return res.status(HttpStatus.OK).json({
customer: customer
});
}
}
**My Service **
import {Injectable} from '#nestjs/common';
import {Model} from 'mongoose';
import {InjectModel} from '#nestjs/mongoose';
import {Customer} from './interfaces/customer.interface';
import {CreateCustomerDto} from './dto/customer/customer.dto';
#Injectable()
export class CustomerService {
constructor(#InjectModel('customer') private readonly customerModel: Model<Customer>) {}
async createCustomer(createCustomerDto: CreateCustomerDto ): Promise<Customer> {
const customer = new this.customerModel(createCustomerDto);
return customer.save();
}
async updateCustomer(createCustomerDto: CreateCustomerDto, id: string): Promise<Customer> {
const customer = await this.customerModel
.findByIdAndUpdate(id, createCustomerDto, {new: true});
return customer;
}
}
And my test
import { Test, TestingModule } from '#nestjs/testing';
import { CustomerController } from './customer.controller';
import {CustomerService} from './customer.service';
import {CreateCustomerDto} from './dto/customer/customer.dto';
import {Customer} from './interfaces/customer.interface';
import {InjectModel} from '#nestjs/mongoose';
jest.mock('./customer.service.ts');
jest.mock('./customer.controller.ts');
jest.mock('./interfaces/customer.interface.ts');
describe('Customer Controller', () => {
let customerController: CustomerController;
let customerService: CustomerService;
beforeAll(async () => {
const module = await Test.createTestingModule({
controllers: [CustomerController],
providers: [CustomerService],
}).compile();
customerController = module.get(CustomerController);
customerService = module.get<CustomerService>(CustomerService);
});
describe('Create Post', () => {
const dto = new CreateCustomerDto();
const res = 200;
const customerModel: Customer;
it('should return an collection of customer when created ', async () => {
const expectedResult = new CustomerService(#InjectModel(customerModel<Customer>));
jest.spyOn(customerService, 'createCustomer').mockResolvedValue(customerModel);
expect(await customerController.createPost(res, dto)).toBe(expectedResult);
});
});
});
**Any thoughts ?**
As already mentioned in the comments, make sure you have your jest properly configured. Try to add/modify the following to your package.json
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".spec.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}