旧版报表、仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

375 lines
9.4 KiB

var Promise = require('../lib');
var sinon = require('sinon');
var assert = require('assert');
var adapter = require('./adapter');
describe('Promises/A+ Tests', function() {
require('promises-aplus-tests').mocha(adapter);
});
describe('Promise', function() {
describe('Promise._immediateFn', function() {
afterEach(function() {
Promise._immediateFn =
(typeof setImmediate === 'function' &&
function(fn) {
setImmediate(fn);
}) ||
function(fn) {
setTimeout(fn, 1);
};
});
it('changes immediate fn', function() {
var spy = sinon.spy();
function immediateFn(fn) {
spy();
fn();
}
Promise._immediateFn = immediateFn;
var done = false;
new Promise(function(resolve) {
resolve();
}).then(function() {
done = true;
});
assert(spy.calledOnce);
assert(done);
});
it('changes immediate fn multiple', function() {
var spy1 = sinon.spy();
function immediateFn1(fn) {
spy1();
fn();
}
var spy2 = sinon.spy();
function immediateFn2(fn) {
spy2();
fn();
}
Promise._immediateFn = immediateFn1;
var done = false;
new Promise(function(resolve) {
resolve();
}).then(function() {});
Promise._immediateFn = immediateFn2;
new Promise(function(resolve) {
resolve();
}).then(function() {
done = true;
});
assert(spy2.called);
assert(spy1.calledOnce);
assert(done);
});
});
describe('Promise._onUnhandledRejection', function() {
var stub, sandbox;
beforeEach(function() {
sandbox = sinon.sandbox.create();
stub = sandbox.stub(console, 'warn');
});
afterEach(function() {
sandbox.restore();
});
it('no error on resolve', function(done) {
Promise.resolve(true)
.then(function(result) {
return result;
})
.then(function(result) {
return result;
});
setTimeout(function() {
assert(!stub.called);
done();
}, 50);
});
it('error single Promise', function(done) {
new Promise(function() {
throw new Error('err');
});
setTimeout(function() {
assert(stub.calledOnce);
done();
}, 50);
});
it('multi promise error', function(done) {
new Promise(function() {
throw new Error('err');
}).then(function(result) {
return result;
});
setTimeout(function() {
assert(stub.calledOnce);
done();
}, 50);
});
it('promise catch no error', function(done) {
new Promise(function() {
throw new Error('err');
}).catch(function(result) {
return result;
});
setTimeout(function() {
assert(!stub.called);
done();
}, 50);
});
it('promise catch no error', function(done) {
new Promise(function() {
throw new Error('err');
})
.then(function(result) {
return result;
})
.catch(function(result) {
return result;
});
setTimeout(function() {
assert(!stub.called);
done();
}, 50);
});
it('promise reject error', function(done) {
Promise.reject('hello');
setTimeout(function() {
assert(stub.calledOnce);
done();
}, 50);
});
it('promise reject error late', function(done) {
var prom = Promise.reject('hello');
prom.catch(function() {});
setTimeout(function() {
assert(!stub.called);
done();
}, 50);
});
it('promise reject error late', function(done) {
Promise.reject('hello');
setTimeout(function() {
assert.equal(stub.args[0][1], 'hello');
done();
}, 50);
});
});
describe('Promise.prototype.then', function() {
var spy, SubClass;
beforeEach(function() {
spy = sinon.spy();
SubClass = function() {
spy();
Promise.apply(this, arguments);
};
function __() {
this.constructor = SubClass;
}
__.prototype = Promise.prototype;
SubClass.prototype = new __();
SubClass.prototype.then = function() {
return Promise.prototype.then.apply(this, arguments);
};
});
it('subclassed Promise resolves to subclass', function() {
var prom = new SubClass(function(resolve) {
resolve();
}).then(function() {}, function() {});
assert(spy.calledTwice);
assert(prom instanceof SubClass);
});
it('subclassed Promise rejects to subclass', function() {
var prom = new SubClass(function(_, reject) {
reject();
}).then(function() {}, function() {});
assert(spy.calledTwice);
assert(prom instanceof SubClass);
});
});
function finallyTests(Promise) {
it('should be called on success', function(done) {
Promise.resolve(3).finally(function() {
assert.equal(arguments.length, 0, 'No arguments to onFinally');
done();
});
});
it('should be called on failure', function(done) {
Promise.reject(new Error()).finally(function() {
assert.equal(arguments.length, 0, 'No arguments to onFinally');
done();
});
});
it('should not affect the result', function(done) {
Promise.resolve(3)
.finally(function() {
return 'dummy';
})
.then(function(result) {
assert.equal(result, 3, 'Result was the resolved result');
return Promise.reject(new Error('test'));
})
.finally(function() {
return 'dummy';
})
.catch(function(reason) {
assert(!!reason, 'There was a reason');
assert.equal(reason.message, 'test', 'We catched the correct error');
})
.finally(done);
});
it('should reject with the handler error if handler throws', function(done) {
Promise.reject(new Error('test2'))
.finally(function() {
throw new Error('test3');
})
.catch(function(reason) {
assert.equal(reason.message, 'test3', 'The handler error was caught');
})
.finally(done);
});
it('should await any promise returned from the callback', function(done) {
var log = [];
Promise.resolve()
.then(function() {
log.push(1);
})
.finally(function() {
return Promise.resolve()
.then(function() {
log.push(2);
})
.then(function() {
log.push(3);
});
})
.then(function() {
log.push(4);
})
.then(function() {
assert.deepEqual(log, [1, 2, 3, 4], 'Correct order of promise chain');
})
.catch(function(err) {
assert(false, err);
})
.finally(done);
});
}
describe('Promise.prototype.finally', function() {
finallyTests(Promise);
});
describe('Promise.prototype.finally polyfill', function() {
var NativePromise = (typeof window !== 'undefined' ? window : global)
.Promise;
// Skip tests if Native Promise doesn't exist
if (!NativePromise) {
return;
}
var originalFinally = null;
beforeEach(function() {
originalFinally = NativePromise.prototype.finally;
NativePromise.prototype.finally = Promise.prototype.finally;
});
beforeEach(function() {
if (originalFinally) {
NativePromise.prototype.finally = originalFinally;
}
});
finallyTests(NativePromise);
});
describe('Promise.all', function() {
it('throws on implicit undefined', function() {
return Promise.all().then(
function() {
assert.fail();
},
function(error) {
assert.ok(error instanceof Error);
}
);
});
it('throws on explicit undefined', function() {
return Promise.all(undefined).then(
function() {
assert.fail();
},
function(error) {
assert.ok(error instanceof Error);
}
);
});
it('throws on null', function() {
return Promise.all(null).then(
function() {
assert.fail();
},
function(error) {
assert.ok(error instanceof Error);
}
);
});
it('throws on 0', function() {
return Promise.all(0).then(
function() {
assert.fail();
},
function(error) {
assert.ok(error instanceof Error);
}
);
});
it('throws on false', function() {
return Promise.all(false).then(
function() {
assert.fail();
},
function(error) {
assert.ok(error instanceof Error);
}
);
});
it('throws on a number', function() {
return Promise.all().then(
function() {
assert.fail(20);
},
function(error) {
assert.ok(error instanceof Error);
}
);
});
it('throws on a boolean', function() {
return Promise.all(true).then(
function() {
assert.fail();
},
function(error) {
assert.ok(error instanceof Error);
}
);
});
it('throws on an object', function() {
return Promise.all({ test: 'object' }).then(
function() {
assert.fail();
},
function(error) {
assert.ok(error instanceof Error);
}
);
});
});
});