Last active
December 24, 2015 21:09
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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