Record all remote calls in a nodejs express app for testing

1.8k views Asked by At

The goal is to have recored api tests. This test are kind of integration tests, they load the whole app with all its middlewares and intercepts the external http calls and records them.

In Python world exists "WebTest" and "VCRPY" for that.

The app:

'use strict';

const express = require('express');
const request = require('superagent');

var app = express();

app.get('/hammer/version', function(req, res) {
    request
        .get('http://httpbin.org/get')
        .end(function(err, response) {
            console.log(response.body);
            res.status(200).json({
                version: '0.1.0',
                url: response.body.url
            });
        });
});

module.exports = app;

The test:

/* global describe, it */
'use strict';

const request = require('supertest');
const app = require('./app.js');

var path = require('path');
var tape = require('tape');
var tapeNock = require('tape-nock');

// call tapeNock with tape and an options object
var test = tapeNock(tape, {
    fixtures: path.join(__dirname, 'fixtures')
});

describe('Version test', function() {
    this.timeout(0);

    it('test version', function(done) {
        test('record_version.json', function(t) {
            request(app)
                .get('/hammer/version')
                .expect(200, {
                    url: "http://httpbin.org/get",
                    version: '0.1.0'
                })
                .end(function(err, res) {
                    if (err) return done(err);
                    t.end();
                    done();
                });
        });
    });
});

The "package.json":

{
  "name": "remote_node_test",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "dependencies": {
    "express": "^4.14.0",
    "mocha": "^3.2.0",
    "nock": "^9.0.2",
    "superagent": "^3.3.1",
    "supertest": "^2.0.1",
    "tape": "^4.6.3",
    "tape-nock": "^1.4.0"
  },
  "devDependencies": {
    "mocha": "^3.2.0"
  },
  "scripts": {
    "test": "mocha"
  },
  "author": "",
  "license": "ISC"
}

The test are run with "mocha":

NOCK_BACK_MODE=record  node_modules/mocha/bin/mocha 

First run works, second run with "lockdown/record" does not work.

The error:

% NOCK_BACK_MODE=lockdown  node_modules/mocha/bin/mocha test.js                                                                                                                              :(


  Version test
TAP version 13
# details.json
    1) return current version


  0 passing (32ms)
  1 failing

  1) Version test return current version:
     TypeError: Cannot read property 'status' of undefined
      at Test._assertStatus (node_modules/supertest/lib/test.js:263:10)
      at Test._assertFunction (node_modules/supertest/lib/test.js:281:11)
      at Test.assert (node_modules/supertest/lib/test.js:171:18)
      at Server.assert (node_modules/supertest/lib/test.js:131:12)
      at emitCloseNT (net.js:1553:8)
      at _combinedTickCallback (internal/process/next_tick.js:71:11)
      at process._tickCallback (internal/process/next_tick.js:98:9)

Recorded are all requests, but i need only to record the "external" requests, and prevent "mocking/recording" my internal logic.

2

There are 2 answers

1
Flet On BEST ANSWER

If you're using mocha, you may want to look for a similar nock/nockBack helpers that are mocha-specific (https://www.npmjs.com/search?q=mocha+nock)

That being said, you may also run into problems where the HTTP call supertest makes to the app gets picked up by nockBack.

I made a little example that uses only tape to do what you're trying to accomplish: https://github.com/Flet/tape-nock-with-supertest-example

The afterRecord and before functions defined in setup-tape-nock.js are probably the secret sauce you would need even if using some other nockBack mocha helper.

Hope this helps!

0
delijati On

One solution seems "replay" and configuring "passThrough" of requests to my local app.

/* global describe, it */
'use strict';

const request = require('supertest');
const app = require('./app.js');

var path = require('path');
const Replay = require('replay');

Replay.fixtures = __dirname + '/fixtures/replay';
Replay.passThrough('localhost', '127.0.0.1', '0.0.0.0');

describe('Version test', function() {
    this.timeout(0);

    it('test version', function(done) {
        request(app)
            .get('/hammer/version')
            .expect(200, {
                url: "http://httpbin.org/get",
                version: '0.1.0'
            })
            .end(function(err, res) {
                if (err) return done(err);
                done();
            });
    });
});