Search code examples
javascriptnode.jsnock

Is it possible to nock an external service call inside a route


I'm trying to test a rest api which calls an external service.

server.js:

const express = require('express');
const app = express();
const router = express.Router();
const redirectUrl = require('../utils/redirection')

let baseUrl = 'myUrl';
let externalUrl = 'externalUrl';

router.get('/redirect', async (req, res) => {

  const { productName } = req.query;

  baseUrl = baseUrl + '/' + productName;
  externalUrl = externalUrl + '/' + productName;
  await redirectUrl(res)(timeOut, externalUrl, baseUrl)

})
app.use(router);

app.listen(3000);

utils/redirection.js:

edirectUrl = res => (timeOut, url, redirectUrl) => {
return new Promise((resolve, reject) => {
let cleared = false;

const timer = setTimeout(() => {
  cleared = true;
  return resolve(res.redirect(302, redirectUrl));
}, timeout);


return fetch(url)
  .then(
    response => {
      if (!cleared) {
        clearTimeout(timer);
        const {location} = response.headers;
        return resolve(res.redirect(302, location));
      }

      return null;
    })
  .catch(err => {
    if (!cleared) {
      clearTimeout(timer);
      return reject(err);
    }
  });


 });
}

test.js:

const requrest = require('request');
const chai = require('chai');
const server = require('../server/server');
const { expect } = chai;
describe('My test', () => {
  it('should redirects to the suitable page', () => {

   nock('url/to/external/service')
   .get('/${productName}')
   .reply(302, {
      headers: {
        location: 'this the page location'
   }})       

    const { status, headers } = request(app).get('/redirect')
    expect(status).to.equal(302);
    expect(headers.location).to.not.equal(0);

  })
})

When I execute the test, the request launches the API call. Then the redirectUrl was called inside. But nock does not intercept the request and the server call the external api. Does nock could intercept a depth HTTP request? or I missed something in my code? Does any suggestion please to resolve this problem?


Solution

  • Without a running example it's hard to tell what is going wrong. But I can tell there's a few things you can change here (I was also struggling with Nock today).

    First, since you're dealing with redirects, take a look at this comment. This worked for me: https://github.com/nock/nock/issues/147#issuecomment-71433752

    Second, pay attention: the syntax to specify headers is wrong, this is the correct one:

    nock('url/to/external/service')
       .get('/${productName}')
       .reply(302, 'whatever you want', {
          location: 'http://the.other.page.location'
       })
    

    Third: split your server.js file into two: server.js and app.js.

    app.js

    const app = express()
    ...
    module.exports = app
    

    server.js

    const app = require('./path/to/app.js')
    ...
    app.listen(3000)
    

    This way you can import your app.js into your test suite without the listen part, which will avoid problems with network ports when new tests are run.

    Let me know if this helped...