Testing Controller and Service in Jest

I'm fairly new to Jest and have been trying (with no luck) to figure out how to write tests for my controller. I'm not sure how to write the test as it calls another function. It would be great if I could get pointed in the right direction at least. Thanks in advance.

controller.ts

import * as Services from './services';

export async function GetCountriesList(req: Request, res: Response): Promise<void> {
    const response = await Services.GetCountriesList();
    res.status(response.code).json({
        status: response.status,
        message: response.message,
        count: response.count,
        data: response.data
     });
}

service.ts

import db from '../../modules/db';
import { DBGenericDataResponse } from '../../types/models';

export async function GetCountriesList(): Promise<DBGenericDataResponse> {
    const lQuery = 'somquery';
    const responseMessage: DBGenericDataResponse = {
        code: 200,
        status: 'ok',
        message: '',
        count: 0,
        data: [],
        error: ''
    };
    try {
        const dbResult = await db.query<any>(lQuery);
        responseMessage.message = 'Countries returned';
        responseMessage.count = dbResult.rows.length;
        responseMessage.data = dbResult.rows;
    } catch (err) {
        responseMessage.code = 400;
        responseMessage.status = 'error';
        responseMessage.message = 'Error retrieving Countries List';
        responseMessage.error  = err;
    }
    return responseMessage;
}

1 answer

  • answered 2021-03-03 05:21 slideshowp2

    You should use jest.mock(moduleName, factory, options) method to mock ./services module.

    E.g.

    controller.ts:

    import * as Services from './services';
    import type { Request, Response } from 'express';
    
    export async function GetCountriesList(req: Request, res: Response): Promise<void> {
      const response = await Services.GetCountriesList();
      res.status(response.code).json({
        status: response.status,
        message: response.message,
        count: response.count,
        data: response.data,
      });
    }
    

    services.ts:

    export async function GetCountriesList() {
      return { code: 200, status: 200, message: 'real message', count: 1, data: 'real data' };
    }
    

    controller.test.ts:

    import { GetCountriesList } from './controller';
    import * as Services from './services';
    import { mocked } from 'ts-jest/utils';
    import type { Request, Response } from 'express';
    
    jest.mock('./services');
    
    describe('GetCountriesList', () => {
      afterAll(() => {
        jest.resetAllMocks();
      });
      it('should pass', async () => {
        mocked(Services.GetCountriesList).mockResolvedValueOnce({
          code: 400,
          status: 400,
          message: 'fake message',
          count: 0,
          data: 'fake data',
        });
        const mReq = ({} as unknown) as Request;
        const mRes = ({ status: jest.fn().mockReturnThis(), json: jest.fn() } as unknown) as Response;
        await GetCountriesList(mReq, mRes);
        expect(mRes.status).toBeCalledWith(400);
        expect(mRes.json).toBeCalledWith({ status: 400, message: 'fake message', count: 0, data: 'fake data' });
      });
    });
    

    unit test result:

     PASS  examples/66449420/controller.test.ts
      GetCountriesList
        ✓ should pass (5 ms)
    
    ---------------|---------|----------|---------|---------|-------------------
    File           | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    ---------------|---------|----------|---------|---------|-------------------
    All files      |   83.33 |      100 |      50 |   83.33 |                   
     controller.ts |     100 |      100 |     100 |     100 |                   
     services.ts   |      50 |      100 |       0 |      50 | 2                 
    ---------------|---------|----------|---------|---------|-------------------
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        4.132 s, estimated 5 s
    

    source code: https://github.com/mrdulin/jest-v26-codelab/tree/main/examples/66449420