2

I am using nock and I'm trying to remove interceptors for certain hostname.

I have tried using:

nock.removeInterceptor({
      hostname: 'somehostname.com',
      proto: 'https',
      path: '/',
    }),

When I print the result of this, it actually gives me true

I have also tried:

const mock = nock(somehostname.com)
    .persist()
    .post('/endpoint')
    .reply(200);

nock.removeInterceptor(mock)

But this gives me false somehow.

The way I'm checking if this is working is by printing the activeMocks: nock.activeMocks() And it still has the interceptors that I'm trying to remove.

Does anyone know what happens?

Felicia Amy
  • 51
  • 1
  • 6
  • The reason your second option doesn't work is because `reply` returns a Scope instead of an Interface. In that case, you want to use the returned value of `post`. As for the first example that returns `true`, we need more info about how the Interceptor was created. There is some sort of mismatch. Can you provide an example? – Matt R. Wilson Jul 22 '19 at 21:06

3 Answers3

5

I'd got the same problem and I solved like this:

const mock = nock(somehostname.com)
    .persist()
    .post('/endpoint')
    .reply(200);

nock.removeInterceptor(mock.interceptors[0])

mock.interceptors is a array of all Interceptor object registered for this scope, so I get the most recently created scope and remove it from nock.

Abe
  • 1,357
  • 13
  • 31
  • This does the trick - or for us: mock.interceptors.forEach(nock.removeInterceptor); does what we want. But our concern is that we're using an internal variable that nock doesn't expose officially through its scope interface. It seems that if nock is going to return you a scope object to represent everything you've mocked in that scope, there should be a function on that scope to cancel/delete it. There's not much other value in the scope variable if you can't manipulate the scope with it. But poking our noses in that array works. Thx. – KrayzeeKev Mar 05 '21 at 01:31
4

It appears that nock uses singletons underneath and that calling nock("my/base-route/i/already/mocked") returns the scope which can then be used to query the interceptor again by using scope.get("my/endpoint/I/already/mocked"), which returns the interceptor. This interceptor can then be removed using nock.removeInterceptor(interceptor) which should return true.

So in total:

function mockRoute() {
    nock("my/base-route/i/already/mocked")
    .get("my/endpoint/I/already/mocked")
    .reply("Something")
}

function removeExistingMock(): boolean {
    const scope = nock("my/base-route/i/already/mocked")
    const interceptor = scope.get("my/endpoint/I/already/mocked")
    return nock.removeInterceptor(interceptor)
}
Elias
  • 515
  • 5
  • 10
0

This worked for me:

nock.removeInterceptor({
  proto: 'https',
  hostname: 'www.somehostname.com',
  path: `/somepath`,
})

It did take a bit of trial and error and looking at the code to get the right options. It looks pretty similar to your code, so the only possible differences I can see are that subdomain and full path are included.

Note that removing the interceptors doesn't remove the mock itself. That is, requests will fail rather than be allowed through to the actual url.

I found the boolean return value unhelpful. It can return true even when no interceptors were removed. I created an issue for that.

Justin Caldicott
  • 739
  • 8
  • 22