twreporter-react
Version:
React-Redux site for The Reporter Foundation in Taiwan
314 lines (195 loc) • 5.89 kB
JavaScript
;
var nock = require('./scope');
var recorder = require('./recorder');
var format = require('util').format;
var mkdirp = require('mkdirp');
var path = require('path');
var expect = require('chai').expect;
var debug = require('debug')('nock.back');
var _mode = null;
var fs;
try {
fs = require('fs');
} catch(err) {
// do nothing, probably in browser
}
/**
* nock the current function with the fixture given
*
* @param {string} fixtureName - the name of the fixture, e.x. 'foo.json'
* @param {object} options - [optional], extra options for nock with, e.x. { assert: true }
* @param {function} nockedFn - the callback function to be executed with the given fixture being loaded,
* the function will be called with { scopes: loaded_nocks || [] } set as this
*
*
* List of options:
*
* @param {function} before - a preprocessing function, gets called before nock.define
* @param {function} after - a postprocessing function, gets called after nock.define
* @param {function} afterRecord - a postprocessing function, gets called after recording. Is passed the array
* of scopes recorded and should return the array scopes to save to the fixture
*
*/
function Back (fixtureName, options, nockedFn) {
if(!Back.fixtures) {
throw new Error( 'Back requires nock.back.fixtures to be set\n' +
'Ex:\n' +
'\trequire(nock).back.fixtures = \'/path/to/fixures/\'');
}
if( arguments.length === 2 ) {
nockedFn = options;
options = {};
}
_mode.setup();
var fixture = path.join(Back.fixtures, fixtureName)
, context = _mode.start(fixture, options);
var nockDone = function () {
_mode.finish(fixture, options, context);
};
debug('context:', context);
nockedFn.call(context, nockDone);
}
/*******************************************************************************
* Modes *
*******************************************************************************/
var wild = {
setup: function () {
nock.cleanAll();
recorder.restore();
nock.activate();
nock.enableNetConnect();
},
start: function () {
return load(); //don't load anything but get correct context
},
finish: function () {
//nothing to do
}
};
var dryrun = {
setup: function () {
recorder.restore();
nock.cleanAll();
nock.activate();
// We have to explicitly enable net connectivity as by default it's off.
nock.enableNetConnect();
},
start: function (fixture, options) {
var contexts = load(fixture, options);
nock.enableNetConnect();
return contexts;
},
finish: function () {
//nothing to do
}
};
var record = {
setup: function () {
recorder.restore();
recorder.clear();
nock.cleanAll();
nock.activate();
nock.disableNetConnect();
},
start: function (fixture, options) {
if (! fs) {
throw new Error('no fs');
}
var context = load(fixture, options);
if( !context.isLoaded ) {
recorder.record({
dont_print: true,
output_objects: true
});
context.isRecording = true;
}
return context;
},
finish: function (fixture, options, context) {
if( context.isRecording ) {
var outputs = recorder.outputs();
if( typeof options.afterRecord === 'function' ) {
outputs = options.afterRecord(outputs);
}
outputs = JSON.stringify(outputs, null, 4);
debug('recorder outputs:', outputs);
mkdirp.sync(path.dirname(fixture));
fs.writeFileSync(fixture, outputs);
}
}
};
var lockdown = {
setup: function () {
recorder.restore();
recorder.clear();
nock.cleanAll();
nock.activate();
nock.disableNetConnect();
},
start: function (fixture, options) {
return load(fixture, options);
},
finish: function () {
//nothing to do
}
};
function load (fixture, options) {
var context = {
scopes : [],
assertScopesFinished: function () {
assertScopes(this.scopes, fixture);
}
};
if( fixture && fixtureExists(fixture) ) {
var scopes = nock.loadDefs(fixture);
applyHook(scopes, options.before);
scopes = nock.define(scopes);
applyHook(scopes, options.after);
context.scopes = scopes;
context.isLoaded = true;
}
return context;
}
function applyHook(scopes, fn) {
if( !fn ) {
return;
}
if( typeof fn !== 'function' ) {
throw new Error ('processing hooks must be a function');
}
scopes.forEach(fn);
}
function fixtureExists(fixture) {
if (! fs) {
throw new Error('no fs');
}
return fs.existsSync(fixture);
}
function assertScopes (scopes, fixture) {
scopes.forEach(function (scope) {
expect( scope.isDone() )
.to.be.equal(
true,
format('%j was not used, consider removing %s to rerecord fixture', scope.pendingMocks(), fixture)
);
});
}
var Modes = {
wild: wild, //all requests go out to the internet, dont replay anything, doesnt record anything
dryrun: dryrun, //use recorded nocks, allow http calls, doesnt record anything, useful for writing new tests (default)
record: record, //use recorded nocks, record new nocks
lockdown: lockdown, //use recorded nocks, disables all http calls even when not nocked, doesnt record
};
Back.setMode = function(mode) {
if( !Modes.hasOwnProperty(mode) ) {
throw new Error ('some usage error');
}
Back.currentMode = mode;
debug('New nock back mode:', Back.currentMode);
_mode = Modes[mode];
_mode.setup();
};
Back.fixtures = null;
Back.currentMode = null;
Back.setMode(process.env.NOCK_BACK_MODE || 'dryrun');
module.exports = exports = Back;