37 lines
1.4 KiB
JavaScript
37 lines
1.4 KiB
JavaScript
|
describe('Evil promises should not be able to break invariants', function () {
|
||
|
'use strict';
|
||
|
|
||
|
specify('resolving to a promise that calls onFulfilled twice', function (done) {
|
||
|
// note that we have to create a trivial subclass, as otherwise the
|
||
|
// Promise.resolve(evilPromise) is just the identity function.
|
||
|
// (And in fact, most native Promise implementations use a private
|
||
|
// [[PromiseConstructor]] field in `Promise.resolve` which can't be
|
||
|
// easily patched in an ES5 engine, so instead of
|
||
|
// `Promise.resolve(evilPromise)` we'll use
|
||
|
// `new Promise(function(r){r(evilPromise);})` below.)
|
||
|
var EvilPromise = function (executor) {
|
||
|
var self = new Promise(executor);
|
||
|
Object.setPrototypeOf(self, EvilPromise.prototype);
|
||
|
return self;
|
||
|
};
|
||
|
if (!Object.setPrototypeOf) { return done(); } // skip test if on IE < 11
|
||
|
Object.setPrototypeOf(EvilPromise, Promise);
|
||
|
EvilPromise.prototype = Object.create(Promise.prototype, {
|
||
|
constructor: { value: EvilPromise }
|
||
|
});
|
||
|
|
||
|
var evilPromise = EvilPromise.resolve();
|
||
|
evilPromise.then = function (f) {
|
||
|
f(1);
|
||
|
f(2);
|
||
|
};
|
||
|
|
||
|
var calledAlready = false;
|
||
|
new Promise(function (r) { r(evilPromise); }).then(function (value) {
|
||
|
assert.strictEqual(calledAlready, false);
|
||
|
calledAlready = true;
|
||
|
assert.strictEqual(value, 1);
|
||
|
}).then(done, done);
|
||
|
});
|
||
|
});
|