Search code examples
javascriptnode.jstestingjestjsend-to-end

Testing gRPC functions


I have a task to test gRPC client call functions with Jest. Here is what a typical node.js function looks like:

client.authenticate(request, meta, (error, response) => {
   if (!error) {
      console.log('REPLY FROM SERVER: ', response)
   } else {
    console.error(error)
  }
})

Procedure calls are callback functions, as we see I can not export response object to outside variable. The above function is the one I need to test. I need to check if the function has been called with no error. How do I do it with jest? Been struggling for a while now.


Solution

  • You can use jest.spyOn(object, methodName) to mock client.authenticate.

    E.g.

    index.ts:

    import { client } from './client';
    
    export function main() {
      const request = {};
      const meta = {};
      client.authenticate(request, meta, (error, response) => {
        if (!error) {
          console.log('REPLY FROM SERVER: ', response);
        } else {
          console.error(error);
        }
      });
    }
    

    client.ts:

    export const client = {
      authenticate(request, meta, callback) {
        console.log('real implementation');
      },
    };
    

    index.test.ts:

    import { main } from './';
    import { client } from './client';
    
    describe('62214949', () => {
      it('should log correct response', () => {
        const mResponse = 'mocked response';
        const logSpy = jest.spyOn(console, 'log');
        jest.spyOn(client, 'authenticate').mockImplementationOnce((request, meta, callback) => {
          console.log('mocked implementation');
          callback(null, mResponse);
        });
        main();
        expect(logSpy).toBeCalledWith('REPLY FROM SERVER: ', 'mocked response');
        expect(client.authenticate).toBeCalledWith({}, {}, expect.any(Function));
      });
    
      it('should handle error', () => {
        const mError = new Error('network');
        const logSpy = jest.spyOn(console, 'error');
        jest.spyOn(client, 'authenticate').mockImplementationOnce((request, meta, callback) => {
          console.log('mocked implementation');
          callback(mError);
        });
        main();
        expect(logSpy).toBeCalledWith(mError);
        expect(client.authenticate).toBeCalledWith({}, {}, expect.any(Function));
      });
    });
    

    unit test result with coverage report:

     PASS  stackoverflow/62214949/index.test.ts (10.557s)
      62214949
        ✓ should log correct response (23ms)
        ✓ should handle error (8ms)
    
      console.log
        mocked implementation
    
          at CustomConsole.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
    
      console.log
        REPLY FROM SERVER:  mocked response
    
          at CustomConsole.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
    
      console.log
        mocked implementation
    
          at CustomConsole.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
    
      console.error
        Error: network
            at Object.<anonymous> (/Users/ldu020/workspace/github.com/mrdulin/react-apollo-graphql-starter-kit/stackoverflow/62214949/index.test.ts:18:20)
            at Object.asyncJestTest (/Users/ldu020/workspace/github.com/mrdulin/react-apollo-graphql-starter-kit/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:100:37)
            at resolve (/Users/ldu020/workspace/github.com/mrdulin/react-apollo-graphql-starter-kit/node_modules/jest-jasmine2/build/queueRunner.js:45:12)
            at new Promise (<anonymous>)
            at mapper (/Users/ldu020/workspace/github.com/mrdulin/react-apollo-graphql-starter-kit/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
            at promise.then (/Users/ldu020/workspace/github.com/mrdulin/react-apollo-graphql-starter-kit/node_modules/jest-jasmine2/build/queueRunner.js:75:41)
            at process._tickCallback (internal/process/next_tick.js:68:7)
    
           8 |       console.log('REPLY FROM SERVER: ', response);
           9 |     } else {
        > 10 |       console.error(error);
             |               ^
          11 |     }
          12 |   });
          13 | }
    
          at CustomConsole.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
          at stackoverflow/62214949/index.ts:10:15
          at Object.<anonymous> (stackoverflow/62214949/index.test.ts:22:7)
    
    -----------|---------|----------|---------|---------|-------------------
    File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    -----------|---------|----------|---------|---------|-------------------
    All files  |      90 |      100 |   66.67 |      90 |                   
     client.ts |      50 |      100 |       0 |      50 | 3                 
     index.ts  |     100 |      100 |     100 |     100 |                   
    -----------|---------|----------|---------|---------|-------------------
    Test Suites: 1 passed, 1 total
    Tests:       2 passed, 2 total
    Snapshots:   0 total
    Time:        12.424s