Update web-platform-tests to revision 78f764c05c229883e87ad135c7153051a66e2851

This commit is contained in:
WPT Sync Bot 2019-03-06 20:32:15 -05:00
parent 55347aa39f
commit bf84a079f9
1983 changed files with 58006 additions and 31437 deletions

View file

@ -13,5 +13,27 @@ test(function() {
assert_equals(document.location, location);
}, "document.location equals window.location");
</script>
test(function() {
var desc1 = Object.getOwnPropertyDescriptor(new Document(), "location");
assert_not_equals(desc1, undefined);
assert_equals(typeof desc1.get, "function");
var desc2 = Object.getOwnPropertyDescriptor(new Document(), "location");
assert_not_equals(desc2, undefined);
assert_equals(typeof desc2.get, "function");
assert_equals(desc1.get, desc2.get);
}, "Attribute getter deduplication");
test(function() {
var desc1 = Object.getOwnPropertyDescriptor(new Document(), "location");
assert_not_equals(desc1, undefined);
assert_equals(typeof desc1.set, "function");
var desc2 = Object.getOwnPropertyDescriptor(new Document(), "location");
assert_not_equals(desc2, undefined);
assert_equals(typeof desc2.set, "function");
assert_equals(desc1.set, desc2.set);
}, "Attribute setter deduplication");
</script>

View file

@ -12,11 +12,17 @@
<iframe id="B"></iframe>
<iframe id="C"></iframe>
<iframe id="D"></iframe>
<iframe id="E"></iframe>
<iframe id="F"></iframe>
<iframe id="G"></iframe>
<iframe id="H"></iframe>
<script>
/*
* Setup boilerplate. This gives us a same-origin window "B" and a cross-origin
* window "C".
* Setup boilerplate. This gives us a same-origin window "B", cross-origin
* windows "C" and "D", initially same-origin but then changing document.domain
* windows "E" and "F", and not-same-site (also cross-origin, of course) windows
* "G" and "H".
*/
var host_info = get_host_info();
@ -26,9 +32,29 @@ pathWithThen = location.pathname.substring(0, location.pathname.lastIndexOf('/')
var B = document.getElementById('B').contentWindow;
var C = document.getElementById('C').contentWindow;
var D = document.getElementById('D').contentWindow;
var E = document.getElementById('E').contentWindow;
var F = document.getElementById('F').contentWindow;
var G = document.getElementById('G').contentWindow;
var H = document.getElementById('H').contentWindow;
B.frameElement.uriToLoad = path;
C.frameElement.uriToLoad = get_host_info().HTTP_REMOTE_ORIGIN + path;
D.frameElement.uriToLoad = get_host_info().HTTP_REMOTE_ORIGIN + pathWithThen;
E.frameElement.uriToLoad = path + "?setdomain";
F.frameElement.uriToLoad = pathWithThen + "?setdomain";
G.frameElement.uriToLoad = get_host_info().HTTP_NOTSAMESITE_ORIGIN + path;
H.frameElement.uriToLoad = get_host_info().HTTP_NOTSAMESITE_ORIGIN + pathWithThen;
function winName(win) {
var iframes = document.getElementsByTagName('iframe');
iframes.find = Array.prototype.find;
var found = iframes.find(function (ifr) {
return ifr.contentWindow == win;
});
if (found) {
return found.id;
}
return "UNKNOWN";
}
function reloadSubframes(cb) {
var iframes = document.getElementsByTagName('iframe');
@ -48,24 +74,59 @@ function isObject(x) { return Object(x) === x; }
* up throwing when it tries to format a message involving a cross-origin object.
*/
/*
* List of tests. Each test is actually a pair: an array of tests to run and a
* boolean for whether these are promise tests. We reload all the subframes in
* between running each toplevel test. This is done to avoid having to reload
* all the subframes for every single test, which is overkill: some of these
* tests are known to touch only one subframe. And doing it makes the test
* really slow.
*/
var testList = [];
function addTest(func, desc) { testList.push({func, desc, promiseTest: false}); }
function addPromiseTest(func, desc) { testList.push({func, desc, promiseTest: true}); }
function addTest(func, desc) {
testList.push(
{tests: [
{func: func.bind(null, C),
desc: desc + " (cross-origin)"},
{func: func.bind(null, E),
desc: desc + " (same-origin + document.domain)"},
{func: func.bind(null, G),
desc: desc + " (cross-site)"}],
promiseTest: false});
}
/**
* A similar helper, but for the subframes that load frame-with-then.html
*/
function addThenTest(func, desc) {
testList.push(
{tests: [
{func: func.bind(null, D),
desc: desc + " (cross-origin)"},
{func: func.bind(null, F),
desc: desc + " (same-origin + document.domain)"},
{func: func.bind(null, H),
desc: desc + " (cross-site)"}],
promiseTest: false});
}
function addPromiseTest(func, desc) {
testList.push({tests:[{func, desc}], promiseTest: true}); }
/*
* Basic sanity testing.
*/
addTest(function() {
addTest(function(win) {
// Note: we do not check location.host as its default port semantics are hard to reflect statically
assert_equals(location.hostname, host_info.ORIGINAL_HOST, 'Need to run the top-level test from domain ' + host_info.ORIGINAL_HOST);
assert_equals(get_port(location), host_info.HTTP_PORT, 'Need to run the top-level test from port ' + host_info.HTTP_PORT);
assert_equals(B.parent, window, "window.parent works same-origin");
assert_equals(C.parent, window, "window.parent works cross-origin");
assert_equals(win.parent, window, "window.parent works cross-origin");
assert_equals(B.location.pathname, path, "location.href works same-origin");
assert_throws("SecurityError", function() { C.location.pathname; }, "location.pathname throws cross-origin");
assert_throws("SecurityError", function() { win.location.pathname; }, "location.pathname throws cross-origin");
assert_equals(B.frames, 'override', "Overrides visible in the same-origin case");
assert_equals(C.frames, C, "Overrides invisible in the cross-origin case");
assert_equals(win.frames, win, "Overrides invisible in the cross-origin case");
}, "Basic sanity-checking");
/*
@ -85,42 +146,42 @@ var whitelistedSymbols = [Symbol.toStringTag, Symbol.hasInstance,
Symbol.isConcatSpreadable];
var whitelistedWindowProps = whitelistedWindowPropNames.concat(whitelistedSymbols);
addTest(function() {
addTest(function(win) {
for (var prop in window) {
if (whitelistedWindowProps.indexOf(prop) != -1) {
C[prop]; // Shouldn't throw.
Object.getOwnPropertyDescriptor(C, prop); // Shouldn't throw.
assert_true(Object.prototype.hasOwnProperty.call(C, prop), "hasOwnProperty for " + String(prop));
win[prop]; // Shouldn't throw.
Object.getOwnPropertyDescriptor(win, prop); // Shouldn't throw.
assert_true(Object.prototype.hasOwnProperty.call(win, prop), "hasOwnProperty for " + String(prop));
} else {
assert_throws("SecurityError", function() { C[prop]; }, "Should throw when accessing " + String(prop) + " on Window");
assert_throws("SecurityError", function() { Object.getOwnPropertyDescriptor(C, prop); },
assert_throws("SecurityError", function() { win[prop]; }, "Should throw when accessing " + String(prop) + " on Window");
assert_throws("SecurityError", function() { Object.getOwnPropertyDescriptor(win, prop); },
"Should throw when accessing property descriptor for " + prop + " on Window");
assert_throws("SecurityError", function() { Object.prototype.hasOwnProperty.call(C, prop); },
assert_throws("SecurityError", function() { Object.prototype.hasOwnProperty.call(win, prop); },
"Should throw when invoking hasOwnProperty for " + prop + " on Window");
}
if (prop != 'location')
assert_throws("SecurityError", function() { C[prop] = undefined; }, "Should throw when writing to " + prop + " on Window");
assert_throws("SecurityError", function() { win[prop] = undefined; }, "Should throw when writing to " + prop + " on Window");
}
for (var prop in location) {
if (prop == 'replace') {
C.location[prop]; // Shouldn't throw.
Object.getOwnPropertyDescriptor(C.location, prop); // Shouldn't throw.
assert_true(Object.prototype.hasOwnProperty.call(C.location, prop), "hasOwnProperty for " + prop);
assert_throws("SecurityError", function() { C.location[prop] = undefined; }, "Should throw when writing to " + prop + " on Location");
win.location[prop]; // Shouldn't throw.
Object.getOwnPropertyDescriptor(win.location, prop); // Shouldn't throw.
assert_true(Object.prototype.hasOwnProperty.call(win.location, prop), "hasOwnProperty for " + prop);
assert_throws("SecurityError", function() { win.location[prop] = undefined; }, "Should throw when writing to " + prop + " on Location");
}
else if (prop == 'href') {
Object.getOwnPropertyDescriptor(C.location, prop); // Shouldn't throw.
assert_true(Object.prototype.hasOwnProperty.call(C.location, prop), "hasOwnProperty for " + prop);
assert_throws("SecurityError", function() { C.location[prop] },
Object.getOwnPropertyDescriptor(win.location, prop); // Shouldn't throw.
assert_true(Object.prototype.hasOwnProperty.call(win.location, prop), "hasOwnProperty for " + prop);
assert_throws("SecurityError", function() { win.location[prop] },
"Should throw reading href on Location");
}
else {
assert_throws("SecurityError", function() { C.location[prop]; }, "Should throw when accessing " + prop + " on Location");
assert_throws("SecurityError", function() { Object.getOwnPropertyDescriptor(C.location, prop); },
assert_throws("SecurityError", function() { win.location[prop]; }, "Should throw when accessing " + prop + " on Location");
assert_throws("SecurityError", function() { Object.getOwnPropertyDescriptor(win.location, prop); },
"Should throw when accessing property descriptor for " + prop + " on Location");
assert_throws("SecurityError", function() { Object.prototype.hasOwnProperty.call(C.location, prop); },
assert_throws("SecurityError", function() { Object.prototype.hasOwnProperty.call(win.location, prop); },
"Should throw when invoking hasOwnProperty for " + prop + " on Location");
assert_throws("SecurityError", function() { C.location[prop] = undefined; }, "Should throw when writing to " + prop + " on Location");
assert_throws("SecurityError", function() { win.location[prop] = undefined; }, "Should throw when writing to " + prop + " on Location");
}
}
}, "Only whitelisted properties are accessible cross-origin");
@ -132,45 +193,45 @@ addTest(function() {
/*
* [[GetPrototypeOf]]
*/
addTest(function() {
assert_equals(Object.getPrototypeOf(C), null, "cross-origin Window proto is null");
assert_equals(Object.getPrototypeOf(C.location), null, "cross-origin Location proto is null (__proto__)");
addTest(function(win) {
assert_equals(Object.getPrototypeOf(win), null, "cross-origin Window proto is null");
assert_equals(Object.getPrototypeOf(win.location), null, "cross-origin Location proto is null (__proto__)");
var protoGetter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').get;
assert_equals(protoGetter.call(C), null, "cross-origin Window proto is null");
assert_equals(protoGetter.call(C.location), null, "cross-origin Location proto is null (__proto__)");
assert_throws("SecurityError", function() { C.__proto__; }, "__proto__ property not available cross-origin");
assert_throws("SecurityError", function() { C.location.__proto__; }, "__proto__ property not available cross-origin");
assert_equals(protoGetter.call(win), null, "cross-origin Window proto is null");
assert_equals(protoGetter.call(win.location), null, "cross-origin Location proto is null (__proto__)");
assert_throws("SecurityError", function() { win.__proto__; }, "__proto__ property not available cross-origin");
assert_throws("SecurityError", function() { win.location.__proto__; }, "__proto__ property not available cross-origin");
}, "[[GetPrototypeOf]] should return null");
/*
* [[SetPrototypeOf]]
*/
addTest(function() {
assert_throws("SecurityError", function() { C.__proto__ = new Object(); }, "proto set on cross-origin Window");
assert_throws("SecurityError", function() { C.location.__proto__ = new Object(); }, "proto set on cross-origin Location");
addTest(function(win) {
assert_throws("SecurityError", function() { win.__proto__ = new Object(); }, "proto set on cross-origin Window");
assert_throws("SecurityError", function() { win.location.__proto__ = new Object(); }, "proto set on cross-origin Location");
var setters = [Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set];
if (Object.setPrototypeOf)
setters.push(function(p) { Object.setPrototypeOf(this, p); });
setters.forEach(function(protoSetter) {
assert_throws(new TypeError, function() { protoSetter.call(C, new Object()); }, "proto setter |call| on cross-origin Window");
assert_throws(new TypeError, function() { protoSetter.call(C.location, new Object()); }, "proto setter |call| on cross-origin Location");
assert_throws(new TypeError, function() { protoSetter.call(win, new Object()); }, "proto setter |call| on cross-origin Window");
assert_throws(new TypeError, function() { protoSetter.call(win.location, new Object()); }, "proto setter |call| on cross-origin Location");
});
// Hack to avoid "duplicate test name" harness issues.
setters.forEach(function(protoSetter) {
test(function() { protoSetter.call(C, null); },
"proto setter |call| on cross-origin Window with null (" + protoSetter + ")");
test(function() { protoSetter.call(C.location, null); },
"proto setter |call| on cross-origin Location with null (" + protoSetter + ")");
test(function() { protoSetter.call(win, null); },
"proto setter |call| on cross-origin Window with null (" + protoSetter + ", " + winName(win) + ")");
test(function() { protoSetter.call(win.location, null); },
"proto setter |call| on cross-origin Location with null (" + protoSetter + ", " + winName(win) + ")");
});
if (Reflect.setPrototypeOf) {
assert_false(Reflect.setPrototypeOf(C, new Object()),
assert_false(Reflect.setPrototypeOf(win, new Object()),
"Reflect.setPrototypeOf on cross-origin Window");
assert_true(Reflect.setPrototypeOf(C, null),
assert_true(Reflect.setPrototypeOf(win, null),
"Reflect.setPrototypeOf on cross-origin Window with null");
assert_false(Reflect.setPrototypeOf(C.location, new Object()),
assert_false(Reflect.setPrototypeOf(win.location, new Object()),
"Reflect.setPrototypeOf on cross-origin Location");
assert_true(Reflect.setPrototypeOf(C.location, null),
assert_true(Reflect.setPrototypeOf(win.location, null),
"Reflect.setPrototypeOf on cross-origin Location with null");
}
}, "[[SetPrototypeOf]] should return false");
@ -178,18 +239,18 @@ addTest(function() {
/*
* [[IsExtensible]]
*/
addTest(function() {
assert_true(Object.isExtensible(C), "cross-origin Window should be extensible");
assert_true(Object.isExtensible(C.location), "cross-origin Location should be extensible");
addTest(function(win) {
assert_true(Object.isExtensible(win), "cross-origin Window should be extensible");
assert_true(Object.isExtensible(win.location), "cross-origin Location should be extensible");
}, "[[IsExtensible]] should return true for cross-origin objects");
/*
* [[PreventExtensions]]
*/
addTest(function() {
assert_throws(new TypeError, function() { Object.preventExtensions(C) },
addTest(function(win) {
assert_throws(new TypeError, function() { Object.preventExtensions(win) },
"preventExtensions on cross-origin Window should throw");
assert_throws(new TypeError, function() { Object.preventExtensions(C.location) },
assert_throws(new TypeError, function() { Object.preventExtensions(win.location) },
"preventExtensions on cross-origin Location should throw");
}, "[[PreventExtensions]] should throw for cross-origin objects");
@ -197,11 +258,11 @@ addTest(function() {
* [[GetOwnProperty]]
*/
addTest(function() {
assert_true(isObject(Object.getOwnPropertyDescriptor(C, 'close')), "C.close is |own|");
assert_true(isObject(Object.getOwnPropertyDescriptor(C, 'top')), "C.top is |own|");
assert_true(isObject(Object.getOwnPropertyDescriptor(C.location, 'href')), "C.location.href is |own|");
assert_true(isObject(Object.getOwnPropertyDescriptor(C.location, 'replace')), "C.location.replace is |own|");
addTest(function(win) {
assert_true(isObject(Object.getOwnPropertyDescriptor(win, 'close')), "win.close is |own|");
assert_true(isObject(Object.getOwnPropertyDescriptor(win, 'top')), "win.top is |own|");
assert_true(isObject(Object.getOwnPropertyDescriptor(win.location, 'href')), "win.location.href is |own|");
assert_true(isObject(Object.getOwnPropertyDescriptor(win.location, 'replace')), "win.location.replace is |own|");
}, "[[GetOwnProperty]] - Properties on cross-origin objects should be reported |own|");
function checkPropertyDescriptor(desc, propName, expectWritable) {
@ -229,52 +290,52 @@ function checkPropertyDescriptor(desc, propName, expectWritable) {
"property descriptor for " + propName + " should " + (expectWritable ? "" : "not ") + "have setter");
}
addTest(function() {
addTest(function(win) {
whitelistedWindowProps.forEach(function(prop) {
var desc = Object.getOwnPropertyDescriptor(C, prop);
var desc = Object.getOwnPropertyDescriptor(win, prop);
checkPropertyDescriptor(desc, prop, prop == 'location');
});
checkPropertyDescriptor(Object.getOwnPropertyDescriptor(C.location, 'replace'), 'replace', false);
checkPropertyDescriptor(Object.getOwnPropertyDescriptor(C.location, 'href'), 'href', true);
assert_equals(typeof Object.getOwnPropertyDescriptor(C.location, 'href').get, 'undefined', "Cross-origin location should have no href getter");
checkPropertyDescriptor(Object.getOwnPropertyDescriptor(win.location, 'replace'), 'replace', false);
checkPropertyDescriptor(Object.getOwnPropertyDescriptor(win.location, 'href'), 'href', true);
assert_equals(typeof Object.getOwnPropertyDescriptor(win.location, 'href').get, 'undefined', "Cross-origin location should have no href getter");
whitelistedSymbols.forEach(function(prop) {
var desc = Object.getOwnPropertyDescriptor(C.location, prop);
var desc = Object.getOwnPropertyDescriptor(win.location, prop);
checkPropertyDescriptor(desc, prop, false);
});
}, "[[GetOwnProperty]] - Property descriptors for cross-origin properties should be set up correctly");
addTest(function() {
assert_equals(typeof D.then, "object");
addThenTest(function(win) {
assert_equals(typeof win.then, "object");
}, "[[GetOwnProperty]] - Subframe named 'then' should shadow the default 'then' value");
addTest(function() {
assert_equals(typeof D.close, "function");
assert_equals(typeof D.open, "object");
addThenTest(function(win) {
assert_equals(typeof win.close, "function");
assert_equals(typeof win.open, "object");
}, "[[GetOwnProperty]] - Subframes should be visible cross-origin only if their names don't match the names of cross-origin-exposed IDL properties");
addTest(function() {
assert_equals(typeof Object.getOwnPropertyDescriptor(C, '0').value, "object");
assert_equals(typeof Object.getOwnPropertyDescriptor(C, '1').value, "object");
addTest(function(win) {
assert_equals(typeof Object.getOwnPropertyDescriptor(win, '0').value, "object");
assert_equals(typeof Object.getOwnPropertyDescriptor(win, '1').value, "object");
assert_throws("SecurityError", function() {
Object.getOwnPropertyDescriptor(C, '2');
Object.getOwnPropertyDescriptor(win, '2');
});
}, "[[GetOwnProperty]] - Should be able to get a property descriptor for an indexed property only if it corresponds to a child window.");
/*
* [[Delete]]
*/
addTest(function() {
assert_throws("SecurityError", function() { delete C[0]; }, "Can't delete cross-origin indexed property");
assert_throws("SecurityError", function() { delete C[100]; }, "Can't delete cross-origin indexed property");
assert_throws("SecurityError", function() { delete C.location; }, "Can't delete cross-origin property");
assert_throws("SecurityError", function() { delete C.parent; }, "Can't delete cross-origin property");
assert_throws("SecurityError", function() { delete C.length; }, "Can't delete cross-origin property");
assert_throws("SecurityError", function() { delete C.document; }, "Can't delete cross-origin property");
assert_throws("SecurityError", function() { delete C.foopy; }, "Can't delete cross-origin property");
assert_throws("SecurityError", function() { delete C.location.href; }, "Can't delete cross-origin property");
assert_throws("SecurityError", function() { delete C.location.replace; }, "Can't delete cross-origin property");
assert_throws("SecurityError", function() { delete C.location.port; }, "Can't delete cross-origin property");
assert_throws("SecurityError", function() { delete C.location.foopy; }, "Can't delete cross-origin property");
addTest(function(win) {
assert_throws("SecurityError", function() { delete win[0]; }, "Can't delete cross-origin indexed property");
assert_throws("SecurityError", function() { delete win[100]; }, "Can't delete cross-origin indexed property");
assert_throws("SecurityError", function() { delete win.location; }, "Can't delete cross-origin property");
assert_throws("SecurityError", function() { delete win.parent; }, "Can't delete cross-origin property");
assert_throws("SecurityError", function() { delete win.length; }, "Can't delete cross-origin property");
assert_throws("SecurityError", function() { delete win.document; }, "Can't delete cross-origin property");
assert_throws("SecurityError", function() { delete win.foopy; }, "Can't delete cross-origin property");
assert_throws("SecurityError", function() { delete win.location.href; }, "Can't delete cross-origin property");
assert_throws("SecurityError", function() { delete win.location.replace; }, "Can't delete cross-origin property");
assert_throws("SecurityError", function() { delete win.location.port; }, "Can't delete cross-origin property");
assert_throws("SecurityError", function() { delete win.location.foopy; }, "Can't delete cross-origin property");
}, "[[Delete]] Should throw on cross-origin objects");
/*
@ -286,31 +347,31 @@ function checkDefine(obj, prop) {
assert_throws("SecurityError", function() { Object.defineProperty(obj, prop, valueDesc); }, "Can't define cross-origin value property " + prop);
assert_throws("SecurityError", function() { Object.defineProperty(obj, prop, accessorDesc); }, "Can't define cross-origin accessor property " + prop);
}
addTest(function() {
checkDefine(C, 'length');
checkDefine(C, 'parent');
checkDefine(C, 'location');
checkDefine(C, 'document');
checkDefine(C, 'foopy');
checkDefine(C.location, 'href');
checkDefine(C.location, 'replace');
checkDefine(C.location, 'port');
checkDefine(C.location, 'foopy');
addTest(function(win) {
checkDefine(win, 'length');
checkDefine(win, 'parent');
checkDefine(win, 'location');
checkDefine(win, 'document');
checkDefine(win, 'foopy');
checkDefine(win.location, 'href');
checkDefine(win.location, 'replace');
checkDefine(win.location, 'port');
checkDefine(win.location, 'foopy');
}, "[[DefineOwnProperty]] Should throw for cross-origin objects");
/*
* EnumerateObjectProperties (backed by [[OwnPropertyKeys]])
*/
addTest(function() {
addTest(function(win) {
let i = 0;
for (var prop in C) {
for (var prop in win) {
i++;
assert_true(whitelistedWindowIndices.includes(prop), prop + " is not safelisted for a cross-origin Window");
}
assert_equals(i, whitelistedWindowIndices.length, "Enumerate all enumerable safelisted cross-origin Window properties");
i = 0;
for (var prop in C.location) {
for (var prop in win.location) {
i++;
}
assert_equals(i, 0, "There's nothing to enumerate for cross-origin Location properties");
@ -320,30 +381,30 @@ addTest(function() {
* [[OwnPropertyKeys]]
*/
addTest(function() {
assert_array_equals(Object.getOwnPropertyNames(C).sort(),
addTest(function(win) {
assert_array_equals(Object.getOwnPropertyNames(win).sort(),
whitelistedWindowPropNames,
"Object.getOwnPropertyNames() gives the right answer for cross-origin Window");
assert_array_equals(Object.keys(C).sort(),
assert_array_equals(Object.keys(win).sort(),
whitelistedWindowIndices,
"Object.keys() gives the right answer for cross-origin Window");
assert_array_equals(Object.getOwnPropertyNames(C.location).sort(),
assert_array_equals(Object.getOwnPropertyNames(win.location).sort(),
whitelistedLocationPropNames,
"Object.getOwnPropertyNames() gives the right answer for cross-origin Location");
assert_equals(Object.keys(C.location).length, 0,
assert_equals(Object.keys(win.location).length, 0,
"Object.keys() gives the right answer for cross-origin Location");
}, "[[OwnPropertyKeys]] should return all properties from cross-origin objects");
addTest(function() {
assert_array_equals(Object.getOwnPropertySymbols(C), whitelistedSymbols,
addTest(function(win) {
assert_array_equals(Object.getOwnPropertySymbols(win), whitelistedSymbols,
"Object.getOwnPropertySymbols() should return the three symbol-named properties that are exposed on a cross-origin Window");
assert_array_equals(Object.getOwnPropertySymbols(C.location),
assert_array_equals(Object.getOwnPropertySymbols(win.location),
whitelistedSymbols,
"Object.getOwnPropertySymbols() should return the three symbol-named properties that are exposed on a cross-origin Location");
}, "[[OwnPropertyKeys]] should return the right symbol-named properties for cross-origin objects");
addTest(function() {
var allWindowProps = Reflect.ownKeys(C);
addTest(function(win) {
var allWindowProps = Reflect.ownKeys(win);
indexedWindowProps = allWindowProps.slice(0, whitelistedWindowIndices.length);
stringWindowProps = allWindowProps.slice(0, -1 * whitelistedSymbols.length);
symbolWindowProps = allWindowProps.slice(-1 * whitelistedSymbols.length);
@ -358,7 +419,7 @@ addTest(function() {
assert_array_equals(symbolWindowProps, whitelistedSymbols,
"Reflect.ownKeys should end with the cross-origin symbols for a cross-origin Window.");
var allLocationProps = Reflect.ownKeys(C.location);
var allLocationProps = Reflect.ownKeys(win.location);
stringLocationProps = allLocationProps.slice(0, -1 * whitelistedSymbols.length);
symbolLocationProps = allLocationProps.slice(-1 * whitelistedSymbols.length);
assert_array_equals(stringLocationProps.sort(), whitelistedLocationPropNames,
@ -367,20 +428,20 @@ addTest(function() {
"Reflect.ownKeys should end with the cross-origin symbols for a cross-origin Location.")
}, "[[OwnPropertyKeys]] should place the symbols after the property names after the subframe indices");
addTest(function() {
var stringProps = Object.getOwnPropertyNames(D);
addThenTest(function(win) {
var stringProps = Object.getOwnPropertyNames(win);
// Named frames are not exposed via [[OwnPropertyKeys]].
assert_equals(stringProps.indexOf("a"), -1);
assert_equals(stringProps.indexOf("b"), -1);
assert_equals(typeof D.a, "object");
assert_equals(typeof D.b, "object");
assert_equals(typeof win.a, "object");
assert_equals(typeof win.b, "object");
assert_equals(stringProps[stringProps.length - 1], "then");
assert_equals(stringProps.indexOf("then"), stringProps.lastIndexOf("then"));
}, "[[OwnPropertyKeys]] should not reorder where 'then' appears if it's a named subframe, nor add another copy of 'then'");
addTest(function() {
assert_equals(B.eval('parent.C'), C, "A and B observe the same identity for C's Window");
assert_equals(B.eval('parent.C.location'), C.location, "A and B observe the same identity for C's Location");
addTest(function(win) {
assert_equals(B.eval('parent.' + winName(win)), win, "A and B observe the same identity for C's Window");
assert_equals(B.eval('parent.' + winName(win) + '.location'), win.location, "A and B observe the same identity for C's Location");
}, "A and B jointly observe the same identity for cross-origin Window and Location");
function checkFunction(f, proto) {
@ -389,40 +450,40 @@ function checkFunction(f, proto) {
assert_equals(Object.getPrototypeOf(f), proto, f.name + " has the right prototype");
}
addTest(function() {
checkFunction(C.close, Function.prototype);
checkFunction(C.location.replace, Function.prototype);
addTest(function(win) {
checkFunction(win.close, Function.prototype);
checkFunction(win.location.replace, Function.prototype);
}, "Cross-origin functions get local Function.prototype");
addTest(function() {
assert_true(isObject(Object.getOwnPropertyDescriptor(C, 'parent')),
addTest(function(win) {
assert_true(isObject(Object.getOwnPropertyDescriptor(win, 'parent')),
"Need to be able to use Object.getOwnPropertyDescriptor do this test");
checkFunction(Object.getOwnPropertyDescriptor(C, 'parent').get, Function.prototype);
checkFunction(Object.getOwnPropertyDescriptor(C.location, 'href').set, Function.prototype);
checkFunction(Object.getOwnPropertyDescriptor(win, 'parent').get, Function.prototype);
checkFunction(Object.getOwnPropertyDescriptor(win.location, 'href').set, Function.prototype);
}, "Cross-origin Window accessors get local Function.prototype");
addTest(function() {
addTest(function(win) {
checkFunction(close, Function.prototype);
assert_not_equals(close, B.close, 'same-origin Window functions get their own object');
assert_not_equals(close, C.close, 'cross-origin Window functions get their own object');
var close_B = B.eval('parent.C.close');
assert_not_equals(close, win.close, 'cross-origin Window functions get their own object');
var close_B = B.eval('parent.' + winName(win) + '.close');
assert_not_equals(close, close_B, 'close_B is unique when viewed by the parent');
assert_not_equals(close_B, C.close, 'different Window functions per-incumbent script settings object');
assert_not_equals(close_B, win.close, 'different Window functions per-incumbent script settings object');
checkFunction(close_B, B.Function.prototype);
checkFunction(location.replace, Function.prototype);
assert_not_equals(location.replace, C.location.replace, "cross-origin Location functions get their own object");
var replace_B = B.eval('parent.C.location.replace');
assert_not_equals(replace_B, C.location.replace, 'different Location functions per-incumbent script settings object');
assert_not_equals(location.replace, win.location.replace, "cross-origin Location functions get their own object");
var replace_B = B.eval('parent.' + winName(win) + '.location.replace');
assert_not_equals(replace_B, win.location.replace, 'different Location functions per-incumbent script settings object');
checkFunction(replace_B, B.Function.prototype);
}, "Same-origin observers get different functions for cross-origin objects");
addTest(function() {
assert_true(isObject(Object.getOwnPropertyDescriptor(C, 'parent')),
addTest(function(win) {
assert_true(isObject(Object.getOwnPropertyDescriptor(win, 'parent')),
"Need to be able to use Object.getOwnPropertyDescriptor do this test");
var get_self_parent = Object.getOwnPropertyDescriptor(window, 'parent').get;
var get_parent_A = Object.getOwnPropertyDescriptor(C, 'parent').get;
var get_parent_B = B.eval('Object.getOwnPropertyDescriptor(parent.C, "parent").get');
var get_parent_A = Object.getOwnPropertyDescriptor(win, 'parent').get;
var get_parent_B = B.eval('Object.getOwnPropertyDescriptor(parent.' + winName(win) + ', "parent").get');
assert_not_equals(get_self_parent, get_parent_A, 'different Window accessors per-incumbent script settings object');
assert_not_equals(get_parent_A, get_parent_B, 'different Window accessors per-incumbent script settings object');
checkFunction(get_self_parent, Function.prototype);
@ -430,10 +491,10 @@ addTest(function() {
checkFunction(get_parent_B, B.Function.prototype);
}, "Same-origin observers get different accessors for cross-origin Window");
addTest(function() {
addTest(function(win) {
var set_self_href = Object.getOwnPropertyDescriptor(window.location, 'href').set;
var set_href_A = Object.getOwnPropertyDescriptor(C.location, 'href').set;
var set_href_B = B.eval('Object.getOwnPropertyDescriptor(parent.C.location, "href").set');
var set_href_A = Object.getOwnPropertyDescriptor(win.location, 'href').set;
var set_href_B = B.eval('Object.getOwnPropertyDescriptor(parent.' + winName(win) + '.location, "href").set');
assert_not_equals(set_self_href, set_href_A, 'different Location accessors per-incumbent script settings object');
assert_not_equals(set_href_A, set_href_B, 'different Location accessors per-incumbent script settings object');
checkFunction(set_self_href, Function.prototype);
@ -441,28 +502,64 @@ addTest(function() {
checkFunction(set_href_B, B.Function.prototype);
}, "Same-origin observers get different accessors for cross-origin Location");
addTest(function() {
assert_equals({}.toString.call(C), "[object Object]");
assert_equals({}.toString.call(C.location), "[object Object]");
addTest(function(win) {
assert_equals({}.toString.call(win), "[object Object]");
assert_equals({}.toString.call(win.location), "[object Object]");
}, "{}.toString.call() does the right thing on cross-origin objects");
addPromiseTest(function() {
return Promise.resolve(C).then((arg) => {
assert_equals(arg, C);
});
}, "Resolving a promise with a cross-origin window without a 'then' subframe should work.");
}, "Resolving a promise with a cross-origin window without a 'then' subframe should work (cross-origin).");
addPromiseTest(function() {
return Promise.resolve(E).then((arg) => {
assert_equals(arg, E);
});
}, "Resolving a promise with a cross-origin window without a 'then' subframe should work (same-origin + document.domain).");
addPromiseTest(function() {
return Promise.resolve(G).then((arg) => {
assert_equals(arg, G);
});
}, "Resolving a promise with a cross-origin window without a 'then' subframe should work (cross-site).");
addPromiseTest(function() {
return Promise.resolve(D).then((arg) => {
assert_equals(arg, D);
});
}, "Resolving a promise with a cross-origin window with a 'then' subframe should work.");
}, "Resolving a promise with a cross-origin window with a 'then' subframe should work (cross-origin).");
addPromiseTest(function() {
return Promise.resolve(F).then((arg) => {
assert_equals(arg, F);
});
}, "Resolving a promise with a cross-origin window with a 'then' subframe should work (same-origin + document.domain).");
addPromiseTest(function() {
return Promise.resolve(H).then((arg) => {
assert_equals(arg, H);
});
}, "Resolving a promise with a cross-origin window with a 'then' subframe should work (cross-site).");
addPromiseTest(function() {
return Promise.resolve(D.location).then((arg) => {
assert_equals(arg, D.location);
});
}, "Resolving a promise with a cross-origin location should work.");
}, "Resolving a promise with a cross-origin location should work (cross-origin).");
addPromiseTest(function() {
return Promise.resolve(F.location).then((arg) => {
assert_equals(arg, F.location);
});
}, "Resolving a promise with a cross-origin location should work (same-origin + document.domain).");
addPromiseTest(function() {
return Promise.resolve(H.location).then((arg) => {
assert_equals(arg, H.location);
});
}, "Resolving a promise with a cross-origin location should work (cross-site).");
// We do a fresh load of the subframes for each test to minimize side-effects.
// It would be nice to reload ourselves as well, but we can't do that without
@ -478,9 +575,14 @@ function testDone() {
function runNextTest() {
var entry = testList.shift();
if (entry.promiseTest) {
promise_test(() => entry.func().finally(testDone), entry.desc);
test(function() {
assert_equals(entry.tests.length, 1, "We can't handle this yet");
});
promise_test(() => entry.tests[0].func().finally(testDone), entry.tests[0].desc);
} else {
test(entry.func, entry.desc);
for (t of entry.tests) {
test(t.func, t.desc);
}
testDone();
}
}

View file

@ -1,5 +1,10 @@
<!doctype html>
<html>
<script>
if (location.search == "?setdomain") {
document.domain = document.domain;
}
</script>
<body>
<!--- Some frames to test ordering -->
<iframe name="a"></iframe>

View file

@ -2,6 +2,10 @@
<html>
<head>
<script>
if (location.search == "?setdomain") {
document.domain = document.domain;
}
// Override the |frames| property to test that such overrides are
// properly ignored cross-origin.
window.frames = "override";

View file

@ -5,158 +5,7 @@
<link rel="help" href="https://html.spec.whatwg.org/multipage/#apis-for-creating-and-navigating-browsing-contexts-by-name">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/tokenization-noopener-noreferrer.js"></script>
<script>
var windowURL = 'resources/close-self.html';
// Tests for how windows features are tokenized into 'name', 'value'
// window features separators are ASCII whitespace, '=' and ','
test (t => {
// Tokenizing `name`: initial window features separators are ignored
// Each of these variants should tokenize to ('noopener', '')
var featureVariants = [
' noopener',
'=noopener',
',,noopener',
',=, noopener',
'\n=noopener=',
'\tnoopener',
'\r,,,=noopener',
'\u000Cnoopener'
];
featureVariants.forEach(feature => {
var win = window.open(windowURL, '', feature);
assert_equals(win, null, `"${feature}" should activate feature "noopener"`);
});
}, 'tokenization should skip window features separators before `name`');
test (t => {
// Tokenizing `name`: lowercase conversion
// Each of these variants should tokenize as feature ('noopener', '')
// except where indicated
// Note also that `value` is lowercased during tokenization
var featureVariants = [
'NOOPENER',
'noOpenER',
' NOopener',
'=NOOPENER',
'noopener=1',
'NOOPENER=1',
'NOOPENER=yes',
'noopener=YES',
];
featureVariants.forEach(feature => {
var win = window.open(windowURL, '', feature);
assert_equals(win, null, `"${feature}" should activate feature "noopener"`);
});
}, 'feature `name` should be converted to ASCII lowercase');
test (t => {
// After `name` has been collected, ignore any window features separators until '='
// except ',' OR a non-window-features-separator — break in those cases
// i.e. ignore whitespace until '=' unless a ',' is encountered first
// Each of these variants should tokenize as feature ('noopener', '')
var featureVariants = [
'noopener',
' noopener\r',
'noopener\n =',
'noopener,',
'noopener =,',
', noopener =',
'noopener,=',
'noopener foo', // => ('noopener', ''), ('foo', '')
'foo noopener=1', // => ('foo', ''), ('noopener', '1')
'foo=\u000Cbar\u000Cnoopener' // => ('foo', 'bar'), ('noopener', '')
];
featureVariants.forEach(feature => {
var win = window.open(windowURL, '', feature);
assert_equals(win, null, `"${feature}" should activate feature "noopener"`);
});
}, 'after `name`, tokenization should skip window features separators that are not "=" or ","');
test (t => {
// After initial '=', tokenizing should ignore all separators except ','
// before collecting `value`
// Each of these variants should tokenize as feature ('noopener', '')
// Except where indicated
var featureVariants = [
'noopener= yes', // => ('noopener', 'yes')
'noopener==,',
'noopener=\n ,',
'noopener = \t ,',
'noopener\n=\r 1,', // => ('noopener', '1')
'noopener=,yes', // => ('noopener'), ('yes')
'noopener= yes=,', // => ('noopener', 'yes')
'noopener = \u000Cyes' // => ('noopener', 'yes')
];
featureVariants.forEach(feature => {
var win = window.open(windowURL, '', feature);
assert_equals(win, null, `"${feature}" should activate feature "noopener"`);
});
}, 'Tokenizing should ignore window feature separators except "," after initial "=" and before value');
test (t => {
// Tokenizing `value` should collect any non-separator code points until first separator
var featureVariants = [
'noopener=1', // => ('noopener', 'noopener')
'noopener=yes', // => ('noopener', 'yes')
'noopener = yes ,', // => ('noopener', 'yes')
'noopener=\nyes ,', // => ('noopener', 'yes')
'noopener=yes yes', // => ('noopener', 'yes'), ('yes', '')
'noopener=yes\ts', // => ('noopener', 'yes'), ('s', '')
'noopener==', // => ('noopener', '')
'noopener=1\n,', // => ('noopener', '1')
'==noopener===', // => ('noopener', '')
'noopener==\u000C' // => ('noopener', '')
];
featureVariants.forEach(feature => {
var win = window.open(windowURL, '', feature);
assert_equals(win, null, `"${feature}" should set "noopener"`);
});
}, 'Tokenizing should read characters until first window feature separator as `value`');
test (t => {
var featureVariants = [
'noopener=1',
'noopener=2',
'noopener=12345',
'noopener=1.5',
'noopener=-1',
];
featureVariants.forEach(feature => {
var win = window.open(windowURL, '', feature);
assert_equals(win, null, `"${feature}" should activate feature "noopener"`);
});
}, 'Integer values other than 0 should activate the feature');
test (t => {
var featureVariants = [
'noopener=0',
'noopener=0.5',
'noopener=error',
];
featureVariants.forEach(feature => {
var win = window.open(windowURL, '', feature);
assert_not_equals(win, null, `"${feature}" should NOT activate feature "noopener"`);
});
}, 'Integer value of 0 should not activate the feature');
test (t => {
var invalidFeatureVariants = [
'-noopener', // => ('-noopener', '')
'NOOPENERRRR', // => ('noopenerrr', '')
'noOpenErR', // => ('noopenerr', '')
'no_opener', // => ('no_opener', '')
' no opener', // => ('no', ''), ('opener', '')
'no\nopener', // => ('no', ''), ('opener', '')
'no,opener', // => ('no', ''), ('opener', '')
'\0noopener', // => ('\0noopener', '')
'noopener\u0000=yes', // => ('noopener\0', 'yes')
'foo=\u000Cnoopener' // => ('foo', 'noopener')
];
invalidFeatureVariants.forEach(feature => {
var win = window.open(windowURL, '', feature);
assert_not_equals(win, null, `"${feature}" should NOT activate feature "noopener"`);
});
}, 'invalid feature names should not tokenize as "noopener"');
booleanTests("noopener");
</script>

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>HTML: window.open `features`: tokenization -- `noreferrer`</title>
<meta name=timeout content=long>
<link rel="help" href="https://html.spec.whatwg.org/multipage/#apis-for-creating-and-navigating-browsing-contexts-by-name">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/tokenization-noopener-noreferrer.js"></script>
<script>
booleanTests("noreferrer");
</script>

View file

@ -0,0 +1,152 @@
function booleanTests(feature) {
const windowURL = 'resources/close-self.html';
// Tests for how windows features are tokenized into 'name', 'value'
// window features separators are ASCII whitespace, '=' and ','
const featureUpper = feature.toUpperCase(),
featureSplitBegin = feature.slice(0, 2),
featureSplitEnd = feature.slice(2),
featureMixedCase = featureSplitBegin.toUpperCase() + featureSplitEnd;
featureMixedCase2 = featureSplitBegin + featureSplitEnd.toUpperCase();
test (t => {
// Tokenizing `name`: initial window features separators are ignored
// Each of these variants should tokenize to (`${feature}`, '')
[
` ${feature}`,
`=${feature}`,
`,,${feature}`,
`,=, ${feature}`,
`\n=${feature}=`,
`\t${feature}`,
`\r,,,=${feature}`,
`\u000C${feature}`
].forEach(variant => {
const win = window.open(windowURL, "", variant);
assert_equals(win, null, `"${variant}" should activate feature "${feature}"`);
});
}, `Tokenization of "${feature}" should skip window features separators before feature`);
test (t => {
// Tokenizing `name`: lowercase conversion
// Each of these variants should tokenize as feature (`${feature}`, '')
// except where indicated
// Note also that `value` is lowercased during tokenization
[
`${featureUpper}`,
`${featureMixedCase}`,
` ${featureMixedCase2}`,
`=${featureUpper}`,
`${featureUpper}=1`,
`${featureUpper}=1`,
`${featureUpper}=yes`,
`${feature}=YES`,
].forEach(variant => {
const win = window.open(windowURL, '', variant);
assert_equals(win, null, `"${variant}" should activate feature "${feature}"`);
});
}, `Feature "${feature}" should be converted to ASCII lowercase`);
test (t => {
// After `name` has been collected, ignore any window features separators until '='
// except ',' OR a non-window-features-separator — break in those cases
// i.e. ignore whitespace until '=' unless a ',' is encountered first
// Each of these variants should tokenize as feature ('noopener', '')
[
`${feature}`,
` ${feature}\r`,
`${feature}\n =`,
`${feature},`,
`${feature} =,`,
`, ${feature} =`,
`${feature},=`,
`${feature} foo`,
`foo ${feature}=1`,
`foo=\u000Cbar\u000C${feature}`
].forEach(variant => {
const win = window.open(windowURL, '', variant);
assert_equals(win, null, `"${variant}" should activate feature "${feature}"`);
});
}, `After "${feature}", tokenization should skip window features separators that are not "=" or ","`);
test (t => {
// After initial '=', tokenizing should ignore all separators except ','
// before collecting `value`
// Each of these variants should tokenize as feature ('noopener', '')
// Except where indicated
[
`${feature}= yes`,
`${feature}==,`,
`${feature}=\n ,`,
`${feature} = \t ,`,
`${feature}\n=\r 1,`,
`${feature}=,yes`,
`${feature}= yes=,`,
`${feature} = \u000Cyes`
].forEach(variant => {
const win = window.open(windowURL, '', variant);
assert_equals(win, null, `"${variant}" should activate feature "${feature}"`);
});
}, `Tokenizing "${feature}" should ignore window feature separators except "," after initial "=" and before value`);
test (t => {
// Tokenizing `value` should collect any non-separator code points until first separator
[
`${feature}=1`,
`${feature}=yes`,
`${feature} = yes ,`,
`${feature}=\nyes ,`,
`${feature}=yes yes`,
`${feature}=yes\ts`,
`${feature}==`,
`${feature}=1\n,`,
`==${feature}===`,
`${feature}==\u000C`
].forEach(variant => {
const win = window.open(windowURL, '', variant);
assert_equals(win, null, `"${variant}" should set "${feature}"`);
});
}, `Tokenizing "${feature}" should read characters until first window feature separator as \`value\``);
test (t => {
[
`${feature}=1`,
`${feature}=2`,
`${feature}=12345`,
`${feature}=1.5`,
`${feature}=-1`,
].forEach(variant => {
const win = window.open(windowURL, '', variant);
assert_equals(win, null, `"${variant}" should activate feature "${feature}"`);
});
}, 'Integer values other than 0 should activate the feature');
test (t => {
[
`${feature}=0`,
`${feature}=0.5`,
`${feature}=error`,
].forEach(variant => {
const win = window.open(windowURL, '', variant);
assert_not_equals(win, null, `"${variant}" should NOT activate feature "${feature}"`);
});
}, `Integer value of 0 should not activate "${feature}"`);
test (t => {
[
`-${feature}`,
`${featureUpper}RRR`,
`${featureMixedCase}R`,
`${featureSplitBegin}_${featureSplitEnd}`,
` ${featureSplitBegin} ${featureSplitEnd}`,
`${featureSplitBegin}\n${featureSplitEnd}`,
`${featureSplitBegin},${featureSplitEnd}`,
`\0${feature}`,
`${feature}\u0000=yes`,
`foo=\u000C${feature}`
].forEach(variant => {
const win = window.open(windowURL, '', variant);
assert_not_equals(win, null, `"${variant}" should NOT activate feature "${feature}"`);
});
}, `Invalid feature names should not tokenize as "${feature}"`);
}

View file

@ -0,0 +1,13 @@
<script>
const channelName = location.search.substr(1),
channel = new BroadcastChannel(channelName);
channel.postMessage({ name: window.name,
haveOpener: window.opener !== null,
referrer: document.referrer });
// Because messages are not delivered synchronously and because closing a
// browsing context prompts the eventual clearing of all task sources, this
// document should not be closed until the opener document has confirmed
// receipt.
channel.onmessage = () => window.close();
</script>

View file

@ -0,0 +1,20 @@
<!doctype html>
<meta charset=utf-8>
<title>window.open() with "noreferrer" tests</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
async_test(t => {
const channelName = "343243423432",
channel = new BroadcastChannel(channelName);
window.open("support/noreferrer-target.html?" + channelName, "", "noreferrer");
channel.onmessage = t.step_func_done(e => {
// Send message first so if asserts throw the popup is still closed
channel.postMessage(null);
assert_equals(e.data.name, "");
assert_equals(e.data.referrer, "");
assert_equals(e.data.haveOpener, false);
});
});
</script>