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>

View file

@ -636,7 +636,7 @@ ReflectionTests.reflects = function(data, idlName, idlObj, domName, domObj) {
// Hard-coded special case
defaultVal = domObj.ownerDocument.URL;
}
if (defaultVal !== null || data.isNullable) {
if (!data.customGetter && (defaultVal !== null || data.isNullable)) {
ReflectionHarness.test(function() {
ReflectionHarness.assertEquals(idlObj[idlName], defaultVal);
}, "IDL get with DOM attribute unset");

View file

@ -0,0 +1,44 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Test for table element's UA-stylesheet-provided styles</title>
<link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#the-css-user-agent-style-sheet-and-presentational-hints">
<link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#tables-2">
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="refElem"></div>
<!-- Note: this test puts the table inside of an element with a non-default
'text-indent' and 'border-collapse' values, so that we can verify that
the table does indeed use the initial value for these properties, rather
than simply inheriting. -->
<div style="text-indent: 100px; border-collapse: collapse">
<table id="tableElem"></table>
</div>
<script>
/* These styles come from the default `table` styling here:
* https://html.spec.whatwg.org/multipage/rendering.html#tables-2
* We can't check for these values directly, because they may be
* serialized slightly differently when read from the computed style.
* So, for each property here, we apply it to a "reference" div and then
* read back the computed value, and we validate that a table element
* has that same computed value by default. */
const defaultTablePropVals = {
'display': 'table',
'box-sizing': 'border-box',
'border-spacing': '2px',
'border-collapse': 'separate',
'text-indent': 'initial',
};
for (var propName in defaultTablePropVals) {
test(function() {
refElem.style[propName] = defaultTablePropVals[propName];
let expectedComputedVal = getComputedStyle(refElem, "")[propName];
let actualComputedVal = getComputedStyle(tableElem, "")[propName];
assert_equals(actualComputedVal, expectedComputedVal);
}, `Computed '${propName}' on table should match html spec`);
}
</script>

View file

@ -32,6 +32,12 @@ test(function() {
}, description);
});
});
test(function() {
var audio = new Audio();
assert_equals(Object.getPrototypeOf(audio), HTMLAudioElement.prototype);
}, "Prototype of object created with named constructor");
test(function() {
assert_throws(new TypeError(), function() {
Audio();

View file

@ -12,8 +12,8 @@
<p class="output">Actual output:</p>
<canvas id="c" class="output" width="
100" height="
<canvas id="c" class="output" width="&#xD;
100" height="&#xD;
100"><p class="fallback">FAIL (fallback content)</p></canvas>
<p class="output expectedtext">Expected output:<p><img src="size.attributes.parse.whitespace.png" class="output expected" id="expected" alt="">
<ul id="d"></ul>
@ -24,8 +24,8 @@ _addTest(function(canvas, ctx) {
_assertSame(canvas.width, 100, "canvas.width", "100");
_assertSame(canvas.height, 100, "canvas.height", "100");
_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
_assertSame(canvas.getAttribute('width'), '\n\t\x0c100', "canvas.getAttribute('width')", "'\\n\\t\\x0c100'");
_assertSame(canvas.getAttribute('height'), '\n\t\x0c100', "canvas.getAttribute('height')", "'\\n\\t\\x0c100'");
_assertSame(canvas.getAttribute('width'), '\r\n\t\x0c100', "canvas.getAttribute('width')", "'\\r\\n\\t\\x0c100'");
_assertSame(canvas.getAttribute('height'), '\r\n\t\x0c100', "canvas.getAttribute('height')", "'\\r\\n\\t\\x0c100'");
});

View file

@ -19,13 +19,13 @@
var t = async_test("Parsing of non-negative integers in setAttribute");
_addTest(function(canvas, ctx) {
canvas.setAttribute('width', '\n\t\x0c100');
canvas.setAttribute('height', '\n\t\x0c100');
canvas.setAttribute('width', '\r\n\t\x0c100');
canvas.setAttribute('height', '\r\n\t\x0c100');
_assertSame(canvas.width, 100, "canvas.width", "100");
_assertSame(canvas.height, 100, "canvas.height", "100");
_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
_assertSame(canvas.getAttribute('width'), '\n\t\x0c100', "canvas.getAttribute('width')", "'\\n\\t\\x0c100'");
_assertSame(canvas.getAttribute('height'), '\n\t\x0c100', "canvas.getAttribute('height')", "'\\n\\t\\x0c100'");
_assertSame(canvas.getAttribute('width'), '\r\n\t\x0c100', "canvas.getAttribute('width')", "'\\r\\n\\t\\x0c100'");
_assertSame(canvas.getAttribute('height'), '\r\n\t\x0c100', "canvas.getAttribute('height')", "'\\r\\n\\t\\x0c100'");
});

View file

@ -0,0 +1,12 @@
Fieldset accessibility tests
============================
These tests are intended to test the accessibility of the fieldset and legend elements.
To run these tests, open the browser's developer tools and navigate to the Accessibility pane (may
need to activate it in Settings), or use an OS-level accessibility inspector, and verify that the
accessible name/role matches the expected accessible name/role.
The following issue discusses ways to automate these tests:
https://github.com/web-platform-tests/wpt/issues/12791

View file

@ -0,0 +1,7 @@
<!doctype html>
<title>fieldset accessibility test: ARIA</title>
<div id=fieldset role=group aria-labelledby=legend>
<div id=legend>Foo</div>
<input>
</div>
<p>Expected accessible name for id=fieldset: "Foo"

View file

@ -0,0 +1,8 @@
<!doctype html>
<title>fieldset accessibility test: baseline</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<fieldset id=fieldset>
<legend>Foo</legend>
<input>
</fieldset>
<p>Expected accessible name for id=fieldset: "Foo"

View file

@ -0,0 +1,11 @@
<!doctype html>
<title>fieldset accessibility test: fieldset -webkit-appearance: none</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<style>
fieldset { -webkit-appearance: none; }
</style>
<fieldset id=fieldset>
<legend>Foo</legend>
<input>
</fieldset>
<p>Expected accessible name for id=fieldset: "Foo"

View file

@ -0,0 +1,11 @@
<!doctype html>
<title>fieldset accessibility test: fieldset display: contents</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<style>
fieldset { display: contents; }
</style>
<fieldset id=fieldset>
<legend>Foo</legend>
<input>
</fieldset>
<p>Expected accessible name for id=fieldset: "Foo"

View file

@ -0,0 +1,11 @@
<!doctype html>
<title>fieldset accessibility test: fieldset display: none</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<style>
fieldset { display: none; }
</style>
<fieldset id=fieldset>
<legend>Foo</legend>
<input>
</fieldset>
<p>Expected no accessible node for id=fieldset.

View file

@ -0,0 +1,13 @@
<!doctype html>
<title>fieldset accessibility test: fieldset div display: contents</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<style>
div { display: contents; }
</style>
<fieldset id=fieldset>
<div>
<legend>Foo</legend>
<input>
</div>
</fieldset>
<p>Expected accessible name for id=fieldset: ""

View file

@ -0,0 +1,8 @@
<!doctype html>
<title>fieldset accessibility test: fieldset role=none</title>
<link rel=help href=http://w3c.github.io/aria/#none>
<fieldset id=fieldset role=none>
<legend>Foo</legend>
<input>
</fieldset>
<p>Expected no accessible node for id=fieldset.

View file

@ -0,0 +1,8 @@
<!doctype html>
<title>fieldset accessibility test: fieldset role=presentation</title>
<link rel=help href=http://w3c.github.io/aria/#presentation>
<fieldset id=fieldset role=presentation>
<legend>Foo</legend>
<input>
</fieldset>
<p>Expected no accessible node for id=fieldset.

View file

@ -0,0 +1,11 @@
<!doctype html>
<title>fieldset accessibility test: fieldset visibility: collapse</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<style>
fieldset { visibility: collapse; }
</style>
<fieldset id=fieldset>
<legend>Foo</legend>
<input>
</fieldset>
<p>Expected no accessible node for id=fieldset.

View file

@ -0,0 +1,12 @@
<!doctype html>
<title>fieldset accessibility test: fieldset visibility: hidden</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<style>
fieldset { visibility: hidden; }
legend, input { visibility: visible; }
</style>
<fieldset id=fieldset>
<legend>Foo</legend>
<input>
</fieldset>
<p>Expected no accessible node for id=fieldset.

View file

@ -0,0 +1,13 @@
<!doctype html>
<title>fieldset accessibility test: flexbox</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<style>
fieldset { display: flex; }
legend { float: left; flex: auto; }
input { display: block; flex: auto; }
</style>
<fieldset id=fieldset>
<legend>Foo</legend>
<input>
</fieldset>
<p>Expected accessible name for id=fieldset: "Foo"

View file

@ -0,0 +1,12 @@
<!doctype html>
<title>fieldset accessibility test: grid</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<style>
fieldset { display: grid; grid-template-columns: auto auto; }
legend { float: left; }
</style>
<fieldset id=fieldset>
<legend>Foo</legend>
<input>
</fieldset>
<p>Expected accessible name for id=fieldset: "Foo"

View file

@ -0,0 +1,11 @@
<!doctype html>
<title>fieldset accessibility test: position: absolute legend</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<style>
legend { position: absolute; }
</style>
<fieldset id=fieldset>
<legend>Foo</legend>
<input>
</fieldset>
<p>Expected accessible name for id=fieldset: "Foo"

View file

@ -0,0 +1,11 @@
<!doctype html>
<title>fieldset accessibility test: legend child display: none</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<style>
legend > span { display: none; }
</style>
<fieldset id=fieldset>
<legend>Foo<span>Bar</span></legend>
<input>
</fieldset>
<p>Expected accessible name for id=fieldset: "Foo"

View file

@ -0,0 +1,11 @@
<!doctype html>
<title>fieldset accessibility test: legend visibility: hidden</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<style>
legend > span { visibility: hidden; }
</style>
<fieldset id=fieldset>
<legend>Foo<span>Bar</span></legend>
<input>
</fieldset>
<p>Expected accessible name for id=fieldset: "Foo"

View file

@ -0,0 +1,11 @@
<!doctype html>
<title>fieldset accessibility test: legend display: contents</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<style>
legend { display: contents; }
</style>
<fieldset id=fieldset>
<legend>Foo</legend>
<input>
</fieldset>
<p>Expected accessible name for id=fieldset: "Foo"

View file

@ -0,0 +1,11 @@
<!doctype html>
<title>fieldset accessibility test: legend display: none</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<style>
legend { display: none; }
</style>
<fieldset id=fieldset>
<legend>Foo</legend>
<input>
</fieldset>
<p>Expected accessible name for id=fieldset: ""

View file

@ -0,0 +1,11 @@
<!doctype html>
<title>fieldset accessibility test: floating legend</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<style>
legend { float: left; }
</style>
<fieldset id=fieldset>
<legend>Foo</legend>
<input>
</fieldset>
<p>Expected accessible name for id=fieldset: "Foo"

View file

@ -0,0 +1,8 @@
<!doctype html>
<title>fieldset accessibility test: legend role=group aria-labelledby=fieldset</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<fieldset id=fieldset>
<legend role=group aria-labelledby=fieldset>Foo</legend>
<input>
</fieldset>
<p>Expected accessible name for id=fieldset: ""

View file

@ -0,0 +1,11 @@
<!doctype html>
<title>fieldset accessibility test: legend visibility: collapse</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<style>
legend { visibility: collapse; }
</style>
<fieldset id=fieldset>
<legend>Foo</legend>
<input>
</fieldset>
<p>Expected accessible name for id=fieldset: ""

View file

@ -0,0 +1,11 @@
<!doctype html>
<title>fieldset accessibility test: legend visibility: hidden</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<style>
legend { visibility: hidden; }
</style>
<fieldset id=fieldset>
<legend>Foo</legend>
<input>
</fieldset>
<p>Expected accessible name for id=fieldset: ""

View file

@ -0,0 +1,10 @@
<!doctype html>
<title>fieldset accessibility test: multiple legends</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<fieldset id=fieldset>
<div></div>
<legend>Foo</legend>
<legend>Bar</legend>
<input>
</fieldset>
<p>Expected accessible name for id=fieldset: "Foo"

View file

@ -0,0 +1,8 @@
<!doctype html>
<title>fieldset accessibility test: role</title>
<fieldset id=fieldset>
<legend id=legend>Foo</legend>
<input>
</fieldset>
<p>Expected accessible role for id=fieldset: "group"
<p>Expected accessible role for id=legend: No corresponding role

View file

@ -0,0 +1,32 @@
<!DOCTYPE html>
<title>fieldset accessibility test: shadow DOM</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<template id="my-fieldset">
<fieldset id=fieldset>
<slot name="my-text"></slot>
<input>
</fieldset>
</template>
<my-fieldset>
<legend slot="my-text">Foo</legend>
</my-fieldset>
<p>Expected accessible name for id=fieldset: ""
<script>
customElements.define('my-fieldset',
class extends HTMLElement {
constructor() {
super();
const template = document.getElementById('my-fieldset');
const templateContent = template.content;
this.attachShadow({mode: 'open'}).appendChild(
templateContent.cloneNode(true)
);
}
}
);
</script>

View file

@ -0,0 +1,8 @@
<!doctype html>
<title>fieldset accessibility test: title attribute and empty legend</title>
<link rel=help href=https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation>
<fieldset id=fieldset title="Foo">
<legend></legend>
<input>
</fieldset>
<p>Expected accessible name for id=fieldset: "Foo"

View file

@ -127,4 +127,9 @@
assert_false(option.selected);
}, "Option constructor does not set dirtiness (so, manipulating the selected content attribute still updates the " +
"selected IDL attribute)");
test(function() {
var option = new Option();
assert_equals(Object.getPrototypeOf(option), HTMLOptionElement.prototype);
}, "Prototype of object created with named constructor");
</script>

View file

@ -0,0 +1,54 @@
<!DOCTYPE html>
<!--
Tentative due to:
https://github.com/whatwg/html/issues/4364
-->
<html>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
</head>
<body>
<h1>User activation can be transferred to a cross-origin child frame via a postMessage option.</h1>
<ol id="instructions">
<li>Click this instruction text.
</ol>
<iframe id="child" width="200" height="200"></iframe>
<script>
async_test(function(t) {
var child = document.getElementById("child");
assert_false(navigator.userActivation.isActive);
assert_false(navigator.userActivation.hasBeenActive);
window.addEventListener("message", t.step_func(event => {
var msg = JSON.parse(event.data);
if (msg.type == 'child-four-loaded') {
// state should be false after load
assert_false(msg.isActive);
assert_false(msg.hasBeenActive);
// click in parent document
test_driver.click(document.getElementById('instructions'));
} else if (msg.type == 'child-four-report') {
assert_true(msg.isActive);
assert_true(msg.hasBeenActive);
assert_false(navigator.userActivation.isActive);
assert_false(navigator.userActivation.hasBeenActive);
t.done();
}
}));
window.addEventListener("click", t.step_func(event => {
assert_true(navigator.userActivation.isActive);
assert_true(navigator.userActivation.hasBeenActive);
// transfer user activation to the child frame
child.contentWindow.postMessage("transfer_user_activation", {targetOrigin: "*", transferUserActivation: true});
}));
child.src = "http://{{domains[www]}}:{{ports[http][0]}}/html/user-activation/resources/child-four.html";
}, "Cross-origin user activation transfer through postMessages");
</script>
</body>
</html>

View file

@ -0,0 +1,54 @@
<!DOCTYPE html>
<!--
Tentative due to:
https://github.com/whatwg/html/issues/4364
-->
<html>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
</head>
<body>
<h1>User activation can be transferred to a child frame via a postMessage option.</h1>
<ol id="instructions">
<li>Click this instruction text.
</ol>
<iframe id="child" width="200" height="200"></iframe>
<script>
async_test(function(t) {
var child = document.getElementById("child");
assert_false(navigator.userActivation.isActive);
assert_false(navigator.userActivation.hasBeenActive);
window.addEventListener("message", t.step_func(event => {
var msg = JSON.parse(event.data);
if (msg.type == 'child-four-loaded') {
// state should be false after load
assert_false(msg.isActive);
assert_false(msg.hasBeenActive);
// click in parent document
test_driver.click(document.getElementById('instructions'));
} else if (msg.type == 'child-four-report') {
assert_true(msg.isActive);
assert_true(msg.hasBeenActive);
assert_false(navigator.userActivation.isActive);
assert_false(navigator.userActivation.hasBeenActive);
t.done();
}
}));
window.addEventListener("click", t.step_func(event => {
assert_true(navigator.userActivation.isActive);
assert_true(navigator.userActivation.hasBeenActive);
// transfer user activation to the child frame
child.contentWindow.postMessage("transfer_user_activation", {transferUserActivation: true});
}));
child.src = "resources/child-four.html";
}, "User activation transfer through postMessages");
</script>
</body>
</html>

View file

@ -0,0 +1,54 @@
<!DOCTYPE html>
<!--
Tentative due to:
https://github.com/whatwg/html/issues/4364
-->
<html>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<h1>User activation transfer request from an inactive frame is ignored.</h1>
<iframe id="child" width="200" height="200"></iframe>
<script>
async_test(function(t) {
var child = document.getElementById("child");
var is_page_loaded = false;
var is_child_four_loaded = false;
assert_false(navigator.userActivation.isActive);
assert_false(navigator.userActivation.hasBeenActive);
function tryPostMessaging() {
if (is_page_loaded && is_child_four_loaded)
child.contentWindow.postMessage("transfer_user_activation", {transferUserActivation: true});
}
window.addEventListener("message", t.step_func(event => {
var msg = JSON.parse(event.data);
if (msg.type == 'child-four-loaded') {
// state should be false after load
assert_false(msg.isActive);
assert_false(msg.hasBeenActive);
is_child_four_loaded = true;
tryPostMessaging();
} else if (msg.type == 'child-four-report') {
assert_false(msg.isActive);
assert_false(msg.hasBeenActive);
assert_false(navigator.userActivation.isActive);
assert_false(navigator.userActivation.hasBeenActive);
t.done();
}
}));
window.addEventListener("load", function(event) {
is_page_loaded = true;
tryPostMessaging();
});
child.src = "resources/child-four.html";
}, "User activation transfer from inactive frame");
</script>
</body>
</html>

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<body style="background: lightgrey;">
<script>
window.parent.postMessage(JSON.stringify({"type": "child-four-loaded", "isActive": navigator.userActivation.isActive,
"hasBeenActive": navigator.userActivation.hasBeenActive}), "*");
window.addEventListener("message", event => {
if (event.source === window.parent && event.data == "transfer_user_activation") {
window.parent.postMessage(JSON.stringify({"type": "child-four-report", "isActive": navigator.userActivation.isActive,
"hasBeenActive": navigator.userActivation.hasBeenActive}), "*");
}
});
</script>
</body>