Search code examples
node.jsnock

is there a way to nock an array of endpoints?


I want to abstract the client API responses from the tests and I'm trying to come up with a helper for that, for example:

class MockedClientApi {
  constructor() {
     this.nock = nock('https://client.domain.com');
  }

  getCountryInfo(country) {
    const endpoint = `/api/info/country/${country}`;
    return this.nock(endpoint).reply(200, responses.getCountryInfo);
  }
  getUserInfo(userId) {
    const endpoint = `/api/info/user/${userId}`;
    return this.nock(endpoint).reply(200, responses.getUserInfo);
  }
}

and then in tests, I can write something like:

let mockedRequests;
before('mock calls', () => {
  mockedRequests = [
    global.clientApi.getCountryInfo('GB'),
    global.clientApi.getUserInfo('ABC')
  ];
});

and of course, this is not like the chaining that nock uses:

mockedRequests = nock('https://client.domain.com')
  .get(`/api/info/country/${country}`)
  .reply(200, responses.getCountryInfo)
  .get(`/api/info/user/${userId}`)
  .reply(200, responses.getUserInfo)

as later I do:

describe('when client API is called', () => {
    it('should call all mocked endpoints', () => {
        expect(mockedRequests.pendingMocks()).to.deep.equal([]);
    });
});

How can one do chaining from dynamic calls/single calls?

I even tried to come up with ideas that didn't work, like:

  mockedRequests = nock([
    global.clientApi.getCountryInfo('GB'),
    global.clientApi.getUserInfo('ABC')
  ]);

Solution

  • It looks like you are initializing nock multiple times, ending up with multiple/different instances or mutating the original one.

    In each class function where you add a mocked request, you should call the instance of nock's "method" function (get, post, etc.) to add each endpoint you want to mock. Then you could add a function to get the full instance of nock or just create helper functions for each assertion you need, like getPendingMocks().

    const { expect } = require('chai');
    const nock = require('nock');
    
    class MockedClientApi {
        constructor() {
            this.mockedApi = nock('https://google.com')
        }
    
        getCountryInfo(country) {
            const endpoint = `/api/info/country/${country}`;
    
            return this.mockedApi.get(endpoint).reply(200, responses.getCountryInfo); // return might be unnecessary
        }
    
        getUserInfo(userId) {
            const endpoint = `/api/info/user/${userId}`;
    
            return this.mockedApi.get(endpoint).reply(200, responses.getUserInfo);
        }
    
        getPendingMocks() {
            return this.mockedApi.pendingMocks();
        }
    }
    
    describe('make tests', () => {
        let mockedClientApi;
        before('get mock', () => {
            mockedClientApi = new MockedClientApi();
    
            mockedClientApi.getCountryInfo();
            mockedClientApi.getUserInfo();
        });
    
        it('should call google', () => {
            expect(mockedClientApi.getPendingMocks()).to.deep.equal([]);
        });
    });
    

    In the end you should also consider adding an after function to clear nock.