Tips for creating an effective unit test using Jest for this specific controller

I'm currently grappling with the task of unit testing my Controller in an express app, but I seem to be stuck. Here are the code files I've been working with:

// CreateUserController.ts
import { Request, Response } from "express";
import { CreateUserService } from "../services/CreateUserService";

class CreateUserController {
    async handle(request: Request, response: Response) {
        try {
            const { name, email, admin, password } = request.body;

            const createUserService = new CreateUserService();

            const user = await createUserService.execute({ name, email, admin, password });
            
            return response.send(user);
        } catch (error) {
            return response.send({ error });
        }
    }
}

export { CreateUserController };
// CreateUserService.ts
import { getCustomRepository } from "typeorm";
import { UsersRepositories } from "../repositories/UsersRepositories";
import { hash } from "bcryptjs";

interface IUserRequest {
    name: string;
    email: string;
    admin?: boolean;
    password: string;
}

class CreateUserService {
    async execute({ name, email, admin = false, password }: IUserRequest) {
            const usersRepository = getCustomRepository(UsersRepositories);

            if(!email) {
                throw new Error('Incorrect e-mail.');
            }

            const userAlreadyExists = await usersRepository.findOne({ email });

            if(userAlreadyExists) {
                throw new Error('User already exists.');
            }

            const passwordHash = await hash(password, 8);

            const user = usersRepository.create({ name, email, admin, password: passwordHash });

            const savedUser = await usersRepository.save(user);

            return savedUser;
    }
}

export { CreateUserService };
// Users.ts
import { Entity, PrimaryColumn, Column, CreateDateColumn, UpdateDateColumn } from "typeorm";
import { Exclude } from "class-transformer";
import { v4 as uuid } from "uuid";

@Entity("users")
class User {

    @PrimaryColumn()
    readonly id: string;

    @Column()
    name: string;

    @Column()
    email: string;

    @Column()
    admin: boolean;

    @Exclude()
    @Column()
    password: string;

    @CreateDateColumn()
    created_at: Date;

    @UpdateDateColumn()
    updated_at: Date;

    constructor() {
        if (!this.id) {
            this.id = uuid();
        }
    }
}

export default User;
// UsersRepositories.ts
import { EntityRepository, Repository } from "typeorm";
import User from "../entities/User";

@EntityRepository(User)
class UsersRepositories extends Repository<User> {}

export { UsersRepositories };

I am keen on testing the CreateUserController, however, it appears that the current implementation may not be easily testable. Can anyone confirm?

// CreateUserController.unit.test.ts
import { CreateUserController } from "./CreateUserController";
import { getCustomRepository } from "typeorm";
import { UsersRepositories } from "../repositories/UsersRepositories";
import { hash } from "bcryptjs";
import { v4 as uuid } from "uuid";


describe('testando', () => {
    it('primeiro it', async () => {
        const userId = uuid();
        const userData = {
            name: 'Fulano',
            email: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0e6b636f67624e6a206d6163">[email protected]</a>',
            password: '123456',
            admin: true
        };
        const returnUserData = {
            id: userId,
            name: 'Fulano',
            email: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="71141c10181d31155f121e1e">[email protected]</a>',
            password: await hash('123456', 8),
            admin: true,
            created_at: new Date(),
            updated_at: new Date()
        };

        jest.spyOn(getCustomRepository(UsersRepositories), 'save').mockImplementation(async () => returnUserData);

        const user = await CreateUserController.handle(userData);
    });
});

Currently encountering some errors, but this is what I've managed to put together so far.

Answer №1

To ensure the controller's functionality, a unit test is necessary to validate that its dependencies are functioning correctly. In this particular scenario, the controller relies on a single dependency - CreateUserService.

When testing the controller, it is essential to consider scenarios where the service returns a user as expected or throws an unexpected exception. Additionally, one should verify that the .send function is invoked with the correct parameters.

While there may be numerous aspects to explain, further exploration and investigation are encouraged for a deeper understanding of the topic.

// CreateUserController.test.ts
import { mocked } from "ts-jest/utils";
import { Request, Response } from "express";
import { CreateUserController } from "./CreateUserController"
import { CreateUserService } from "./CreateUserService";

jest.mock('./CreateUserService'); // mock CreateUserService constructor

describe('CreateUserController', () => {
  // Test cases implementation goes here...
});

// Update to handle error responses in the controller
/*
    It will fail in the second case because I expect that the controller has to respond with status 500, to make it pass, let update your controller:
*/

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The nodemailer module in Node.js encountered an issue while trying to send an email, resulting

Looking to confirm registration, I want to send an email from my server (kimsufi). To accomplish this, I am utilizing nodemailer which can be found at https://github.com/andris9/Nodemailer Encountering the following error: Error occurred Sendmail exited ...

Utilize the 'response.download' method to retrieve unique data not typically expected for a given request

Each time I try to download a file, the response I get is different. The file is generated correctly every time: user,first_name,last_name,active,completed_training 4,Foo,Bas,YES,YES 5,Ble,Loco,NO,NO 9,gui2,md,NO,NO 3137,foo,baz,NO,NO However, the respons ...

Having trouble retrieving object values from the request body during a POST request in [Node.js, MySQL]

I am currently developing a management system and working on creating POST requests for the API to add a new city to the database. However, I am facing an issue where instead of receiving the correct values from the request's body, I am getting "undef ...

After a loop, a TypeScript promise will be returned

I am facing a challenge in returning after all calls to an external service are completed. My current code processes through the for loop too quickly and returns prematurely. Using 'promise.all' is not an option here since I require values obtain ...

Using Nest JS to create two instances of a single provider

While running a test suite, I noticed that there are two instances of the same provider alive - one for the implementation and another for the real implementation. I reached this conclusion because when I tried to replace a method with jest.fn call in my ...

React doesn't have file upload configured to update the state

I am working on integrating a file upload button that sends data to an API. To ensure only the button triggers the upload dialog and not the input field, I have set it up this way. Issue: The File is not being saved to state, preventing me from using a ...

Tips for preventing CORS issues in a React - GraphQL app

In my current project, I am exploring the capabilities of the Camunda platform. Specifically, I am developing a React application that interacts with a GraphQL API to perform certain actions. After successfully testing the API using Postman, I have identif ...

Using the i18next Module for Localization in ExpressJS and Front-End Development

I am currently integrating the i18next module into my NodeJs/ExpressJS web application. All the translation files are stored in the /locales directory. According to information from i18next.com, it can also be utilized on the client side. <script typ ...

Experiencing difficulty when attempting to save a zip file to the C drive

I came across this code snippet on SO and decided to use it for my project. The goal is to send a simple 1.5mb zip file and save it on my C drive by making a request through Postman with the binary option enabled, sending the zip file to localhost:3012. c ...

Is it possible for a conditional type in TypeScript to be based on its own value?

Is it possible to use this type in TypeScript? type Person = { who: string; } type Person = Person.who === "me" ? Person & Me : Person; ...

An issue with TypeORM syntax causing errors within a NestJS migration file

I recently encountered an issue while setting up PostgreSQL with NestJS and TypeORM on Heroku. Despite successfully running a migration, my application kept crashing. I attempted various troubleshooting methods by scouring through blogs, GitHub issues, and ...

The pivotal Angular universal service

In my application, I have the need to store global variables that are specific to each user. To achieve this, I created a Service that allows access to these variables from any component. However, I am wondering if there is a way to share this service t ...

Creating a String-only pattern Validator: A step-by-step guide

Below is the code I've written: ***<input type="text" placeholder="First Name" name="firstName1" [(ngModel)]="firstName" #firstName1="ngModel" required pattern="^[a-z0-9_-]{8,15}$" >*** ...

Waiting for a function to complete its processing loop in Angular 7

In my code, I'm dealing with an angular entity called Z which has a property that is a list of another entity named Y. My goal is to delete the entity Z, but before doing so, I need to also delete all the Y entities within it. The challenge arises fro ...

The function res.send() is triggered before the nested function finishes executing and returns a value

I am currently facing an issue with the 'GetUsers' function. It seems that the function is returning the correct values, but when trying to send these values using res.send(users), it appears as undefined. I have attempted to move the res.send(us ...

The Nextjs next-auth implementation with URL '/api/auth/callback/cognito' encountered a 502 Bad Gateway error while in production

I'm facing a challenge while trying to deploy a nextjs app that utilizes 'next-auth' with AWS Cognito. Interestingly, the app runs smoothly when tested locally using either next dev or next start. However, upon deploying it on the producti ...

"I am facing issues with Nodejs $lookup as it is not producing the

I am looking to merge two document collections. The first collection, "prefix," contains an array of category IDs under the categoryId key, while the second collection, "categories," holds objects with a unique _id field. Here is my sample database structu ...

"Encounter an error due to an unexpected token, specifically 'Doctype

In my current project, I am utilizing react, react-router-dom, and express. Whenever I initiate a request by clicking on a link, everything functions correctly. However, issues arise when sending requests via the browser. Strangely, requests such as http ...

What is the most efficient way to transfer substantial data from a route to a view in Node.js when using the render method

Currently, I have a routing system set up in my application. Whenever a user navigates to site.com/page, the route triggers a call to an SQL database to retrieve data which is then parsed and returned as JSON. The retrieved data is then passed to the view ...

Troubleshooting problem in Grunt-TS, Grunt, watch/compile, and Dropbox integration

UPDATE: Recently, I've been experiencing some issues with another computer when it comes to watching and compiling. It seems like the tscommandxxxxxx.tmp.txt files that are generated during compilation might be causing the trouble... sometimes they ar ...