Skip to content

Instantly share code, notes, and snippets.

@bryanaka
Last active December 24, 2015 21:09
Show Gist options
  • Save bryanaka/6863887 to your computer and use it in GitHub Desktop.
Save bryanaka/6863887 to your computer and use it in GitHub Desktop.
A very simple promise demonstration. Tests can be run using Jasmine and Karma Test Runner. Karma Config posted at https://gist.github.com/bryanaka/6863961
/* jshint undef: true, unused: true */
(function(window) {
'use strict';
var Promise = function () {
this.state = 'pending';
this._successHandlers = [];
this.values = null;
};
Promise.prototype.resolve = function resolve() {
var callbacks = this._successHandlers,
len = callbacks.length,
i;
if(this.state === 'pending') {
this.state = 'success';
this.values = arguments;
for(i = 0; i < len; i++) {
callbacks[i].apply(this, arguments);
}
} else {
this.reject('This promise has already been resolved');
}
};
Promise.prototype.success = function success(callback) {
if(this.state === 'success') {
callback.apply(this, this.values);
} else{
this._successHandlers.push(callback);
}
};
Promise.prototype.reject = function reject(reason) {
this.state = (this.state === 'success' ? 'success' : 'error');
throw new Error(reason);
};
window.Promise = Promise;
})(window);
/* jshint undef: false, unused: true */
describe('Promise', function() {
'use strict';
var prom;
beforeEach(function() {
prom = new Promise();
});
it('begins with a pending state', function() {
expect(prom.state).toBe('pending');
});
describe('#success', function () {
it('registers functions to this._successHandlers', function() {
prom.success(function () {
console.log('yo');
});
expect(prom._successHandlers.length).toBe(1);
});
it('can register multiple functions', function() {
prom.success(function () {
console.log('yo');
});
prom.success(function () {
console.log('dawg');
});
expect(prom._successHandlers.length).toBe(2);
});
it('executes immediately if the promise has already been resolved', function() {
var hi, asyncFlag;
runs(function(){
prom.resolve('world');
prom.success(function(place) {
asyncFlag = true;
hi = 'hello ' + place;
});
});
waitsFor(function() {
return asyncFlag;
}, 'timed out', 1500);
runs(function() {
expect(hi).toEqual('hello world');
});
});
});
describe('#resolve', function() {
var followUp = 'hows it going?',
person,
asyncFlag;
beforeEach(function() {
person = {
greet: function greet() {
console.log('Hello good sir');
},
saySup: function saySup(followUp, stuff) {
console.log('Sup man? '+followUp);
console.log('i haz '+stuff);
}
};
spyOn(person, 'greet');
spyOn(person, 'saySup');
prom.success(person.greet);
prom.success(person.saySup);
});
it('triggers any success handlers to be run', function() {
prom.resolve();
expect(person.greet).toHaveBeenCalled();
expect(person.saySup).toHaveBeenCalled();
});
it('triggers successHandlers and passes the data to them', function() {
var stuff = {'clothes': 'shirt'};
prom.resolve(followUp, stuff);
expect(person.saySup).toHaveBeenCalledWith(followUp, stuff);
});
it('moves promise.state to success', function() {
prom.resolve();
expect(prom.state).toEqual('success');
});
describe('if called twice', function() {
it('throws on second call', function() {
prom.resolve();
expect(prom.resolve).toThrow();
});
it('throws with the appropriate message', function() {
try {
prom.resolve();
prom.resolve();
} catch(e) {
expect(e.message).toContain('already');
expect(e.message).toContain('resolved');
}
});
it('maintains a success state', function() {
try {
prom.resolve();
prom.resolve();
} catch(e) {
expect(prom.state).toEqual('success');
}
});
});
it('can trigger success handlers asyncronously', function() {
var foo = new Promise(),
bar = new Promise(),
dude1,
dude2;
runs(function() {
asyncFlag = false;
foo.resolve('hello');
setTimeout(function() {
bar.resolve('sup breh');
}, 500);
foo.success(function(greeting) {
dude1 = greeting+' Bryan';
});
bar.success(function(greeting) {
asyncFlag = true;
dude2 = 'Derek, ' + greeting;
});
});
waitsFor(function(){
return asyncFlag;
}, 'timed out dude', 1000);
runs(function() {
expect(dude1).toEqual('hello Bryan');
expect(dude2).toEqual('Derek, sup breh');
});
});
});
describe('#reject', function() {
it('places the promise into an error state', function() {
try { prom.reject(); }
catch(e) {
expect(prom.state).toEqual('error');
}
});
it('throws an exception', function() {
expect(prom.reject).toThrow();
});
it('throws an exception with the reason provided as message', function() {
try {
prom.reject('rejected as a test');
} catch(e) {
expect(e.message).toEqual('rejected as a test');
}
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment