123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- var failIfThrows = function (done) {
- 'use strict';
- return function (e) {
- done(e || new Error());
- };
- };
- describe('Promise.all', function () {
- 'use strict';
- it('should not be enumerable', function () {
- expect(Promise).ownPropertyDescriptor('all').to.have.property('enumerable', false);
- });
- it('fulfills if passed an empty array', function (done) {
- var iterable = [];
- Promise.all(iterable).then(function (value) {
- assert(Array.isArray(value));
- assert.deepEqual(value, []);
- }).then(done, failIfThrows(done));
- });
- it('fulfills if passed an empty array-like', function (done) {
- var f = function () {
- Promise.all(arguments).then(function (value) {
- assert(Array.isArray(value));
- assert.deepEqual(value, []);
- }).then(done, failIfThrows(done));
- };
- f();
- });
- it('fulfills if passed an array of mixed fulfilled promises and values', function (done) {
- var iterable = [0, Promise.resolve(1), 2, Promise.resolve(3)];
- Promise.all(iterable).then(function (value) {
- assert(Array.isArray(value));
- assert.deepEqual(value, [0, 1, 2, 3]);
- }).then(done, failIfThrows(done));
- });
- it('rejects if any passed promise is rejected', function (done) {
- var foreverPending = new Promise(function () { });
- var error = new Error('Rejected');
- var rejected = Promise.reject(error);
- var iterable = [foreverPending, rejected];
- Promise.all(iterable).then(
- function () {
- assert(false, 'should never get here');
- },
- function (reason) {
- assert.strictEqual(reason, error);
- }
- ).then(done, failIfThrows(done));
- });
- it('resolves foreign thenables', function (done) {
- var normal = Promise.resolve(1);
- var foreign = { then: function (f) { f(2); } };
- var iterable = [normal, foreign];
- Promise.all(iterable).then(function (value) {
- assert.deepEqual(value, [1, 2]);
- }).then(done, failIfThrows(done));
- });
- it('fulfills when passed an sparse array, giving `undefined` for the omitted values', function (done) {
- /* eslint-disable no-sparse-arrays */
- var iterable = [Promise.resolve(0), , , Promise.resolve(1)];
- /* eslint-enable no-sparse-arrays */
- Promise.all(iterable).then(function (value) {
- assert.deepEqual(value, [0, undefined, undefined, 1]);
- }).then(done, failIfThrows(done));
- });
- it('does not modify the input array', function (done) {
- var input = [0, 1];
- var iterable = input;
- Promise.all(iterable).then(function (value) {
- assert.notStrictEqual(input, value);
- }).then(done, failIfThrows(done));
- });
- it('should reject with a TypeError if given a non-iterable', function (done) {
- var notIterable = {};
- Promise.all(notIterable).then(
- function () {
- assert(false, 'should never get here');
- },
- function (reason) {
- assert(reason instanceof TypeError);
- }
- ).then(done, failIfThrows(done));
- });
- // test cases from
- // https://github.com/domenic/promises-unwrapping/issues/89#issuecomment-33110203
- var tamper = function (p) {
- // eslint-disable-next-line no-param-reassign
- p.then = function (fulfill, reject) {
- fulfill('tampered');
- return Promise.prototype.then.call(this, fulfill, reject);
- };
- return p;
- };
- it('should be robust against tampering (1)', function (done) {
- var g = [tamper(Promise.resolve(0))];
- // Prevent countdownHolder.[[Countdown]] from ever reaching zero
- Promise.all(g).then(
- function () { done(); },
- failIfThrows(done)
- );
- });
- it('should be robust against tampering (2)', function (done) {
- // Promise from Promise.all resolved before arguments
- var fulfillCalled = false;
- var g = [
- Promise.resolve(0),
- tamper(Promise.resolve(1)),
- Promise.resolve(2).then(function () {
- assert(!fulfillCalled, 'should be resolved before all()');
- }).then(function () {
- assert(!fulfillCalled, 'should be resolved before all()');
- })['catch'](failIfThrows(done))
- ];
- Promise.all(g).then(function () {
- assert(!fulfillCalled, 'should be resolved last');
- fulfillCalled = true;
- }).then(done, failIfThrows(done));
- });
- it('should be robust against tampering (3)', function (done) {
- var g = [
- Promise.resolve(0),
- tamper(Promise.resolve(1)),
- Promise.reject(2)
- ];
- // Promise from Promise.all resolved despite rejected promise in arguments
- Promise.all(g).then(function () {
- throw new Error('should not reach here!');
- }, function (e) {
- assert.strictEqual(e, 2);
- }).then(done, failIfThrows(done));
- });
- it('should be robust against tampering (4)', function (done) {
- var hijack = true;
- var actualArguments = [];
- var P = function (resolver) {
- var self;
- if (hijack) {
- hijack = false;
- self = new Promise(function (resolve, reject) {
- resolver(function (values) {
- // record arguments & # of times resolve function is called
- actualArguments.push(values.slice());
- return resolve(values);
- }, reject);
- });
- } else {
- self = new Promise(resolver);
- }
- Object.setPrototypeOf(self, P.prototype);
- return self;
- };
- if (!Object.setPrototypeOf) { return done(); } // skip test if on IE < 11
- Object.setPrototypeOf(P, Promise);
- P.prototype = Object.create(Promise.prototype, {
- constructor: { value: P }
- });
- P.resolve = function (p) { return p; };
- var g = [
- Promise.resolve(0),
- tamper(Promise.resolve(1)),
- Promise.resolve(2)
- ];
- // Promise.all calls resolver twice
- P.all(g)['catch'](failIfThrows(done));
- Promise.resolve().then(function () {
- assert.deepEqual(actualArguments, [[0, 'tampered', 2]]);
- }).then(done, failIfThrows(done));
- });
- });
|