Search code examples
node.jsmockingjestjsexpress-validatorts-jest

How to mock and avoid express-validator calls in jest?


There is code in our codebase like below:

@Validate(Param1)
async post(request, responseHandler) {
 // some code
}

I Am trying to test the post function. But want to avoid evaluating the @Validate function. The Validate is a function in another module.

// validator.ts
export const Validate = () => {
  // some code
}

How to? .


Solution

  • You could use jest.mock(moduleName, factory, options) create the mocked Validate decorator instead of using the real Validate decorator which may have a lot of validation rules.

    E.g.

    index.ts:

    import { Validate } from './validator';
    
    export class Controller {
      @Validate('params')
      async post(request, responseHandler) {
        console.log('real post implementation');
      }
    }
    

    validator.ts:

    export const Validate = (params) => {
      return (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => {
        const oFunc = descriptor.value;
        descriptor.value = function inner(...args: any[]) {
          console.log('real validator decorator implementation');
          // lots of validation
          const rval = oFunc.apply(this, args);
          return rval;
        };
      };
    };
    

    index.test.ts:

    import { Validate } from './validator';
    import { mocked } from 'ts-jest/utils';
    
    jest.mock('./validator');
    
    describe('63531414', () => {
      afterAll(() => {
        jest.resetAllMocks();
      });
      it('should pass', async () => {
        mocked(Validate).mockImplementationOnce((params) => {
          return (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => {
            const oFunc = descriptor.value;
            descriptor.value = function inner(...args: any[]) {
              console.log('mocked validator decorator implementation');
              const rval = oFunc.apply(this, args);
              return rval;
            };
          };
        });
        const { Controller } = require('./');
        const logSpy = jest.spyOn(console, 'log');
        const ctrl = new Controller();
        await ctrl.post({}, () => {});
        expect(Validate).toBeCalledWith('params');
        expect(logSpy).toBeCalledWith('real post implementation');
      });
    });
    

    unit test result with coverage report:

     PASS  src/stackoverflow/63531414/index.test.ts (12.634s)
      63531414
        ✓ should pass (154ms)
    
      console.log node_modules/jest-mock/build/index.js:860
        mocked validator decorator implementation
    
      console.log node_modules/jest-mock/build/index.js:860
        real post implementation
    
    --------------|----------|----------|----------|----------|-------------------|
    File          |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
    --------------|----------|----------|----------|----------|-------------------|
    All files     |    45.45 |      100 |       25 |    45.45 |                   |
     index.ts     |      100 |      100 |      100 |      100 |                   |
     validator.ts |    14.29 |      100 |        0 |    14.29 |       2,3,4,5,7,8 |
    --------------|----------|----------|----------|----------|-------------------|
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        14.354s
    

    source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/63531414