[ui/promises] add tests for Promise.race()

This commit is contained in:
spalger 2017-02-16 12:15:51 -07:00
parent 4b1dbf8413
commit bc82b29623
2 changed files with 90 additions and 4 deletions

View file

@ -78,4 +78,90 @@ describe('Promise service', function () {
expect(thenback.getCall(0).args[0][1]).to.be(undefined);
});
});
describe('Promise.race()', () => {
let crankTimeout;
beforeEach(() => {
// constantly call $rootScope.$apply() in a loop so we can
// pretend that these are real promises
(function crank$apply() {
$rootScope.$apply();
crankTimeout = setTimeout(crank$apply, 1);
}());
});
afterEach(() => {
clearTimeout(crankTimeout);
});
it(`resolves with the first resolved promise's value`, async () => {
const p1 = new Promise(resolve => setTimeout(resolve, 100, 1));
const p2 = new Promise(resolve => setTimeout(resolve, 200, 2));
expect(await Promise.race([p1, p2])).to.be(1);
});
it(`rejects with the first rejected promise's rejection reason`, async () => {
const p1 = new Promise((r, reject) => setTimeout(reject, 200, new Error(1)));
const p2 = new Promise((r, reject) => setTimeout(reject, 100, new Error(2)));
expect(await Promise.race([p1, p2]).catch(e => e.message)).to.be('2');
});
it('does not wait for subsequent promises to resolve/reject', async () => {
const start = Date.now();
const p1 = new Promise(resolve => setTimeout(resolve, 100));
const p2 = new Promise(resolve => setTimeout(resolve, 5000));
await Promise.race([p1, p2]);
const time = Date.now() - start;
expect(time).to.be.lessThan(1000);
expect(time).to.be.greaterThan(100);
});
it('allows non-promises in the array', async () => {
expect(await Promise.race([1,2,3])).to.be(1);
});
context('argument is undefined', () => {
it('rejects the promise', async () => {
const football = {};
expect(await Promise.race().catch(e => football)).to.be(football);
});
});
context('argument is a string', () => {
it(`resolves with the first character`, async () => {
expect(await Promise.race('abc')).to.be('a');
});
});
context('argument is a non-iterable object', () => {
it('reject the promise', async () => {
const football = {};
expect(await Promise.race({}).catch(e => football)).to.be(football);
});
});
context('argument is a generator', () => {
it('resolves with the first resolved value', async () => {
function *gen() {
yield new Promise(resolve => setTimeout(resolve, 100, 1));
yield new Promise(resolve => setTimeout(resolve, 200, 2));
}
expect(await Promise.race(gen())).to.be(1);
});
it('resolves with the first non-promise value', async () => {
function *gen() {
yield 1;
yield new Promise(resolve => setTimeout(resolve, 200, 2));
}
expect(await Promise.race(gen())).to.be(1);
});
it('iterates all values from the generator, even if one is already "resolved"', async () => {
let yieldCount = 0;
function *gen() {
yieldCount += 1;
yield 1;
yieldCount += 1;
yield new Promise(resolve => setTimeout(resolve, 200, 2));
}
expect(await Promise.race(gen())).to.be(1);
expect(yieldCount).to.be(2);
});
});
});
});

View file

@ -95,11 +95,11 @@ module.service('Promise', function ($q, $timeout) {
});
});
};
Promise.race = function (arr) {
Promise.race = function (iterable) {
return new Promise((resolve, reject) => {
arr.forEach(p => {
Promise.resolve(p).then(resolve, reject);
});
for (const i of iterable) {
Promise.resolve(i).then(resolve, reject);
}
});
};