Skip to content

Commit

Permalink
Merge pull request #8 from qubyte/feature/return-promise
Browse files Browse the repository at this point in the history
Return promises from requireWithStubs and reset.
  • Loading branch information
mroderick committed Feb 24, 2016
2 parents fce46ad + 363d13b commit 26cb099
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 23 deletions.
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ define('Car', ['SteeringWheel'], function(SteeringWheel){

Car.prototype.getSteeringWheelColor = function getSteeringWheelColor(){
return this.steeringWheel.color;
}
};

return Car;
});
Expand Down Expand Up @@ -73,7 +73,7 @@ define([

afterEach(function(done){
bogus.reset(done);
})
});

describe('Car', function(){
describe('getSteeringWheelColor method', function(){
Expand All @@ -88,6 +88,29 @@ define([
});
```

### Promises

Both `bogus.require` and `bogus.reset` return promises. The `beforeEach` and
`afterEach` in the example above can be written as:

```javascript
beforeEach(function(){
var fakeSteeringWheel = function(){
this.color = 'blue';
};

bogus.stub('SteeringWheel', fakeSteeringWheel);

return bogus.require('Car').then(function(module){
Car = module;
});
});

afterEach(function(){
return bogus.reset();
});
```

### Stub multiple dependencies

If you're stubbing several dependencies, you can pass a map of them to `stub`
Expand Down
50 changes: 46 additions & 4 deletions bogus.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@ define(['require'], function(require){

'use strict';

// Modified (not to use global) and minified from https://github.com/timjansen/PinkySwear.js
/* jshint ignore:start */
var pinkySwear = (function(){function n(n){return"function"==typeof n}function t(n){return"object"==typeof n}function e(n){"undefined"!=typeof setImmediate?setImmediate(n):"undefined"!=typeof process&&process.nextTick?process.nextTick(n):setTimeout(n,0)}function r(o){var c,i=[],f=[],a=function(n,t){return null==c&&null!=n&&(c=n,i=t,f.length&&e(function(){for(var n=0;n<f.length;n++)f[n]()})),c};return a.then=function(a,p){var l=r(o),s=function(){function e(r){var o,c=0;try{if(r&&(t(r)||n(r))&&n(o=r.then)){if(r===l)throw new TypeError;o.call(r,function(){c++||e.apply(u,arguments)},function(n){c++||l(!1,[n])})}else l(!0,arguments)}catch(i){c++||l(!1,[i])}}try{var r=c?a:p;n(r)?e(r.apply(u,i||[])):l(c,i)}catch(o){l(!1,[o])}};return null!=c?e(s):f.push(s),l},o&&(a=o(a)),a}var u;return r}());
/* jshint ignore:end */

// PinkySwear is A+ only and lacks .catch, which is a part of ES2015 promises. This function is
// used as an argument to pinkySwear to bridge the gap (just in case).
function addCatch(p){
p.catch = function(cb){
p.then(undefined, cb);
};
return p;
}

function isObject(value){
return Object.prototype.toString.call(value) === '[object Object]';
}
Expand Down Expand Up @@ -61,18 +75,39 @@ define(['require'], function(require){
function requireWithStubs(name, callback, errback){
// Cache the current index of the module in the array.
var moduleIndex = stubbed.push(name) - 1;
var promise = pinkySwear(addCatch);

preserveDefinition(name);
requirejs.undef(name);


function resolve(mod){
promise(true, [mod]);

if (callback) {
callback(mod);
}
}

function reject(err){
promise(false, [err]);

if (errback) {
errback(err);
}
}

// Require all the dependencies to ensure that they're registered.
require(stubbed, function () {
callback(arguments[moduleIndex]); // Return the required module.
}, errback);
require(stubbed, function(){
resolve(arguments[moduleIndex]); // Return the required module.
}, reject);

return promise;
}

function reset(callback){
var originalsToRestore = [];
var promise = pinkySwear(addCatch);

if (stubbed.length === 0) {
callback();
Expand All @@ -93,8 +128,15 @@ define(['require'], function(require){
// require the module in order to trigger requirejs to commit to defining it
require(originalsToRestore, function(){
stubbed = [];
callback();

if (callback) {
callback();
}

promise(true, []);
});

return promise;
}

return {
Expand Down
67 changes: 50 additions & 17 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@
it('should be a function', function(){
assert(typeof bogus.requireWithStubs === 'function');
});

it('should return a promise', function(){
var p = bogus.requireWithStubs('blah', function(){}, function(){});

assert.equal(typeof p.then, 'function');
assert.equal(typeof p.catch, 'function');
});
});

describe('require method', function(){
Expand All @@ -120,18 +127,22 @@
});

describe('reset method', function(){
it('should return all original implementations to their names', function(done){
var define = requirejs.define,
modules = [],
moduleNames = [],
i, j, module,
defineStub;
var modules;
var defineStub;

beforeEach(function(done){
var define = requirejs.define;
var i;
var moduleNames = [];
var module;

modules = [];

sandbox.stub(requirejs, 'defined', function(){
return true;
});

for (i = 0; i < 10; i++){
for (i = 0; i < 10; i++) {
module = {
name : getUniqueModuleName(),
originalImplementation : {name: 'original'},
Expand All @@ -146,19 +157,41 @@
}

defineStub = sandbox.spy(requirejs, 'define');
requirejs(moduleNames, function () {
bogus.reset(function(){
j = 0;
modules.forEach(function(module, index){
var call = defineStub.getCall(index);

assert.equal(call.args[0], module.name);
j++;
});
requirejs(moduleNames, function(){
done();
});
});

it('is a function', function(){
assert.equal(typeof bogus.reset, 'function');
});

it('returns a promise', function(){
var p = bogus.reset();

assert.equal(typeof p.then, 'function');
assert.equal(typeof p.catch, 'function');
});

it('returns all original implementations to their names and call a callback', function(done){
bogus.reset(function(){
modules.forEach(function(module, index){
var call = defineStub.getCall(index);

assert.equal(call.args[0], module.name);
});

done();
});
});

assert.equal(j, modules.length);
it('returns all original implementations to their names and resolves a returned promise', function(){
return bogus.reset().then(function(){
modules.forEach(function(module, index){
var call = defineStub.getCall(index);

done();
assert.equal(call.args[0], module.name);
});
});
});
Expand Down

0 comments on commit 26cb099

Please sign in to comment.