зеркало из https://github.com/mozilla/gecko-dev.git
176 строки
5.2 KiB
JavaScript
176 строки
5.2 KiB
JavaScript
/*
|
|
* This file is meant to provide common infrastructure for several consumers.
|
|
* The consumer is expected to define the following things:
|
|
*
|
|
* 1) An verifyPromiseGlobal function which does whatever test the consumer
|
|
* wants.
|
|
* 2) An isXrayArgumentTest global boolean, because some of these tests act
|
|
* differenly based on that boolean.
|
|
* 3) A function named getPromise. This function is given a global object and a
|
|
* single argument to use for getting the promise. The getPromise function
|
|
* is expected to trigger the canonical Promise.resolve for the given global
|
|
* with the given argument in some way that depends on the test, and return
|
|
* the result.
|
|
* 4) A subframe (frames[0]) which can be used as a second global for creating
|
|
* promises.
|
|
*/
|
|
|
|
/* global verifyPromiseGlobal, getPromise, isXrayArgumentTest */
|
|
|
|
var label = "parent";
|
|
|
|
function passBasicPromise() {
|
|
var p1 = Promise.resolve();
|
|
verifyPromiseGlobal(p1, window, "Promise.resolve return value 1");
|
|
var p2 = getPromise(window, p1);
|
|
is(p1, p2, "Basic promise should just pass on through");
|
|
return p2;
|
|
}
|
|
|
|
function passPrimitive(global) {
|
|
var p = getPromise(global, 5);
|
|
verifyPromiseGlobal(p, global, "Promise wrapping primitive");
|
|
return p.then(function(arg) {
|
|
is(arg, 5, "Should have the arg we passed in");
|
|
});
|
|
}
|
|
|
|
function passThenable(global) {
|
|
var called = false;
|
|
var thenable = {
|
|
then(f) {
|
|
called = true;
|
|
f(7);
|
|
},
|
|
};
|
|
var p = getPromise(global, thenable);
|
|
verifyPromiseGlobal(p, global, "Promise wrapping thenable");
|
|
return p.then(function(arg) {
|
|
ok(called, "Thenable should have been called");
|
|
is(arg, 7, "Should have the arg our thenable passed in");
|
|
});
|
|
}
|
|
|
|
function passWrongPromiseWithMatchingConstructor() {
|
|
var p1 = Promise.resolve();
|
|
verifyPromiseGlobal(p1, window, "Promise.resolve() return value 2");
|
|
p1.constructor = frames[0].Promise;
|
|
var p2 = getPromise(frames[0], p1);
|
|
// The behavior here will depend on whether we're touching frames[0] via Xrays
|
|
// or not. If we are not, the current compartment while getting our promise
|
|
// will be that of frames[0]. If we are, it will be our window's compartment.
|
|
if (isXrayArgumentTest) {
|
|
isnot(
|
|
p1,
|
|
p2,
|
|
"Should have wrapped the Promise in a new promise, because its constructor is not matching the current-compartment Promise constructor"
|
|
);
|
|
verifyPromiseGlobal(
|
|
p2,
|
|
window,
|
|
"Promise wrapping xrayed promise with therefore non-matching constructor"
|
|
);
|
|
} else {
|
|
is(
|
|
p1,
|
|
p2,
|
|
"Should have left the Promise alone because its constructor matched"
|
|
);
|
|
}
|
|
return p2;
|
|
}
|
|
|
|
function passCorrectPromiseWithMismatchedConstructor() {
|
|
var p1 = Promise.resolve(9);
|
|
verifyPromiseGlobal(p1, window, "Promise.resolve() return value 3");
|
|
p1.constructor = frames[0].Promise;
|
|
var p2 = getPromise(window, p1);
|
|
isnot(
|
|
p1,
|
|
p2,
|
|
"Should have wrapped promise in a new promise, since its .constructor was wrong"
|
|
);
|
|
verifyPromiseGlobal(
|
|
p2,
|
|
window,
|
|
"Promise wrapping passed-in promise with mismatched constructor"
|
|
);
|
|
return p2.then(function(arg) {
|
|
is(arg, 9, "Should have propagated along our resolution value");
|
|
});
|
|
}
|
|
|
|
function passPromiseToOtherGlobal() {
|
|
var p1 = Promise.resolve();
|
|
verifyPromiseGlobal(p1, window, "Promise.resolve() return value 4");
|
|
var p2 = getPromise(frames[0], p1);
|
|
// The behavior here will depend on whether we're touching frames[0] via Xrays
|
|
// or not. If we are not, the current compartment while getting our promise
|
|
// will be that of frames[0]. If we are, it will be our window's compartment.
|
|
if (isXrayArgumentTest) {
|
|
is(
|
|
p1,
|
|
p2,
|
|
"Should have left the Promise alone, because its constructor matches the current compartment's constructor"
|
|
);
|
|
} else {
|
|
isnot(
|
|
p1,
|
|
p2,
|
|
"Should have wrapped promise in a promise from the other global"
|
|
);
|
|
verifyPromiseGlobal(
|
|
p2,
|
|
frames[0],
|
|
"Promise wrapping passed-in basic promise"
|
|
);
|
|
}
|
|
return p2;
|
|
}
|
|
|
|
function passPromiseSubclass() {
|
|
class PromiseSubclass extends Promise {
|
|
constructor(func) {
|
|
super(func);
|
|
}
|
|
}
|
|
|
|
var p1 = PromiseSubclass.resolve(11);
|
|
verifyPromiseGlobal(p1, window, "PromiseSubclass.resolve() return value");
|
|
var p2 = getPromise(window, p1);
|
|
isnot(p1, p2, "Should have wrapped promise subclass in a new promise");
|
|
verifyPromiseGlobal(
|
|
p2,
|
|
window,
|
|
"Promise wrapping passed-in promise subclass"
|
|
);
|
|
return p2.then(function(arg) {
|
|
is(
|
|
arg,
|
|
11,
|
|
"Should have propagated along our resolution value from subclass"
|
|
);
|
|
});
|
|
}
|
|
|
|
function runPromiseArgumentTests(finishFunc) {
|
|
Promise.resolve()
|
|
.then(passBasicPromise)
|
|
.then(passPrimitive.bind(undefined, window))
|
|
.then(passPrimitive.bind(undefined, frames[0]))
|
|
.then(passThenable.bind(undefined, window))
|
|
.then(passThenable.bind(undefined, frames[0]))
|
|
.then(passWrongPromiseWithMatchingConstructor)
|
|
.then(passCorrectPromiseWithMismatchedConstructor)
|
|
.then(passPromiseToOtherGlobal)
|
|
.then(passPromiseSubclass)
|
|
.then(finishFunc)
|
|
.catch(function(e) {
|
|
ok(
|
|
false,
|
|
`Exception thrown: ${e}@${location.pathname}:${e.lineNumber}:${e.columnNumber}`
|
|
);
|
|
finishFunc();
|
|
});
|
|
}
|