mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
Update web-platform-tests to revision 78f764c05c229883e87ad135c7153051a66e2851
This commit is contained in:
parent
55347aa39f
commit
bf84a079f9
1983 changed files with 58006 additions and 31437 deletions
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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}"`);
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
Loading…
Add table
Add a link
Reference in a new issue