How do I create a test for my services controller (Jest)?

I'm trying to create a test for my Animals List Services Controller, making sure the database query is tested. Right now with what I have, I have been able to mock the database query call to ensure the query is being called with the right parameters. However, i'm also trying to mock the return values from the database query call. I'm not sure how to mock dbResult in "services.ts" to get the rows property. Please I need some help, not sure how to do it. Thank you in advance.

I believe I was able to mock the database query call, however, is there a way to refactor or create a test to mock the return call of dbResult?

services.ts

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

export async function GetAnimalsList(): Promise<DBGenericDataResponse> {
    const lQuery = `select animalid, description from animal where active=1 order by sortorder, description`;
    const responseMessage: DBGenericDataResponse = {
        code: 200,
        status: 'ok',
        message: '',
        count: 0,
        data: [],
        error: ''
    };
    try {
        const dbResult = await db.query<any>(lQuery);
        responseMessage.message = 'Animals Returned';
        responseMessage.count = dbResult.rows.length;
        responseMessage.data = dbResult.rows;
    } catch (err) {
        responseMessage.code = 400;
        responseMessage.status = 'error';
        responseMessage.message = 'Error retrieving Animals List';
        responseMessage.error  = err;
    }
    return responseMessage;
}

ServicesTest.spec.ts

import * as Services from '../../../../src/controllers/animals/services';
import db from '../../../../src/modules/db';


describe('GetAnimalsList', () => {
   afterEach(() => {
      jest.resetAllMocks();
   });

   it('should call the database with the correct query parameter', async () => {
      const dbMock = jest.spyOn(db, 'query');

      const response = await Services.GetAnimalsList();

      expect(dbMock).toBeCalled();
      expect(dbMock).toHaveBeenCalledWith(
         'select animalid, description from animal where active=1 order by sortorder, description'
      );
   });
});

1 answer

  • answered 2021-04-15 02:22 slideshowp2

    Use mockFn.mockResolvedValueOnce(value) to mock resolved value for db.query(), use mockFn.mockRejectedValueOnce(value) to mock rejected value for db.query().

    E.g.

    db.ts:

    export default {
      async query<T>(sql: string): Promise<{ rows: T[] }> {
        return {
          rows: [],
        };
      },
    };
    

    service.ts:

    import db from './db';
    
    interface DBGenericDataResponse {
      code: number;
      status: string;
      message: string;
      count: number;
      data: any[];
      error: string;
    }
    
    export async function GetAnimalsList(): Promise<DBGenericDataResponse> {
      const lQuery = `select animalid, description from animal where active=1 order by sortorder, description`;
      const responseMessage: DBGenericDataResponse = {
        code: 200,
        status: 'ok',
        message: '',
        count: 0,
        data: [],
        error: '',
      };
      try {
        const dbResult = await db.query<any>(lQuery);
        responseMessage.message = 'Animals Returned';
        responseMessage.count = dbResult.rows.length;
        responseMessage.data = dbResult.rows;
      } catch (err) {
        responseMessage.code = 400;
        responseMessage.status = 'error';
        responseMessage.message = 'Error retrieving Animals List';
        responseMessage.error = err;
      }
      return responseMessage;
    }
    

    service.test.ts:

    import * as services from './service';
    import db from './db';
    
    describe('67099512', () => {
      afterEach(() => {
        jest.clearAllMocks();
      });
      it('should get animal list', async () => {
        const dbMock = jest.spyOn(db, 'query').mockResolvedValueOnce({ rows: ['dog', 'cat'] });
        const response = await services.GetAnimalsList();
        expect(response).toEqual({
          code: 200,
          status: 'ok',
          error: '',
          message: 'Animals Returned',
          count: 2,
          data: ['dog', 'cat'],
        });
        expect(dbMock).toBeCalled();
        expect(dbMock).toHaveBeenCalledWith(
          'select animalid, description from animal where active=1 order by sortorder, description'
        );
      });
    
      it('should handle error', async () => {
        const error = new Error('Internal server error');
        const dbMock = jest.spyOn(db, 'query').mockRejectedValueOnce(error);
        const response = await services.GetAnimalsList();
        expect(response).toEqual({
          code: 400,
          status: 'error',
          error,
          message: 'Error retrieving Animals List',
          count: 0,
          data: [],
        });
        expect(dbMock).toBeCalled();
        expect(dbMock).toHaveBeenCalledWith(
          'select animalid, description from animal where active=1 order by sortorder, description'
        );
      });
    });
    

    unit test result:

     PASS  examples/67099512/service.test.ts (11.552 s)
      67099512
        ✓ should get animal list (5 ms)
        ✓ should handle error (1 ms)
    
    ------------|---------|----------|---------|---------|-------------------
    File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    ------------|---------|----------|---------|---------|-------------------
    All files   |   93.75 |      100 |      50 |   93.75 |                   
     db.ts      |      50 |      100 |       0 |      50 | 3                 
     service.ts |     100 |      100 |     100 |     100 |                   
    ------------|---------|----------|---------|---------|-------------------
    Test Suites: 1 passed, 1 total
    Tests:       2 passed, 2 total
    Snapshots:   0 total
    Time:        14.375 s