Auto merge of #21450 - servo:wpt_update_18-08-2018, r=jdm

Sync WPT with upstream (18-08-2018)

Automated downstream sync of changes from upstream as of 18-08-2018.
[no-wpt-sync]

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21450)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-08-18 19:49:35 -04:00 committed by GitHub
commit cd0e7e7ebb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
140 changed files with 4328 additions and 1419 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,4 +0,0 @@
[015.html]
[global scope unchanged]
expected: FAIL

View file

@ -0,0 +1,3 @@
[no-new-global.window.html]
[BarProp maintains its prototype and properties through open()]
expected: FAIL

View file

@ -0,0 +1,65 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Async local storage API surface</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script type="module">
import { storage, StorageArea } from "std:async-local-storage";
import * as classAssert from "./helpers/class-assert.js";
import { testWithArea } from "./helpers/als-tests.js";
test(() => {
classAssert.isConstructor(StorageArea);
classAssert.functionName(StorageArea, "StorageArea");
classAssert.functionLength(StorageArea, 1);
classAssert.hasClassPrototype(StorageArea);
classAssert.hasPrototypeConstructorLink(StorageArea);
classAssert.propertyKeys(StorageArea, ["length", "prototype", "name"], []);
}, "StorageArea constructor");
test(() => {
classAssert.propertyKeys(StorageArea.prototype, [
"constructor", "set", "get", "has", "delete", "clear",
"keys", "values", "entries", "backingStore"
], []);
classAssert.methods(StorageArea.prototype, {
set: 2,
get: 1,
has: 1,
delete: 1,
clear: 0,
keys: 0,
values: 0,
entries: 0
});
classAssert.accessors(StorageArea.prototype, {
backingStore: ["get"]
});
}, "StorageArea.prototype methods and properties");
testWithArea(async area => {
classAssert.propertyKeys(area, [], []);
}, "Instances don't have any properties")
test(() => {
assert_equals(storage instanceof StorageArea, true, "instanceof");
assert_equals(storage.constructor, StorageArea, ".constructor property");
assert_equals(Object.getPrototypeOf(storage), StorageArea.prototype, "[[Prototype]]");
}, "Built-in storage export is a StorageArea");
testWithArea(async area => {
assert_false(Symbol.toStringTag in StorageArea.prototype,
"Symbol.toStringTag must not be in the prototype");
assert_equals(Object.prototype.toString.call(StorageArea.prototype), "[object Object]",
"The prototype must not be customized");
assert_equals(Object.prototype.toString.call(area), "[object Object]",
"A constructed StorageArea must not be customized");
assert_equals(Object.prototype.toString.call(storage), "[object Object]",
"The default storage area must not be customized");
}, "No custom toStringTag");
</script>

View file

@ -0,0 +1,72 @@
import { StorageArea, storage as defaultArea } from "std:async-local-storage";
import { assertArrayCustomEquals } from "./equality-asserters.js";
export function testWithArea(testFn, description) {
promise_test(t => {
const area = new StorageArea(description);
t.add_cleanup(t => area.clear());
return testFn(area, t);
}, description);
}
export function testWithDefaultArea(testFn, description) {
promise_test(t => {
t.add_cleanup(t => defaultArea.clear());
return testFn(defaultArea, t);
}, description);
}
// These two functions take a key/value and use them to test
// set()/get()/delete()/has()/keys()/values()/entries(). The keyEqualityAsserter should be a
// function from ./equality-asserters.js.
export function testVariousMethodsWithDefaultArea(label, key, value, keyEqualityAsserter) {
testWithDefaultArea(testVariousMethodsInner(key, value, keyEqualityAsserter), label);
}
export function testVariousMethods(label, key, value, keyEqualityAsserter) {
testWithArea(testVariousMethodsInner(key, value, keyEqualityAsserter), label);
}
function testVariousMethodsInner(key, value, keyEqualityAsserter) {
return async area => {
await assertPromiseEquals(area.set(key, value), undefined, "set()", "undefined");
await assertPromiseEquals(area.get(key), value, "get()", "the set value");
await assertPromiseEquals(area.has(key), true, "has()", "true");
const keysPromise = area.keys();
assertIsPromise(keysPromise, "keys()");
assertArrayCustomEquals(await keysPromise, [key], keyEqualityAsserter, "keys() must have the key");
const valuesPromise = area.values();
assertIsPromise(valuesPromise);
assert_array_equals(await valuesPromise, [value], "values() must have the value");
const entriesPromise = area.entries();
assertIsPromise(entriesPromise, "entries()");
const entries = await entriesPromise;
assert_true(Array.isArray(entries), "entries() must give an array");
assert_equals(entries.length, 1, "entries() must have only one value");
assert_true(Array.isArray(entries[0]), "entries() 0th element must be an array");
assert_equals(entries[0].length, 2, "entries() 0th element must have 2 elements");
keyEqualityAsserter(entries[0][0], key, "entries() 0th element's 0th element must be the key");
assert_equals(entries[0][1], value, "entries() 0th element's 1st element must be the value");
await assertPromiseEquals(area.delete(key), undefined, "delete()", "undefined");
await assertPromiseEquals(area.get(key), undefined, "get()", "undefined after deleting");
await assertPromiseEquals(area.has(key), false, "has()", "false after deleting");
};
}
async function assertPromiseEquals(promise, expected, label, expectedLabel) {
assertIsPromise(promise, label);
assert_equals(await promise, expected, label + " must fulfill with " + expectedLabel);
}
function assertIsPromise(promise, label) {
assert_equals(promise.constructor, Promise, label + " must return a promise");
}

View file

@ -0,0 +1,107 @@
export function isConstructor(o) {
assert_equals(typeof o, "function", "Must be a function according to typeof");
assert_true(isConstructorTest(o), "Must be a constructor according to the meta-object protocol");
assert_throws(new TypeError(), () => o(), "Attempting to call (not construct) must throw");
}
export function functionLength(o, expected, label) {
const lengthExpected = { writable: false, enumerable: false, configurable: true };
const { value } = propertyDescriptor(o, "length", lengthExpected);
assert_equals(value, expected, `${formatLabel(label)}length value`);
}
export function functionName(o, expected, label) {
const lengthExpected = { writable: false, enumerable: false, configurable: true };
const { value } = propertyDescriptor(o, "name", lengthExpected);
assert_equals(value, expected, `${formatLabel(label)}name value`);
}
export function hasClassPrototype(o) {
const prototypeExpected = { writable: false, enumerable: false, configurable: false };
const { value } = propertyDescriptor(o, "prototype", prototypeExpected);
assert_equals(typeof value, "object", "prototype must be an object");
assert_not_equals(value, null, "prototype must not be null");
}
export function hasPrototypeConstructorLink(klass) {
const constructorExpected = { writable: true, enumerable: false, configurable: true };
const { value } = propertyDescriptor(klass.prototype, "constructor", constructorExpected);
assert_equals(value, klass, "constructor property must match");
}
export function propertyKeys(o, expectedNames, expectedSymbols, label) {
label = formatLabel(label);
assert_array_equals(Object.getOwnPropertyNames(o), expectedNames, `${label}property names`);
assert_array_equals(Object.getOwnPropertySymbols(o), expectedSymbols,
`${label}property symbols`);
}
export function methods(o, expectedMethods) {
for (const [name, length] of Object.entries(expectedMethods)) {
method(o, name, length);
}
}
export function accessors(o, expectedAccessors) {
for (const [name, accessorTypes] of Object.entries(expectedAccessors)) {
accessor(o, name, accessorTypes);
}
}
function method(o, prop, length) {
const methodExpected = { writable: true, enumerable: false, configurable: true };
const { value } = propertyDescriptor(o, prop, methodExpected);
assert_equals(typeof value, "function", `${prop} method must be a function according to typeof`);
assert_false(isConstructorTest(value),
`${prop} method must not be a constructor according to the meta-object protocol`);
functionLength(value, length, prop);
functionName(value, prop, prop);
propertyKeys(value, ["length", "name"], [], prop);
}
function accessor(o, prop, expectedAccessorTypes) {
const accessorExpected = { enumerable: false, configurable: true };
const propDesc = propertyDescriptor(o, prop, accessorExpected);
for (const possibleType of ["get", "set"]) {
const accessorFunc = propDesc[possibleType];
if (expectedAccessorTypes.includes(possibleType)) {
const label = `${prop}'s ${possibleType}ter`;
assert_equals(typeof accessorFunc, "function",
`${label} must be a function according to typeof`);
assert_false(isConstructorTest(accessorFunc),
`${label} must not be a constructor according to the meta-object protocol`);
functionLength(accessorFunc, possibleType === "get" ? 0 : 1, label);
functionName(accessorFunc, `${possibleType} ${prop}`, label);
propertyKeys(accessorFunc, ["length", "name"], [], label);
} else {
assert_equals(accessorFunc, undefined, `${prop} must not have a ${possibleType}ter`);
}
}
}
function propertyDescriptor(obj, prop, mustMatch) {
const propDesc = Object.getOwnPropertyDescriptor(obj, prop);
for (const key in Object.keys(mustMatch)) {
assert_equals(propDesc[key], mustMatch[key], `${prop} ${key}`);
}
return propDesc;
}
function isConstructorTest(o) {
try {
new (new Proxy(o, {construct: () => ({})}));
return true;
} catch (e) {
return false;
}
}
function formatLabel(label) {
return label !== undefined ? ` ${label}` : "";
}

View file

@ -0,0 +1,37 @@
export function assertEqualDates(actual, expected, label) {
assert_equals(expected.constructor, Date,
"assertEqualDates usage check: expected must be a Date");
const labelPart = label === undefined ? "" : `${label}: `;
assert_equals(actual.constructor, Date, `${labelPart}must be a Date`);
assert_equals(actual.valueOf(), expected.valueOf(), `${labelPart}timestamps must match`);
}
export function assertEqualArrayBuffers(actual, expected, label) {
assert_equals(expected.constructor, ArrayBuffer,
"assertEqualArrayBuffers usage check: expected must be an ArrayBuffer");
const labelPart = label === undefined ? "" : `${label}: `;
assert_equals(actual.constructor, ArrayBuffer, `${labelPart}must be an ArrayBuffer`);
assert_array_equals(new Uint8Array(actual), new Uint8Array(expected), `${labelPart}must match`);
}
export function assertArrayBufferEqualsABView(actual, expected, label) {
assert_true(ArrayBuffer.isView(expected),
"assertArrayBufferEqualsABView usage check: expected must be an ArrayBuffer view");
assertEqualArrayBuffers(actual, expected.buffer, label);
}
export function assertArrayCustomEquals(actual, expected, equalityAsserter, label) {
assert_true(Array.isArray(expected),
"assertArrayCustomEquals usage check: expected must be an Array");
const labelPart = label === undefined ? "" : `${label}: `;
assert_true(Array.isArray(actual), `${labelPart}must be an array`);
assert_equals(actual.length, expected.length, `${labelPart}length must be as expected`);
for (let i = 0; i < actual.length; ++i) {
equalityAsserter(actual[i], expected[i], `${labelPart}index ${i}`);
}
}

View file

@ -0,0 +1,66 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Async local storage: tests against various key types</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script type="module">
import { testWithArea, testVariousMethods } from "./helpers/als-tests.js";
import { assertEqualDates, assertEqualArrayBuffers, assertArrayBufferEqualsABView }
from "./helpers/equality-asserters.js";
const invalidKeys = {
"undefined": undefined,
"null": null,
"a boolean": true,
"a symbol": Symbol("a symbol"),
"an object": { an: "object" },
"a function": () => {},
"a regexp": /foo/,
"a Map": new Map(),
"a Set": new Set(),
"an IDBKeyRange": IDBKeyRange.only(5)
};
const validKeys = {
"a number": [5, assert_equals],
"a string": ["a string", assert_equals],
"a Date": [new Date(), assertEqualDates],
"a typed array": [new Uint8Array([1, 2]), assertArrayBufferEqualsABView],
"a DataView": [new DataView(new Uint8Array([3, 4]).buffer), assertArrayBufferEqualsABView],
"an ArrayBuffer": [new Uint8Array([5, 6]).buffer, assertEqualArrayBuffers]
};
const methods = ["set", "get", "has", "delete"];
for (const method of methods) {
testWithArea(async (area, t) => {
for (const [description, key] of Object.entries(invalidKeys)) {
await promise_rejects(t, "DataError", area[method](key), description);
}
}, `${method}: invalid keys`);
testWithArea(async (area, t) => {
for (const [description, key] of Object.entries(invalidKeys)) {
await promise_rejects(t, "DataError", area[method]([key]), description);
}
}, `${method}: invalid keys, nested in arrays`);
testWithArea(async (area, t) => {
for (const [key] of Object.values(validKeys)) {
await area[method](key);
}
}, `${method}: valid keys`);
testWithArea(async (area, t) => {
for (const [key] of Object.values(validKeys)) {
await area[method]([key]);
}
}, `${method}: valid keys, nested in arrays`);
}
for (const [description, [key, equalityAsserter]] of Object.entries(validKeys)) {
testVariousMethods(`Storage methods smoke test: ${description} key`, key, 5, equalityAsserter);
}
</script>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Async local storage: should not work in non-secure contexts when included via import()</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
"use strict";
test(() => {
assert_false(self.isSecureContext, "This test must run in a non-secure context");
}, "Prerequisite check");
promise_test(t => {
return promise_rejects(t, "SecurityError", import("std:async-local-storage"));
});
</script>

View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Async local storage: should not work in non-secure contexts when included via an import statement</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
"use strict";
setup({ allow_uncaught_exception: true });
test(() => {
assert_false(self.isSecureContext, "This test must run in a non-secure context");
}, "Prerequisite check");
async_test(t => {
window.addEventListener("error", t.step_func_done(errorEvent => {
assert_equals(errorEvent.error.constructor, DOMException, "Must trigger a DOMException");
assert_equals(errorEvent.error.name, "SecurityError",
"The DOMException must be a \"SecurityError\"");
}, { once: true }));
});
</script>
<script type="module">
import "std:async-local-storage";
</script>

View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Async local storage: should not work in non-secure contexts when included via a script element</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
"use strict";
setup({ allow_uncaught_exception: true });
test(() => {
assert_false(self.isSecureContext, "This test must run in a non-secure context");
}, "Prerequisite check");
async_test(t => {
self.addEventListener("error", t.step_func_done(errorEvent => {
assert_equals(errorEvent.error.constructor, DOMException, "Must trigger a DOMException");
assert_equals(errorEvent.error.name, "SecurityError",
"The DOMException must be a \"SecurityError\"");
}, { once: true }));
});
</script>
<script type="module" src="std:async-local-storage"></script>

View file

@ -6,6 +6,7 @@
<script src="/resources/testharnessreport.js"></script>
<script type="module">
import { testVariousMethodsWithDefaultArea } from "./helpers/als-tests.js";
import { storage } from "std:async-local-storage";
test(() => {
@ -21,26 +22,7 @@ test(() => {
assert_equals(backingStore.version, 1);
}, "backingStore returns the correct object");
promise_test(async (t) => {
t.add_cleanup(async () => {
await storage.clear();
});
assert_equals(await storage.set("key", "value"), undefined);
assert_equals(await storage.get("key"), "value");
assert_equals(await storage.has("key"), true);
assert_array_equals(await storage.keys(), ["key"]);
assert_array_equals(await storage.values(), ["value"]);
const entries = await storage.entries();
assert_true(Array.isArray(entries));
assert_equals(entries.length, 1);
assert_array_equals(entries[0], ["key", "value"]);
assert_equals(await storage.delete("key"), undefined);
assert_equals(await storage.get("key"), undefined);
assert_equals(await storage.has("key"), false);
}, "storage methods work, at least for one entry with string key and value");
testVariousMethodsWithDefaultArea(
"Storage methods smoke test with string key and value", "key", "value", assert_equals
);
</script>

View file

@ -84,3 +84,15 @@ backgroundFetchTest(async (test, backgroundFetch) => {
assert_equals(results[0].text, 'Background Fetch');
}, 'Using Background Fetch to successfully fetch a single resource');
backgroundFetchTest(async (test, backgroundFetch) => {
const registrationId = uniqueId();
// Very large download total that will definitely exceed the quota.
const options = {downloadTotal: Number.MAX_SAFE_INTEGER};
await promise_rejects(
test, "QUOTA_EXCEEDED_ERR",
backgroundFetch.fetch(registrationId, 'resources/feature-name.txt', options),
'This fetch should have thrown a quota exceeded error');
}, 'Background Fetch that exceeds the quota throws a QuotaExceededError');

View file

@ -0,0 +1,42 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/cookies/resources/cookie-helper.sub.js"></script>
<script>
["", "MaxAge=10"].forEach(extraParams => {
// Without 'secure'
set_prefixed_cookie_via_dom_test({
prefix: "__Host-",
params: "Path=/;" + extraParams,
shouldExistInDOM: false,
shouldExistViaHTTP: false,
title: "__Host: Secure origin: Does not set 'Path=/;" + extraParams + "'"
});
// With 'secure'
set_prefixed_cookie_via_dom_test({
prefix: "__Host-",
params: "Secure; Path=/;" + extraParams,
shouldExistInDOM: true,
shouldExistViaHTTP: true,
title: "__Host: Secure origin: Does set 'Secure; Path=/;" + extraParams + "'"
});
// With 'domain'
set_prefixed_cookie_via_dom_test({
prefix: "__Host-",
params: "Secure; Path=/; Domain=" + document.location.hostname + "; " + extraParams,
shouldExistInDOM: false,
shouldExistViaHTTP: false,
title: "__Host: Secure origin: Does not set 'Secure; Path=/; Domain=" + document.location.hostname + "; " + extraParams + "'"
});
});
set_prefixed_cookie_via_dom_test({
prefix: "__Host-",
params: "Secure; Path=/cookies/resources/list.py",
shouldExistInDOM: false,
shouldExistViaHTTP: false,
title: "__Host: Secure origin: Does not set 'Secure; Path=/cookies/resources/list.py'"
});
</script>

View file

@ -10,7 +10,7 @@
params: "Path=/;" + extraParams,
shouldExistInDOM: false,
shouldExistViaHTTP: false,
title: "__Host: Non-secure origin: 'Path=/;" + extraParams + "'"
title: "__Host: Non-secure origin: Does not set 'Path=/;" + extraParams + "'"
});
// With 'secure'
@ -19,7 +19,16 @@
params: "Secure; Path=/;" + extraParams,
shouldExistInDOM: false,
shouldExistViaHTTP: false,
title: "__Host: Non-secure origin: 'Secure; Path=/;" + extraParams + "'"
title: "__Host: Non-secure origin: Does not set 'Secure; Path=/;" + extraParams + "'"
});
// With 'domain'
set_prefixed_cookie_via_http_test({
prefix: "__Host-",
params: "Secure; Path=/; Domain=" + document.location.hostname + "; " + extraParams,
shouldExistInDOM: false,
shouldExistViaHTTP: false,
title: "__Host: Secure origin: Does not set 'Secure; Path=/; Domain=" + document.location.hostname + "; " + extraParams + "'"
});
});
@ -28,7 +37,7 @@
params: "Secure; Path=/cookies/resources/list.py",
shouldExistInDOM: false,
shouldExistViaHTTP: false,
title: "__Host: Non-secure origin: 'Secure; Path=/cookies/resources/list.py'"
title: "__Host: Non-secure origin: Does not set 'Secure; Path=/cookies/resources/list.py'"
});
</script>

View file

@ -0,0 +1,43 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/cookies/resources/cookie-helper.sub.js"></script>
<script>
["", "MaxAge=10", "HttpOnly"].forEach(extraParams => {
// Without 'secure'
set_prefixed_cookie_via_http_test({
prefix: "__Host-",
params: "Path=/;" + extraParams,
shouldExistInDOM: false,
shouldExistViaHTTP: false,
title: "__Host: Secure origin: Does not set 'Path=/;" + extraParams + "'"
});
// With 'secure'
set_prefixed_cookie_via_http_test({
prefix: "__Host-",
params: "Secure; Path=/;" + extraParams,
shouldExistInDOM: true,
shouldExistViaHTTP: true,
title: "__Host: Secure origin: Does set 'Secure; Path=/;" + extraParams + "'"
});
// With 'domain'
set_prefixed_cookie_via_http_test({
prefix: "__Host-",
params: "Secure; Path=/; Domain=" + document.location.hostname + "; " + extraParams,
shouldExistInDOM: false,
shouldExistViaHTTP: false,
title: "__Host: Secure origin: Does not set 'Secure; Path=/; Domain=" + document.location.hostname + "; " + extraParams + "'"
});
});
set_prefixed_cookie_via_http_test({
prefix: "__Host-",
params: "Secure; Path=/cookies/resources/list.py",
shouldExistInDOM: false,
shouldExistViaHTTP: false,
title: "__Host: Secure origin: Does not set 'Secure; Path=/cookies/resources/list.py'"
});
</script>

View file

@ -3,14 +3,14 @@
<script src="/resources/testharnessreport.js"></script>
<script src="/cookies/resources/cookie-helper.sub.js"></script>
<script>
["", "domain="+document.location.hostname, "MaxAge=10", "HttpOnly"].forEach(extraParams => {
["", "MaxAge=10", "domain="+document.location.hostname].forEach(extraParams => {
// Without 'secure'
set_prefixed_cookie_via_dom_test({
prefix: "__Secure-",
params: "Path=/;" + extraParams,
shouldExistInDOM: false,
shouldExistViaHTTP: false,
title: "__Secure: Non-secure origin: 'Path=/;" + extraParams + "'"
title: "__Secure: Non-secure origin: Should not set 'Path=/;" + extraParams + "'"
});
// With 'secure'
@ -19,7 +19,7 @@
params: "Secure; Path=/;" + extraParams,
shouldExistInDOM: false,
shouldExistViaHTTP: false,
title: "__Secure: Non-secure origin: 'Secure; Path=/;" + extraParams + "'"
title: "__Secure: Non-secure origin: Should not set 'Secure; Path=/;" + extraParams + "'"
});
});
</script>

View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/cookies/resources/cookie-helper.sub.js"></script>
<script>
["", "MaxAge=10", "domain="+document.location.hostname].forEach(extraParams => {
// Without 'secure'
set_prefixed_cookie_via_dom_test({
prefix: "__Secure-",
params: "Path=/;" + extraParams,
shouldExistInDOM: false,
shouldExistViaHTTP: false,
title: "__Secure: Secure origin: Should not set 'Path=/;" + extraParams + "'"
});
// With 'secure'
set_prefixed_cookie_via_dom_test({
prefix: "__Secure-",
params: "Secure; Path=/;" + extraParams,
shouldExistInDOM: true,
shouldExistViaHTTP: true,
title: "__Secure: Secure origin: Should set 'Secure; Path=/;" + extraParams + "'"
});
});
</script>

View file

@ -8,18 +8,16 @@
set_prefixed_cookie_via_http_test({
prefix: "__Secure-",
params: "Path=/;" + extraParams,
shouldExistInDOM: false,
shouldExistViaHTTP: false,
title: "__Secure: Non-secure origin: 'Path=/;" + extraParams + "'"
title: "__Secure: Non-secure origin: Should not set 'Path=/;" + extraParams + "'"
});
// With 'secure'
set_prefixed_cookie_via_http_test({
prefix: "__Secure-",
params: "Secure; Path=/;" + extraParams,
shouldExistInDOM: false,
shouldExistViaHTTP: false,
title: "__Secure: Non-secure origin: 'Secure; Path=/;" + extraParams + "'"
shouldExistViaHTTP: true,
title: "__Secure: Non-secure origin: Should set 'Secure; Path=/;" + extraParams + "'"
});
});
</script>

View file

@ -6,22 +6,18 @@
["", "domain="+CROSS_SITE_HOST, "MaxAge=10", "HttpOnly"].forEach(extraParams => {
// Without 'secure'
set_prefixed_cookie_via_http_test({
origin: SECURE_CROSS_SITE_ORIGIN,
prefix: "__Secure-",
params: "Path=/;" + extraParams,
shouldExistInDOM: false,
shouldExistViaHTTP: false,
title: "__Secure: secure origin: 'Path=/;" + extraParams + "'"
title: "__Secure: secure origin: Should not set 'Path=/;" + extraParams + "'"
});
// With 'secure'
set_prefixed_cookie_via_http_test({
origin: SECURE_CROSS_SITE_ORIGIN,
prefix: "__Secure-",
params: "Secure;Path=/;" + extraParams,
shouldExistInDOM: false,
shouldExistViaHTTP: true,
title: "__Secure: secure origin: 'Secure;Path=/;" + extraParams + "'"
title: "__Secure: secure origin: Should set 'Secure;Path=/;" + extraParams + "'"
});
});
</script>

View file

@ -12,7 +12,7 @@
assert_dom_cookie(name, value, shouldExistInDOM);
return credFetch("/cookies/rfx6265bis/resources/list.py")
return credFetch("/cookies/resources/list.py")
.then(r => r.json())
.then(cookies => assert_equals(cookies[name], shouldExistViaHTTP ? value : undefined));
}, title);

View file

@ -180,27 +180,13 @@ return credFetch(origin + "/cookies/resources/dropSecure.py")
}
//
// DOM based cookie manipulation API's
// DOM based cookie manipulation APIs
//
// borrowed from http://www.quirksmode.org/js/cookies.html
function create_cookie_from_js(name, value, days, secure_flag) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
var secure = "";
if (secure_flag == true) {
secure = "secure; ";
}
document.cookie = name+"="+value+expires+"; "+secure+"path=/";
}
// erase cookie value and set for expiration
function erase_cookie_from_js(name) {
create_cookie_from_js(name,"",-1);
assert_dom_cookie(name, "", false);
let secure = self.location.protocol == "https:" ? "Secure" : "";
document.cookie = `${name}=0; path=/; expires=${new Date(0).toUTCString()}; ${secure}`;
var re = new RegExp("(?:^|; )" + name);
assert_equals(re.test(document.cookie), false, "Sanity check: " + name + " has been deleted.");
}

View file

@ -1,46 +0,0 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/cookies/resources/cookie-helper.sub.js"></script>
<script>
function cookie_force_test(secure_origin, secure_cookie, present, title) {
var counter = 0;
promise_test(t => {
var testCookieValue = "" + Math.random();
var markerCookieName = "marker";
var markerCookieValue = "markerVal";
var brakes = 5000; //limit cookie setting limit in case browers are magic
// Set an initial cookie as a marker
create_cookie_from_js(markerCookieName, markerCookieValue, 10, secure_cookie);
//TODO we cant trust document.cookie to set secure cookies. Need a round trip to a secure origin.
assert_dom_cookie(markerCookieName, markerCookieValue, true);
// Set new cookies until marker is gone
try {
for (i = 0; i < brakes; i++) {
create_cookie_from_js(markerCookieName + counter++, markerCookieValue, 10, secure_cookie);
assert_dom_cookie(markerCookieName, markerCookieValue, true);
}
} catch(err) {
//shame on me, just fiddling for now
}
assert_dom_cookie(markerCookieName, markerCookieValue, present);
if (present == false) {
alert("It took " + counter + " cookies to force out the marker cookie");
} else {
alert("Even after " + counter + " cookies the marker cookie was not forced out. Try incresing the current limit of " + brakes);
}
}, title);
}
//actual tests to verify that non-secure origins should "leave secure cookies alone"
cookie_force_test(false, false, false, "non-secure origins should be able to force out insecure cookies.");
</script>

View file

@ -23,9 +23,10 @@ const testValues = {
* inlineStart: "margin-inline-start", inlineEnd: "margin-inline-end",
* blockStart: "margin-block-start", blockEnd: "margin-block-end",
* }, shorthands: {
* inline: ["margin-inline-start", "margin-inline-end"],
* block: ["margin-block-start", "margin-block-end"],
* }, type: ["length"], prerequisites: "...", property: "'margin-*'" }
* "margin": ["margin-top", "margin-right", "margin-bottom", "margin-left"],
* "margin-inline": ["margin-inline-start", "margin-inline-end"],
* "margin-block": ["margin-block-start", "margin-block-end"],
* }, type: ["length"], prerequisites: "...", property: "margin-*" }
*
* @param {string} property
* A string representing the property names, like "margin-*".
@ -59,8 +60,10 @@ export function createBoxPropertyGroup(property, descriptor) {
physical[physicalSide] = isInset ? physicalSide : property.replace("*", physicalSide);
prerequisites += makeDeclaration(descriptor.prerequisites, physicalSide);
}
shorthands[property.replace("-*", "")] =
["top", "right", "bottom", "left"].map(physicalSide => physical[physicalSide]);
const type = [].concat(descriptor.type);
return {name, logical, physical, shorthands, type, prerequisites, property};
return {logical, physical, shorthands, type, prerequisites, property};
}
/**
@ -109,6 +112,29 @@ export function runTests(group) {
}, `Test that logical ${group.property} properties are supported.`);
testElement.style.cssText = "";
const shorthandValues = {};
for (const [shorthand, longhands] of shorthands || []) {
let valueArray;
if (group.type.length > 1) {
valueArray = [values[0]];
} else {
valueArray = testValues[group.type].slice(0, longhands.length);
}
shorthandValues[shorthand] = valueArray;
const value = valueArray.join(" ");
const expected = [[shorthand, value]];
for (let [i, longhand] of longhands.entries()) {
expected.push([longhand, valueArray[group.type.length > 1 ? 0 : i]]);
}
test(function() {
testElement.style.setProperty(shorthand, value);
testCSSValues("shorthand in inline style", testElement.style, expected);
const stylesheet = `.test { ${group.prerequisites} }`;
testComputedValues("shorthand in computed style", stylesheet, expected);
}, `Test that ${shorthand} shorthand sets longhands and serializes correctly.`);
testElement.style.cssText = "";
}
for (const writingMode of writingModes) {
for (const style of writingMode.styles) {
const writingModeDecl = makeDeclaration(style);
@ -141,21 +167,15 @@ export function runTests(group) {
}, `Test that logical ${group.property} properties share computed values `
+ `with their physical associates, with '${writingModeDecl}'.`);
// Test logical shorthand properties.
if (shorthands) {
test(function() {
for (const [shorthand, longhands] of shorthands) {
let shorthandValues;
if (group.type.length > 1) {
shorthandValues = [values[0]];
} else {
shorthandValues = testValues[group.type].slice(0, longhands.length);
}
const decl = group.prerequisites + `${shorthand}: ${shorthandValues.join(" ")}; `;
let valueArray = shorthandValues[shorthand];
const decl = group.prerequisites + `${shorthand}: ${valueArray.join(" ")}; `;
const expected = [];
for (let [i, longhand] of longhands.entries()) {
const longhandValue = shorthandValues[group.type.length > 1 ? 0 : i];
const longhandValue = valueArray[group.type.length > 1 ? 0 : i];
expected.push([longhand, longhandValue]);
expected.push([associated[longhand], longhandValue]);
}

View file

@ -1,11 +1,13 @@
<!DOCTYPE html>
<link rel="author" title="Anders Hartvoll Ruud" href="andruud@chromium.org">
<!-- TODO(andruud): Add Typed OM details to spec and link to it here. -->
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1/#supported-syntax-strings" />
<link rel="help" href="https://github.com/w3c/css-houdini-drafts/pull/783" />
<meta name="assert" content="Verifies that registered custom properties interact correctly with CSS Typed OM" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style id=style>
div {}
</style>
<div id=target></div>
<script>
@ -43,7 +45,7 @@ function assert_computed_type(name, value, expected) {
}
if (value != null) {
target.attributeStyleMap.set(name, value);
target.style = `${name}: ${value}`;
}
let computedValue = target.computedStyleMap().get(name);
@ -52,7 +54,7 @@ function assert_computed_type(name, value, expected) {
assert_true(computedValue instanceof expected);
if (value != null) {
target.attributeStyleMap.delete(name);
target.style = '';
}
}
@ -177,7 +179,7 @@ test(function(){
assert_equals(target.computedStyleMap().getAll(name).length, 2);
assert_true(target.computedStyleMap().getAll(name).every(x => x instanceof CSSUnitValue));
target.attributeStyleMap.set(name, '10px 20px 30px');
target.style = `${name}: 10px 20px 30px`;
assert_equals(target.computedStyleMap().getAll(name).length, 3);
assert_true(target.computedStyleMap().getAll(name).every(x => x instanceof CSSUnitValue));
}, 'All computed values correctly reified in space-separated list');
@ -187,7 +189,7 @@ test(function(){
assert_equals(target.computedStyleMap().getAll(name).length, 2);
assert_true(target.computedStyleMap().getAll(name).every(x => x instanceof CSSUnitValue));
target.attributeStyleMap.set(name, '10px, 20px, 30px');
target.style = `${name}: 10px, 20px, 30px`;
assert_equals(target.computedStyleMap().getAll(name).length, 3);
assert_true(target.computedStyleMap().getAll(name).every(x => x instanceof CSSUnitValue));
}, 'All computed values correctly reified in comma-separated list');
@ -285,7 +287,7 @@ test(function(){
test(function(){
let name = gen_prop('<length>+', '0px');
target.attributeStyleMap.clear();
target.attributeStyleMap.set(name, '10px 20px 30px');
target.style = `${name}: 10px 20px 30px`;
assert_equals(target.attributeStyleMap.getAll(name).length, 3);
assert_true(target.attributeStyleMap.getAll(name).every(x => x instanceof CSSUnitValue));
}, 'attributeStyleMap.getAll returns a list of CSSUnitValues for <length>+');
@ -293,9 +295,145 @@ test(function(){
test(function(){
let name = gen_prop('<length>#', '0px');
target.attributeStyleMap.clear();
target.attributeStyleMap.set(name, '10px, 20px, 30px');
target.style = `${name}: 10px, 20px, 30px`;
assert_equals(target.attributeStyleMap.getAll(name).length, 3);
assert_true(target.attributeStyleMap.getAll(name).every(x => x instanceof CSSUnitValue));
}, 'attributeStyleMap.getAll returns a list of CSSUnitValues for <length>#');
// StylePropertyMap.set
function test_style_property_map_set_using_property_map(propertyMapName, propertyMap, options) {
test(function(){
let name = gen_prop(options.syntax, options.initialValue);
propertyMap.clear();
for (let value of options.shouldAccept)
propertyMap.set(name, value);
for (let value of options.shouldReject) {
assert_throws(new TypeError(), () => propertyMap.set(name, value));
}
}, `${propertyMapName}.set accepts correct CSSUnitValues for ${options.syntax}`);
}
// Verify that the correct CSSStyleValues are accepted/rejected for a registered
// property with the specified syntax.
//
// The same test is performed twice: once for attributeStyleMap, and once
// for styleMap.
function test_style_property_map_set(options) {
test_style_property_map_set_using_property_map('attributeStyleMap', target.attributeStyleMap, options);
test_style_property_map_set_using_property_map('styleMap', style.sheet.rules[0].styleMap, options);
}
let unparsed = x => new CSSUnparsedValue([x]);
let keyword = x => new CSSKeywordValue(x);
let sum = (a, b) => new CSSMathSum(a, b);
let url_image = x => CSSStyleValue.parse('background-image', x);
test_style_property_map_set({
syntax: '*',
initialValue: 'none',
shouldAccept: [unparsed('thing')],
shouldReject: [CSS.px(15), keyword('none')],
});
test_style_property_map_set({
syntax: '<angle>',
initialValue: '0deg',
shouldAccept: [CSS.deg(42), CSS.turn(2)],
shouldReject: [unparsed('42deg'), CSS.px(15)],
});
test_style_property_map_set({
syntax: '<custom-ident>',
initialValue: 'none',
shouldAccept: [keyword('foo')],
shouldReject: [unparsed('foo'), CSS.px(15)],
});
test_style_property_map_set({
syntax: '<image>',
initialValue: 'url(a)',
shouldAccept: [url_image('url(b)')],
shouldReject: [unparsed('url(b)'), CSS.px(100)],
});
test_style_property_map_set({
syntax: '<integer>',
initialValue: '0',
shouldAccept: [CSS.number(1), CSS.number(-42)],
shouldReject: [unparsed('42'), CSS.px(100)],
});
test_style_property_map_set({
syntax: '<length-percentage>',
initialValue: '0px',
shouldAccept: [CSS.percent(10), CSS.px(1), CSS.em(1)],
shouldReject: [unparsed('10%'), unparsed('10px'), CSS.dpi(1)],
});
test_style_property_map_set({
syntax: '<length>',
initialValue: '0px',
shouldAccept: [CSS.px(10), CSS.em(10), CSS.vh(200), sum(CSS.px(10), CSS.em(20))],
shouldReject: [unparsed('10px'), CSS.percent(1)],
});
test_style_property_map_set({
syntax: '<number>',
initialValue: '0',
shouldAccept: [CSS.number(1337), CSS.number(-42.5)],
shouldReject: [unparsed('42'), CSS.px(15)],
});
test_style_property_map_set({
syntax: '<percentage>',
initialValue: '0%',
shouldAccept: [CSS.percent(10)],
shouldReject: [unparsed('10%'), CSS.px(1)],
});
test_style_property_map_set({
syntax: '<resolution>',
initialValue: '0dpi',
shouldAccept: [CSS.dpi(100), CSS.dpcm(10), CSS.dppx(50)],
shouldReject: [unparsed('42'), CSS.px(15)],
});
test_style_property_map_set({
syntax: '<time>',
initialValue: '0s',
shouldAccept: [CSS.s(42), CSS.ms(16)],
shouldReject: [unparsed('42s'), CSS.px(15)],
});
test_style_property_map_set({
syntax: '<url>',
initialValue: 'url(a)',
shouldAccept: [url_image('url(b)')],
shouldReject: [unparsed('url(b)'), CSS.px(100)],
});
test_style_property_map_set({
syntax: '<transform-list>',
initialValue: 'translateX(0px)',
shouldAccept: [CSSStyleValue.parse('transform', 'translateX(10px)')],
shouldReject: [unparsed('transformX(10px'), CSS.px(100)],
});
test_style_property_map_set({
syntax: 'none | thing | THING',
initialValue: 'none',
shouldAccept: [keyword('thing'), keyword('THING')],
shouldReject: [unparsed('thing'), CSS.px(15), keyword('notathing')],
});
test_style_property_map_set({
syntax: '<angle> | <length>',
initialValue: '0deg',
shouldAccept: [CSS.deg(42), CSS.turn(2), CSS.px(10), CSS.em(10)],
shouldReject: [unparsed('42deg'), unparsed('20px'), CSS.s(1)],
});
</script>

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<meta charset="UTF-8">
<link rel="author" title="Xidorn Quan" href="mailto:me@upsuper.org">
<link rel="author" title="Mozilla" href="https://www.mozilla.org">
<link rel="help" href="https://drafts.csswg.org/css-scrollbars-1/#scrollbar-width">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
.area {
width: 100px;
height: 100px;
overflow: auto;
display: inline-block;
}
.area::before {
content: "";
display: block;
width: 200px;
height: 200px;
}
</style>
<div id="scrollbar-none" class="area" style="scrollbar-width: none"></div>
<div id="scrollbar-thin" class="area" style="scrollbar-width: thin"></div>
<div id="scrollbar-auto" class="area" style="scrollbar-width: auto"></div>
<script>
test(function() {
let elem = document.getElementById("scrollbar-none");
assert_equals(elem.clientWidth, 100);
assert_equals(elem.clientHeight, 100);
}, "scrollbar-width: none should have no scrollbar");
test(function() {
let thin = document.getElementById("scrollbar-thin");
let auto = document.getElementById("scrollbar-auto");
assert_greater_than_equal(thin.clientWidth, auto.clientWidth);
assert_greater_than_equal(thin.clientHeight, auto.clientHeight);
}, "scrollbar-width: thin should have scrollbar no wider than auto");
</script>

View file

@ -144,13 +144,13 @@
<div class="a"/>
</div>
<div class="flexbox">
<div class="b"><div class="fixedSizeChild"/></div>
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox">
<div class="c"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- end -->
@ -158,13 +158,13 @@
<div class="a" style="margin-top: 190px"/>
</div>
<div class="flexbox">
<div class="b" style="margin-top: 160px"><div class="fixedSizeChild"/></div>
<div class="a"/>
<div class="a" style="margin-top: 160px"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox">
<div class="c" style="margin-top: 120px"/>
<div class="a" style="margin-top: 120px"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="a"/>
<div class="c"/>
</div>
</body>
</html>

View file

@ -149,28 +149,28 @@
</div>
<!-- start -->
<div class="flexbox" style="align-content: start; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: start">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: start; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: start">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: start; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: start">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- end -->
<div class="flexbox" style="align-content: end; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: end">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: end; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: end">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: end; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: end">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>

View file

@ -150,28 +150,28 @@
</div>
<!-- start -->
<div class="flexbox" style="align-content: start; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: start">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: start; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: start">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: start; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: start">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- end -->
<div class="flexbox" style="align-content: end; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: end">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: end; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: end">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: end; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: end">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>

View file

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Reftest Reference</title>
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
<style>
div.flexbox {
width: 20px;
height: 200px;
margin-right: 2px;
float: left;
background: lightgray;
}
div.a {
width: 20px;
height: 10px;
background: lightgreen;
}
div.b {
width: 20px;
height: 30px;
background: pink;
}
div.c {
width: 20px;
height: 40px;
background: orange;
}
/* Inside of 'b': */
div.fixedSizeChild {
width: 10px;
height: 30px;
background: purple;
}
</style>
</head>
<body>
<!-- default (stretch) -->
<div class="flexbox">
<div class="a" style="margin-top: 190px"/>
</div>
<div class="flexbox">
<div class="b" style="height:110px"><div class="fixedSizeChild"/></div>
<div class="a" style="margin-top:80px"/>
</div>
<div class="flexbox">
<div class="c" style="margin-top:40px"/>
<div class="b" style="height: 70px"><div class="fixedSizeChild"/></div>
<div class="a" style="margin-top:40px"/>
</div>
<!-- flex-start -->
<div class="flexbox">
<div class="a" style="margin-top: 190px"/>
</div>
<div class="flexbox">
<div class="b" style="margin-top: 160px"><div class="fixedSizeChild"/></div>
<div class="a"/>
</div>
<div class="flexbox">
<div class="c" style="margin-top: 120px"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="a"/>
</div>
<!-- flex-end -->
<div class="flexbox">
<div class="a"/>
</div>
<div class="flexbox">
<div class="b"><div class="fixedSizeChild"/></div>
<div class="a"/>
</div>
<div class="flexbox">
<div class="c"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="a"/>
</div>
<!-- center -->
<div class="flexbox">
<div class="a" style="margin-top: 95px"/>
</div>
<div class="flexbox">
<div class="b" style="margin-top: 80px"><div class="fixedSizeChild"/></div>
<div class="a"/>
</div>
<div class="flexbox">
<div class="c" style="margin-top: 60px"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="a"/>
</div>
<!-- space-between -->
<div class="flexbox">
<div class="a" style="margin-top: 190px"/>
</div>
<div class="flexbox">
<div class="b"><div class="fixedSizeChild"/></div>
<div class="a" style="margin-top: 160px"/>
</div>
<div class="flexbox">
<div class="c"/>
<div class="b" style="margin-top: 60px"><div class="fixedSizeChild"/></div>
<div class="a" style="margin-top: 60px"/>
</div>
<!-- space-around -->
<div class="flexbox">
<div class="a" style="margin-top: 95px"/>
</div>
<div class="flexbox">
<div class="b" style="margin-top: 40px"><div class="fixedSizeChild"/></div>
<div class="a" style="margin-top: 80px"/>
</div>
<div class="flexbox">
<div class="c" style="margin-top: 20px"/>
<div class="b" style="margin-top: 40px"><div class="fixedSizeChild"/></div>
<div class="a" style="margin-top: 40px"/>
</div>
<!-- space-evenly -->
<div class="flexbox">
<div class="a" style="margin-top: 95px"/>
</div>
<div class="flexbox">
<div class="b" style="margin-top: calc(160px / 3)"><div class="fixedSizeChild"/></div>
<div class="a" style="margin-top: calc(160px / 3)"/>
</div>
<div class="flexbox">
<div class="c" style="margin-top: 30px"/>
<div class="b" style="margin-top: 30px"><div class="fixedSizeChild"/></div>
<div class="a" style="margin-top: 30px"/>
</div>
<!-- start -->
<div class="flexbox">
<div class="a"/>
</div>
<div class="flexbox">
<div class="b"><div class="fixedSizeChild"/></div>
<div class="a"/>
</div>
<div class="flexbox">
<div class="c"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="a"/>
</div>
<!-- end -->
<div class="flexbox">
<div class="a" style="margin-top: 190px"/>
</div>
<div class="flexbox">
<div class="b" style="margin-top: 160px"><div class="fixedSizeChild"/></div>
<div class="a"/>
</div>
<div class="flexbox">
<div class="c" style="margin-top: 120px"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="a"/>
</div>
</body>
</html>

View file

@ -0,0 +1,179 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!-- Testcase with a series of row wrap-reverse flex containers, with 1-3 flex lines,
testing each possible value of the 'align-content' property. -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Test: Testing 'align-content' in a row wrap-reverse flex container</title>
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
<link rel="help" href="http://www.w3.org/TR/css-flexbox-1/#align-content-property"/>
<link rel="match" href="flexbox-align-content-horiz-002-ref.xhtml"/>
<style>
div.flexbox {
width: 20px; /* Skinny, to force us to wrap */
height: 200px;
display: flex;
flex-wrap: wrap-reverse;
margin-right: 2px;
float: left;
background: lightgray;
}
div.a {
width: 20px;
height: 10px;
flex: none;
background: lightgreen;
}
div.b {
width: 20px;
height: auto; /* height comes from contents */
flex: none;
background: pink;
}
div.c {
width: 20px;
height: 40px;
flex: none;
background: orange;
}
/* Inside of 'b': */
div.fixedSizeChild {
width: 10px;
height: 30px;
background: purple;
}
</style>
</head>
<body>
<!-- default (stretch) -->
<div class="flexbox">
<div class="a"/>
</div>
<div class="flexbox">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- flex-start -->
<div class="flexbox" style="align-content: flex-start">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: flex-start">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: flex-start">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- flex-end -->
<div class="flexbox" style="align-content: flex-end">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: flex-end">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: flex-end">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- center -->
<div class="flexbox" style="align-content: center">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: center">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: center">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- space-between -->
<div class="flexbox" style="align-content: space-between">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: space-between">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: space-between">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- space-around -->
<div class="flexbox" style="align-content: space-around">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: space-around">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: space-around">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- space-evenly -->
<div class="flexbox" style="align-content: space-evenly">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: space-evenly">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: space-evenly">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- start -->
<div class="flexbox" style="align-content: start">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: start">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: start">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- end -->
<div class="flexbox" style="align-content: end">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: end">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: end">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
</body>
</html>

View file

@ -147,13 +147,13 @@
<div class="a"/>
</div>
<div class="flexbox">
<div class="b"><div class="fixedSizeChild"/></div>
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox">
<div class="c"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- end -->
@ -161,13 +161,13 @@
<div class="a" style="margin-left: 190px"/>
</div>
<div class="flexbox">
<div class="b" style="margin-left: 160px"><div class="fixedSizeChild"/></div>
<div class="a"/>
<div class="a" style="margin-left: 160px"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox">
<div class="c" style="margin-left: 120px"/>
<div class="a" style="margin-left: 120px"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="a"/>
<div class="c"/>
</div>
</body>
</html>

View file

@ -149,28 +149,28 @@
</div>
<!-- start -->
<div class="flexbox" style="align-content: start; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: start">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: start; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: start">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: start; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: start">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- end -->
<div class="flexbox" style="align-content: end; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: end">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: end; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: end">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: end; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: end">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>

View file

@ -150,28 +150,28 @@
</div>
<!-- start -->
<div class="flexbox" style="align-content: start; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: start">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: start; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: start">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: start; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: start">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- end -->
<div class="flexbox" style="align-content: end; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: end">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: end; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: end">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: end; flex-wrap: wrap-reverse">
<div class="flexbox" style="align-content: end">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>

View file

@ -0,0 +1,173 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Reftest Reference</title>
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
<style>
div.flexbox {
width: 200px;
margin-bottom: 2px;
background: lightgray;
height: 20px;
clear: all;
}
div.a {
width: 10px;
height: 20px;
background: lightgreen;
float: right;
}
div.b {
width: 30px;
height: 20px;
background: pink;
float: right;
}
div.c {
width: 40px;
height: 20px;
background: orange;
float: right;
}
/* Inside of 'b': */
div.fixedSizeChild {
width: 30px;
height: 10px;
background: purple;
}
</style>
</head>
<body>
<!-- default (stretch) -->
<div class="flexbox">
<div class="a"/>
</div>
<div class="flexbox">
<div class="a"/>
<div class="b" style="margin-right:80px; width:110px"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox">
<div class="a"/>
<div class="b" style="margin-right: 40px; width: 70px"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- flex-start -->
<div class="flexbox">
<div class="a"/>
</div>
<div class="flexbox">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- flex-end -->
<div class="flexbox">
<div class="a" style="margin-right: 190px"/>
</div>
<div class="flexbox">
<div class="a" style="margin-right: 160px"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox">
<div class="a" style="margin-right: 120px"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- center -->
<div class="flexbox">
<div class="a" style="margin-right: 95px"/>
</div>
<div class="flexbox">
<div class="a" style="margin-right: 80px"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox">
<div class="a" style="margin-right: 60px"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- space-between -->
<div class="flexbox">
<div class="a"/>
</div>
<div class="flexbox">
<div class="a"/>
<div class="b" style="margin-right: 160px"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox">
<div class="a"/>
<div class="b" style="margin-right: 60px"><div class="fixedSizeChild"/></div>
<div class="c" style="margin-right: 60px"/>
</div>
<!-- space-around -->
<div class="flexbox">
<div class="a" style="margin-right: 95px"/>
</div>
<div class="flexbox">
<div class="a" style="margin-right: 40px"/>
<div class="b" style="margin-right: 80px"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox">
<div class="a" style="margin-right: 20px"/>
<div class="b" style="margin-right: 40px"><div class="fixedSizeChild"/></div>
<div class="c" style="margin-right: 40px"/>
</div>
<!-- space-evenly -->
<div class="flexbox">
<div class="a" style="margin-right: 95px"/>
</div>
<div class="flexbox">
<div class="a" style="margin-right: calc(160px / 3)"/>
<div class="b" style="margin-right: calc(160px / 3)"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox">
<div class="a" style="margin-right: 30px"/>
<div class="b" style="margin-right: 30px"><div class="fixedSizeChild"/></div>
<div class="c" style="margin-right: 30px"/>
</div>
<!-- start -->
<div class="flexbox">
<div class="a" style="margin-right: 190px"/>
</div>
<div class="flexbox">
<div class="a" style="margin-right: 160px"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox">
<div class="a" style="margin-right: 120px"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- end -->
<div class="flexbox">
<div class="a"/>
</div>
<div class="flexbox">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
</body>
</html>

View file

@ -0,0 +1,179 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!-- Testcase with a series of column wrap-reverse flex containers, with 1-3 flex lines,
testing each possible value of the 'align-content' property. -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Test: Testing 'align-content' in a column wrap-reverse flex container</title>
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
<link rel="help" href="http://www.w3.org/TR/css-flexbox-1/#align-content-property"/>
<link rel="match" href="flexbox-align-content-vert-002-ref.xhtml"/>
<style>
div.flexbox {
width: 200px;
height: 20px; /* Short, to force us to wrap */
display: flex;
flex-direction: column;
flex-wrap: wrap-reverse;
margin-bottom: 2px;
background: lightgray;
}
div.a {
width: 10px;
height: 20px;
flex: none;
background: lightgreen;
}
div.b {
width: auto; /* width comes from contents */
height: 20px;
flex: none;
background: pink;
}
div.c {
width: 40px;
height: 20px;
flex: none;
background: orange;
}
/* Inside of 'b': */
div.fixedSizeChild {
width: 30px;
height: 10px;
background: purple;
}
</style>
</head>
<body>
<!-- default (stretch) -->
<div class="flexbox">
<div class="a"/>
</div>
<div class="flexbox">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- flex-start -->
<div class="flexbox" style="align-content: flex-start">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: flex-start">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: flex-start">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- flex-end -->
<div class="flexbox" style="align-content: flex-end">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: flex-end">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: flex-end">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- center -->
<div class="flexbox" style="align-content: center">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: center">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: center">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- space-between -->
<div class="flexbox" style="align-content: space-between">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: space-between">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: space-between">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- space-around -->
<div class="flexbox" style="align-content: space-around">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: space-around">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: space-around">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- space-evenly -->
<div class="flexbox" style="align-content: space-evenly">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: space-evenly">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: space-evenly">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- start -->
<div class="flexbox" style="align-content: start">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: start">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: start">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
<!-- end -->
<div class="flexbox" style="align-content: end">
<div class="a"/>
</div>
<div class="flexbox" style="align-content: end">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
</div>
<div class="flexbox" style="align-content: end">
<div class="a"/>
<div class="b"><div class="fixedSizeChild"/></div>
<div class="c"/>
</div>
</body>
</html>

View file

@ -9,8 +9,10 @@
# Tests for alignment of flex lines (align-content property)
== flexbox-align-content-horiz-001a.xhtml flexbox-align-content-horiz-001-ref.xhtml
== flexbox-align-content-horiz-001b.xhtml flexbox-align-content-horiz-001-ref.xhtml
== flexbox-align-content-horiz-002.xhtml flexbox-align-content-horiz-002-ref.xhtml
== flexbox-align-content-vert-001a.xhtml flexbox-align-content-vert-001-ref.xhtml
== flexbox-align-content-vert-001b.xhtml flexbox-align-content-vert-001-ref.xhtml
== flexbox-align-content-vert-002.xhtml flexbox-align-content-vert-002-ref.xhtml
== flexbox-align-content-wmvert-001.xhtml flexbox-align-content-wmvert-001-ref.xhtml
# Tests for cross-axis alignment (align-self / align-items properties)

View file

@ -0,0 +1,31 @@
---
layout: page
title: Reverting Changes
order: 3
---
Testing is imperfect and from time to time changes are merged into master which
break things for users of web-platform-tests. Such breakage can include:
* Failures in Travis or Taskcluster runs for this repository, either on the
master branch or on pull requests following the breaking change.
* Breakage in browser engine repositories which import and run
web-platform-tests, such as Chromium, Edge, Gecko, Servo and WebKit.
* Breakage in results collections systems for results dashboards, such as
[wpt.fyi](https://wpt.fyi).
* Breakage in supplemental tooling used by working groups, such as the
[CSS build system][].
When such breakage happens, if the maintainers of the affected systems request
it, pull requests to revert the original change should normally be approved and
merged as soon as possible. (When the original change itself was fixing a
serious problem, it's a judgement call, but prefer the fastest path to a stable
state acceptable to everyone.)
Once a revert has happened, the maintainers of the affected systems are
expected to work with the original patch author to resolve the problem so that
the change can be relanded. A reasonable timeframe to do so is within one week.
[CSS build system]: https://github.com/web-platform-tests/wpt/tree/master/css/tools

View file

@ -1,20 +0,0 @@
<!doctype html>
<title>Replacement of window object after document.open</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<iframe></iframe>
<script>
var t = async_test();
onload = t.step_func(function() {
var iframe = document.getElementsByTagName("iframe")[0];
iframe.contentWindow.state = 1;
var handle = iframe.contentWindow;
iframe.contentDocument.open();
assert_false("state" in iframe.contentWindow, "Variables are not preserved after document.open");
assert_equals(iframe.contentWindow.state, undefined, "Variables are not preserved after document.open");
assert_equals(iframe.contentWindow, handle);
t.done();
});
</script>

View file

@ -1,20 +0,0 @@
<!doctype html>
<title>Replacement of document prototype object after document.open</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<iframe src="/common/blank.html"></iframe>
<script>
var t = async_test();
var iframe;
onload = t.step_func(function() {
var iframe = document.getElementsByTagName("iframe")[0];
var handle = Object.getPrototypeOf(iframe.contentDocument);
handle.test_state = 1;
assert_equals(iframe.contentDocument.open(), iframe.contentDocument);
var new_handle = Object.getPrototypeOf(iframe.contentDocument);
assert_equals(new_handle.test_state, undefined);
assert_not_equals(new_handle, handle);
t.done();
});
</script>

View file

@ -1,34 +0,0 @@
<!doctype html>
<title>document.open replacing singleton</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<iframe src="/common/blank.html"></iframe>
<script>
var iframe = document.getElementsByTagName("iframe")[0];
var steps;
iframe.onload = function() {
steps = ["window", "location", "history", "navigator", "applicationCache", "sessionStorage", "localStorage", "locationbar"].map(
function(x) {
var t = async_test(document.title + " " + x);
var handle = iframe.contentWindow[x];
handle.test_state = 1;
return t.step_func(
function() {
var new_handle = iframe.contentWindow[x];
assert_equals(new_handle.test_state, undefined);
if (x !== "window") {
assert_not_equals(new_handle, handle);
} else {
assert_equals(new_handle, handle);
}
t.done();
});
}
);
}
onload = function() {
assert_equals(iframe.contentDocument.open(), iframe.contentDocument);
steps.forEach(function(x) {x()});
}
</script>

View file

@ -5,7 +5,7 @@ onload = function() {
parent.tests[0].step(function() {parent.assert_equals(document.open(), document)});
document.write("<script>test_prop = 2;<\/script>");
document.close();
parent.tests[0].step(function() {parent.assert_equals(test_prop, 1)});
parent.tests[0].step(function() {parent.assert_equals(test_prop, 2)});
parent.tests[1].step(function() {parent.assert_equals(window.test_prop, 2)});
parent.tests[2].step(function() {parent.assert_equals(get_this(), window)});
parent.tests_done();

View file

@ -5,7 +5,7 @@
<div id="log"></div>
<script>
var tests = [async_test("global scope unchanged"),
async_test("window object changed"),
async_test("window object unchanged"),
async_test("this is the window object")];
function tests_done() {
tests.forEach(function(t) {t.done()});

View file

@ -0,0 +1,18 @@
// In an earlier version of the HTML Standard, document open steps had "prompt
// to unload document" as a step. Test that this no longer happens.
async_test(t => {
const frame = document.body.appendChild(document.createElement("iframe"));
t.add_cleanup(() => frame.remove());
frame.src = "/common/blank.html";
frame.onload = t.step_func(() => {
frame.contentWindow.onbeforeunload = t.unreached_func("beforeunload should not be fired");
frame.contentDocument.open();
t.step_timeout(t.step_func_done(() => {
// If the beforeunload event has still not fired by this point, we
// consider the test a success. `frame.remove()` above will allow the
// `load` event to be fired on the top-level Window, thus unblocking
// testharness.
}), 500);
});
}, "document.open() should not fire a beforeunload event");

View file

@ -3,7 +3,7 @@
onload = function() {
document.open();
document.close();
parent.report(window.setTimeout === setTimeout, false, "setTimeout");
parent.report(window.setTimeout === setTimeout, true, "setTimeout");
parent.report(window === this, true, "this");
parent.done();
}

View file

@ -1,5 +1,5 @@
<!DOCTYPE html>
<title>document.open and singleton replacement</title>
<title>document.open and no singleton replacement</title>
<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-document-open">
<script src="/resources/testharness.js"></script>

View file

@ -0,0 +1,57 @@
// In an earlier version of the HTML Standard, document open steps created a
// new JavaScript realm and migrated the existing objects to use the new realm.
// Test that this no longer happens.
async_test(t => {
const frame = document.body.appendChild(document.createElement("iframe"));
// Ensure a load event gets dispatched to unblock testharness
t.add_cleanup(() => frame.remove());
frame.src = "resources/global-variables-frame.html";
frame.onload = t.step_func_done(() => {
assert_equals(frame.contentWindow.hey, "You", "precondition");
frame.contentDocument.open();
assert_equals(frame.contentWindow.hey, "You", "actual check");
});
}, "Obtaining a variable from a global whose document had open() invoked");
function testIdentity(desc, frameToObject, frameToConstructor) {
async_test(t => {
const frame = document.body.appendChild(document.createElement("iframe"));
// Ensure a load event gets dispatched to unblock testharness
t.add_cleanup(() => frame.remove());
frame.src = "/common/blank.html";
frame.onload = t.step_func_done(() => {
const obj = frameToObject(frame);
frame.contentDocument.open();
assert_equals(frameToObject(frame), obj);
});
}, `${desc} maintains object identity through open()`);
async_test(t => {
const frame = document.body.appendChild(document.createElement("iframe"));
// Ensure a load event gets dispatched to unblock testharness
t.add_cleanup(() => frame.remove());
frame.src = "/common/blank.html";
frame.onload = t.step_func_done(() => {
const obj = frameToObject(frame);
const origProto = Object.getPrototypeOf(obj);
const origCtor = frameToConstructor(frame);
const sym = Symbol();
obj[sym] = "foo";
frame.contentDocument.open();
assert_equals(frameToObject(frame)[sym], "foo");
assert_true(frameToObject(frame) instanceof origCtor);
assert_equals(Object.getPrototypeOf(frameToObject(frame)), origProto);
assert_equals(frameToConstructor(frame), origCtor);
});
}, `${desc} maintains its prototype and properties through open()`);
}
testIdentity("Document", frame => frame.contentDocument, frame => frame.contentWindow.Document);
testIdentity("WindowProxy", frame => frame.contentWindow, frame => frame.contentWindow.Window);
testIdentity("BarProp", frame => frame.contentWindow.locationbar, frame => frame.contentWindow.BarProp);
testIdentity("History", frame => frame.contentWindow.history, frame => frame.contentWindow.History);
testIdentity("localStorage", frame => frame.contentWindow.localStorage, frame => frame.contentWindow.Storage);
testIdentity("Location", frame => frame.contentWindow.location, frame => frame.contentWindow.Location);
testIdentity("sessionStorage", frame => frame.contentWindow.sessionStorage, frame => frame.contentWindow.Storage);
testIdentity("Navigator", frame => frame.contentWindow.navigator, frame => frame.contentWindow.Navigator);

View file

@ -0,0 +1,4 @@
<!doctype html>
<script>
hey = "You";
</script>

View file

@ -0,0 +1,19 @@
// In an earlier version of the HTML Standard, document open steps had "unload
// document" as a step. Test that this no longer happens.
async_test(t => {
const frame = document.body.appendChild(document.createElement("iframe"));
t.add_cleanup(() => frame.remove());
frame.src = "/common/blank.html";
frame.onload = t.step_func(() => {
frame.contentWindow.onpagehide = t.unreached_func("onpagehide got called");
frame.contentDocument.onvisibilitychange = t.unreached_func("onvisibilitychange got called");
frame.contentWindow.onunload = t.unreached_func("onunload got called");
frame.contentDocument.open();
t.step_timeout(t.step_func_done(() => {
// If none of the three events have been fired by this point, we consider
// the test a success. `frame.remove()` above will allow the `load` event
// to be fired on the top-level Window, thus unblocking testharness.
}), 500);
});
}, "document.open(): Do not fire pagehide, visibilitychange, or unload events");

View file

@ -54,7 +54,7 @@ enum NFCPushTarget {
dictionary NFCWatchOptions {
USVString url = "";
NFCRecordType? recordType;
NFCRecordType recordType;
USVString mediaType = "";
NFCWatchMode mode = "web-nfc-only";
};

View file

@ -0,0 +1,2 @@
suggested_reviewers:
- dcreager

View file

@ -0,0 +1,74 @@
# Network Error Logging
The tests in this directory exercise the user agent's implementation of [Network
Error Logging](https://w3c.github.io/network-error-logging/) and
[Reporting](https://w3c.github.io/reporting/).
## Collector
Each test case generates a unique `reportID` that is used to distinguish the NEL
reports generated by that test case.
The [support/report.py][] file is a [Python file handler][] that can be used as
a Reporting collector. Its default operation is to save any reports that it
receives into the [stash][]. If you pass in the optional `op` URL parameter,
with a value of `retrieve_report`, it will instead return a list of all of the
reports received for a particular `reportID`.
[Python file handler]: https://wptserve.readthedocs.io/en/latest/handlers.html#python-file-handlers
[stash]: https://wptserve.readthedocs.io/en/latest/stash.html
[support/report.py]: support/report.py
## Installing NEL policies
NEL reports are only generated if the user agent has received a NEL policy for
the origin of the request. The current request counts; if its response contains
a policy, that policy is used for the current request and all future requests,
modulo the policy's `max_age` field.
Most of the test cases will therefore make a request or two to install NEL
policies, and then make another request that should or should not be covered by
those policies. It will then assert that NEL reports were or were not created,
as required by the spec.
The [support][] directory contains several images, each of which defines a
particular "kind" of NEL policy (e.g., `include_subdomains` set vs unset, no
policy at all, etc.). The [support/nel.sub.js][] file contains helper
JavaScript methods for requesting those images, so that the test cases
themselves are more descriptive.
[support]: support
[support/nel.sub.js]: support/nel.sub.js
## Avoiding spurious reports
NEL policies apply to **all** future requests to the origin. We therefore serve
all of the test case's "infrastructure" (the test case itself,
[support/report.py][] and [support/nel.sub.js][]) on a different origin than
the requests that exercise the NEL implementation. That ensures that we don't
have to wade through NEL reports about the infrastructure when verifying the NEL
reports about the requests that we care about.
## Browser configuration
You must configure your browser's Reporting implementation to upload reports for
a request immediately. The test cases do not currently have any timeouts; they
assume that as soon as the Fetch API promise resolves, any NEL reports for the
request have already been uploaded.
## Test parallelism
Because NEL policies are stored in a global cache in the user agent, we need to
run the tests in this directory serially instead of in parallel. We implement a
simple spin-lock in [support/lock.py][] to ensure that only one test is allowed
to perform any NEL-related requests at a time.
[support/lock.py]: support/lock.py
## CORS preflights
Reporting uploads are subject to CORS preflights. We want to test normal
operation (when preflight requests succeed) as well as failures of the CORS
preflight logic in the user agent. To support this, our test collector is
configured to always reject the CORS preflight for a single domain (www2), and
to always grant the CORS preflight for all other test subdomains.

View file

@ -0,0 +1,26 @@
<!DOCTYPE HTML>
<html>
<head>
<title>
Test that NEL reports are not sent if the CORS preflight fails
</title>
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<script src='./support/nel.sub.js'></script>
</head>
<body>
<script>
nel_test(async t => {
// Make a request to a resource whose response headers include a NEL
// policy, but where the report uploader will reject the CORS preflight.
await fetchResourceWithBasicPolicy('www2');
// Because the CORS preflight is rejected, we should never receive a
// report about the request.
assert_false(await reportExists({
url: getURLForResourceWithBasicPolicy('www2'),
type: "network-error",
}));
});
</script>
</body>
</html>

View file

@ -0,0 +1,30 @@
<!DOCTYPE HTML>
<html>
<head>
<title>
Test that include_subdomains policies do NOT report HTTP errors
</title>
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<script src='./support/nel.sub.js'></script>
</head>
<body>
<script>
nel_test(async t => {
// Make a request to a resource whose response headers include an
// include_subdomains NEL policy.
await fetchResourceWithIncludeSubdomainsPolicy();
// Make a request to another resource on a subdomain of the above. This
// resource doesn't exist, so the server should return a 404.
await fetchMissingResource('www');
// The include_subdomains policy that we just received should NOT cover
// the second request, since include_subdomains policies can only report
// on DNS errors.
assert_false(await reportExists({
url: getURLForMissingResource('www'),
type: "network-error",
}));
});
</script>
</body>
</html>

View file

@ -0,0 +1,30 @@
<!DOCTYPE HTML>
<html>
<head>
<title>
Test that include_subdomains policies do NOT report successful requests
</title>
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<script src='./support/nel.sub.js'></script>
</head>
<body>
<script>
nel_test(async t => {
// Make a request to a resource whose response headers include an
// include_subdomains NEL policy.
await fetchResourceWithIncludeSubdomainsPolicy();
// Make a request to another resource on a subdomain of the above, which
// does not define its own NEL policy.
await fetchResourceWithNoPolicy('www');
// The include_subdomains policy that we just received should NOT cover
// the second request, since include_subdomains policies can only report
// on DNS errors.
assert_false(await reportExists({
url: getURLForResourceWithNoPolicy('www'),
type: "network-error",
}));
});
</script>
</body>
</html>

View file

@ -0,0 +1,29 @@
<!DOCTYPE HTML>
<html>
<head>
<title>
Test that NEL reports are not observable from JavaScript
</title>
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<script src='./support/nel.sub.js'></script>
</head>
<body>
<script>
nel_test(async t => {
// Register an observer for NEL reports.
var observer = new ReportingObserver((reports, _) => {
assert_unreached("NEL reports should not be observable");
}, {"types": ["network-error"]});
observer.observe();
// Make a request to a resource whose response headers include a NEL
// policy. If NEL reports are observable, this will queue a task that
// calls the observer function above (which we don't want).
await fetchResourceWithBasicPolicy();
// Wait for one second to give any observer callback task a chance to
// fire.
await new Promise(resolve => t.step_timeout(resolve, 1000 /* msec */));
});
</script>
</body>
</html>

View file

@ -0,0 +1,42 @@
<!DOCTYPE HTML>
<html>
<head>
<title>
Test that NEL reports are sent for HTTP errors
</title>
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<script src='./support/nel.sub.js'></script>
</head>
<body>
<script>
nel_test(async t => {
// Make a request to a resource whose response headers include a NEL
// policy.
await fetchResourceWithBasicPolicy();
// Make a request to another resource on the same domain. This resource
// doesn't exist, so the server should return a 404.
await fetchMissingResource();
// The 404 won't contain its own NEL policy, but the policy we received in
// the first request should cover the second request, too, since they're
// at the same origin, so the collector should have received a report
// about it.
assert_true(await reportExists({
url: getURLForMissingResource(),
user_agent: navigator.userAgent,
type: "network-error",
body: {
method: "GET",
sampling_fraction: 1.0,
status_code: 404,
phase: "application",
type: "http.error",
},
metadata: {
content_type: "application/reports+json",
},
}));
});
</script>
</body>
</html>

View file

@ -0,0 +1,46 @@
<!DOCTYPE HTML>
<html>
<head>
<title>
Test that include_subdomains policies report DNS failures for subdomains
</title>
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<script src='./support/nel.sub.js'></script>
</head>
<body>
<script>
nel_test(async t => {
// Make a request to a resource whose response headers include an
// include_subdomains NEL policy.
await fetchResourceWithIncludeSubdomainsPolicy();
// Make a request to another resource on a nonexistent subdomain of the
// above. Since the subdomain doesn't exist, the request should fail with
// a DNS error.
await fetchResourceWithNoPolicy('nonexistent').then((response) => {
assert_unreached("Request to nonexistent domain should fail");
}, (err) => {
// Silence the error, since it's expected.
});
// The include_subdomains policy that we just received should cover the
// second request, since include_subdomains policies can report on DNS
// errors, so the collector should have received a report about it.
assert_true(await reportExists({
url: getURLForResourceWithNoPolicy('nonexistent'),
user_agent: navigator.userAgent,
type: "network-error",
body: {
method: "GET",
sampling_fraction: 1.0,
status_code: 0,
phase: "dns",
type: "dns.name_not_resolved",
},
metadata: {
content_type: "application/reports+json",
},
}));
});
</script>
</body>
</html>

View file

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<head>
<title>
Test that NEL reports are sent for successful requests
</title>
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<script src='./support/nel.sub.js'></script>
</head>
<body>
<script>
nel_test(async t => {
// Make a request to a resource whose response headers include an
// include_subdomains NEL policy.
await fetchResourceWithIncludeSubdomainsPolicy();
// That policy should apply to the request that delivered it. Even though
// the policy has include_subdomains set, it SHOULD generate a full,
// non-downgraded report about the request, since the request has the
// same origin as the policy. (I.e., since the origins are the same, the
// include_subdomains setting is irrelevant.)
assert_true(await reportExists({
url: getURLForResourceWithIncludeSubdomainsPolicy(),
user_agent: navigator.userAgent,
type: "network-error",
body: {
method: "GET",
sampling_fraction: 1.0,
status_code: 200,
phase: "application",
type: "ok",
},
metadata: {
content_type: "application/reports+json",
},
}));
});
</script>
</body>
</html>

View file

@ -0,0 +1,37 @@
<!DOCTYPE HTML>
<html>
<head>
<title>
Test that NEL reports are sent for successful requests
</title>
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<script src='./support/nel.sub.js'></script>
</head>
<body>
<script>
nel_test(async t => {
// Make a request to a resource whose response headers include a NEL
// policy.
await fetchResourceWithBasicPolicy();
// That policy should apply to the request that delivered it, so the
// collector should have received a report about the request.
assert_true(await reportExists({
url: getURLForResourceWithBasicPolicy(),
user_agent: navigator.userAgent,
type: "network-error",
body: {
method: "GET",
sampling_fraction: 1.0,
status_code: 200,
phase: "application",
type: "ok",
},
metadata: {
content_type: "application/reports+json",
},
}));
});
</script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,6 @@
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Cache-Control: post-check=0, pre-check=0, false
Pragma: no-cache
Report-To: { "group": "nel-group", "max_age": 0, "endpoints": [] }
NEL: {"max_age": 0}

View file

@ -0,0 +1,38 @@
_LOCK_KEY = "network-error-logging:lock"
_TIMEOUT = 5 # seconds
def wait_for_lock(request):
t0 = time.time()
while time.time() - t0 < _TIMEOUT:
time.sleep(0.5)
value = request.server.stash.take(key=_LOCK_KEY)
if value is None:
return True
return False
def lock(request, report_id):
with request.server.stash.lock:
# Loop until the lock is free
if not wait_for_lock(request):
return (503, [], "Cannot obtain lock")
request.server.stash.put(key=_LOCK_KEY, value=report_id)
return "Obtained lock for %s" % report_id
def unlock(request, report_id):
with request.server.stash.lock:
lock_holder = request.server.stash.take(key=_LOCK_KEY)
if lock_holder != request_id:
# Return the lock holder to the stash
request.server.stash.put(key=_LOCK_KEY, value=lock_holder)
return (503, [], "Cannot release lock held by %s" % lock_holder)
return "Released lock for %s" % report_id
def main(request, response):
op = request.GET.first("op")
report_id = request.GET.first("reportID")
if op == "lock":
return lock(request, report_id)
elif op == "unlock":
return unlock(request, report_id)
else:
return (400, [], "Invalid op")

View file

@ -0,0 +1,169 @@
const reportID = "{{$id:uuid()}}";
/*
* NEL tests have to run serially, since the user agent maintains a global cache
* of Reporting and NEL policies, and we don't want the policies for multiple
* tests to interfere with each other. These functions (along with a Python
* handler in lock.py) implement a simple spin lock.
*/
function obtainNELLock() {
return fetch("/network-error-logging/support/lock.py?op=lock&reportID=" + reportID);
}
function releaseNELLock() {
return fetch("/network-error-logging/support/lock.py?op=unlock&reportID=" + reportID);
}
function nel_test(callback, name, properties) {
promise_test(async t => {
await obtainNELLock();
await clearReportingAndNELConfigurations();
await callback(t);
await releaseNELLock();
}, name, properties);
}
/*
* Helper functions for constructing domain names that contain NEL policies.
*/
function _monitoredDomain(subdomain) {
if (subdomain == "www") {
return "{{hosts[alt][www]}}"
} else if (subdomain == "www1") {
return "{{hosts[alt][www1]}}"
} else if (subdomain == "www2") {
return "{{hosts[alt][www2]}}"
} else if (subdomain == "nonexistent") {
return "{{hosts[alt][nonexistent]}}"
} else {
return "{{hosts[alt][]}}"
}
}
function _getNELResourceURL(subdomain, suffix) {
return "https://" + _monitoredDomain(subdomain) +
":{{ports[https][0]}}/network-error-logging/support/" + suffix;
}
/*
* Fetches a resource whose headers define a basic NEL policy (i.e., with no
* include_subdomains flag). We ensure that we request the resource from a
* different origin than is used for the main test case HTML file or for report
* uploads. This minimizes the number of reports that are generated for this
* policy.
*/
function getURLForResourceWithBasicPolicy(subdomain) {
return _getNELResourceURL(subdomain, "pass.png?id="+reportID);
}
function fetchResourceWithBasicPolicy(subdomain) {
const url = getURLForResourceWithBasicPolicy(subdomain);
return fetch(url, {mode: "no-cors"});
}
/*
* Fetches a resource whose headers define an include_subdomains NEL policy.
*/
function getURLForResourceWithIncludeSubdomainsPolicy(subdomain) {
return _getNELResourceURL(subdomain, "subdomains-pass.png?id="+reportID);
}
function fetchResourceWithIncludeSubdomainsPolicy(subdomain) {
const url = getURLForResourceWithIncludeSubdomainsPolicy(subdomain);
return fetch(url, {mode: "no-cors"});
}
/*
* Fetches a resource whose headers do NOT define a NEL policy. This may or may
* not generate a NEL report, depending on whether you've already successfully
* requested a resource from the same origin that included a NEL policy.
*/
function getURLForResourceWithNoPolicy(subdomain) {
return _getNELResourceURL(subdomain, "no-policy-pass.png");
}
function fetchResourceWithNoPolicy(subdomain) {
const url = getURLForResourceWithNoPolicy(subdomain);
return fetch(url, {mode: "no-cors"});
}
/*
* Fetches a resource that doesn't exist. This may or may not generate a NEL
* report, depending on whether you've already successfully requested a resource
* from the same origin that included a NEL policy.
*/
function getURLForMissingResource(subdomain) {
return _getNELResourceURL(subdomain, "nonexistent.png");
}
function fetchMissingResource(subdomain) {
const url = getURLForMissingResource(subdomain);
return fetch(url, {mode: "no-cors"});
}
/*
* Fetches resources that clear out any existing Reporting or NEL configurations
* for all origins that any test case might use.
*/
function getURLForClearingConfiguration(subdomain) {
return _getNELResourceURL(subdomain, "clear-pass.png?id="+reportID);
}
async function clearReportingAndNELConfigurations(subdomain) {
await Promise.all([
fetch(getURLForClearingConfiguration(""), {mode: "no-cors"}),
fetch(getURLForClearingConfiguration("www"), {mode: "no-cors"}),
fetch(getURLForClearingConfiguration("www1"), {mode: "no-cors"}),
fetch(getURLForClearingConfiguration("www2"), {mode: "no-cors"}),
]);
return;
}
/*
* Returns whether all of the fields in obj1 also exist in obj2 with the same
* values. (Put another way, returns whether obj1 and obj2 are equal, ignoring
* any extra fields in obj2.)
*/
function _isSubsetOf(obj1, obj2) {
for (const prop in obj1) {
if (typeof obj1[prop] === 'object') {
if (typeof obj2[prop] !== 'object') {
return false;
}
if (!_isSubsetOf(obj1[prop], obj2[prop])) {
return false;
}
} else if (obj1[prop] != obj2[prop]) {
return false;
}
}
return true;
}
/*
* Verifies that a report was uploaded that contains all of the fields in
* expected.
*/
async function reportExists(expected) {
var timeout =
document.querySelector("meta[name=timeout][content=long]") ? 50 : 1;
var reportLocation =
"/network-error-logging/support/report.py?op=retrieve_report&timeout=" +
timeout + "&reportID=" + reportID;
const response = await fetch(reportLocation);
const json = await response.json();
for (const report of json) {
if (_isSubsetOf(expected, report)) {
return true;
}
}
return false;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,6 @@
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Cache-Control: post-check=0, pre-check=0, false
Pragma: no-cache
Report-To: { "group": "nel-group", "max_age": 10886400, "endpoints": [{ "url": "https://{{hosts[][www]}}:{{ports[https][0]}}/network-error-logging/support/report.py?op=put&reportID={{GET[id]}}" }] }
NEL: {"report_to": "nel-group", "max_age": 10886400, "success_fraction": 1.0}

View file

@ -0,0 +1,52 @@
import time
import json
import re
def retrieve_from_stash(request, key, timeout, default_value):
t0 = time.time()
while time.time() - t0 < timeout:
time.sleep(0.5)
value = request.server.stash.take(key=key)
if value is not None:
return json.dumps(value)
return default_value
def main(request, response):
# Handle CORS preflight requests
if request.method == 'OPTIONS':
# Always reject preflights for one subdomain
if "www2" in request.headers["Origin"]:
return (400, [], "CORS preflight rejected for www2")
return [
("Content-Type", "text/plain"),
("Access-Control-Allow-Origin", "*"),
("Access-Control-Allow-Methods", "post"),
("Access-Control-Allow-Headers", "Content-Type"),
], "CORS allowed"
op = request.GET.first("op");
key = request.GET.first("reportID")
if op == "retrieve_report":
try:
timeout = float(request.GET.first("timeout"))
except:
timeout = 0.5
return [("Content-Type", "application/json")], retrieve_from_stash(request, key, timeout, '[]')
# append new reports
new_reports = json.loads(request.body)
for report in new_reports:
report["metadata"] = {
"content_type": request.headers["Content-Type"],
}
with request.server.stash.lock:
reports = request.server.stash.take(key=key)
if reports is None:
reports = []
reports.extend(new_reports)
request.server.stash.put(key=key, value=reports)
# return acknowledgement report
return [("Content-Type", "text/plain")], "Recorded report"

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,6 @@
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Cache-Control: post-check=0, pre-check=0, false
Pragma: no-cache
Report-To: { "group": "nel-group", "max_age": 10886400, "include_subdomains": true, "endpoints": [{ "url": "https://{{hosts[][www]}}:{{ports[https][0]}}/network-error-logging/support/report.py?op=put&reportID={{GET[id]}}" }] }
NEL: {"report_to": "nel-group", "max_age": 10886400, "include_subdomains": true, "success_fraction": 1.0}

View file

@ -0,0 +1,25 @@
def main(request, response):
if "clear-vary-value-override-cookie" in request.GET:
response.unset_cookie("vary-value-override")
return "vary cookie cleared"
set_cookie_vary = request.GET.first("set-vary-value-override-cookie",
default="")
if set_cookie_vary:
response.set_cookie("vary-value-override", set_cookie_vary)
return "vary cookie set"
# If there is a vary-value-override cookie set, then use its value
# for the VARY header no matter what the query string is set to. This
# override is necessary to test the case when two URLs are identical
# (including query), but differ by VARY header.
cookie_vary = request.cookies.get("vary-value-override");
if cookie_vary:
response.headers.set("vary", cookie_vary)
else:
# If there is no cookie, then use the query string value, if present.
query_vary = request.GET.first("vary", default="")
if query_vary:
response.headers.set("vary", query_vary)
return "vary response"

View file

@ -267,4 +267,84 @@ cache_test(function(cache, test) {
'twice.');
}, 'Cache.addAll called with the same Request object specified twice');
cache_test(async function(cache, test) {
const url = '../resources/vary.py?vary=x-shape';
let requests = [
new Request(url, { headers: { 'x-shape': 'circle' }}),
new Request(url, { headers: { 'x-shape': 'square' }}),
];
let result = await cache.addAll(requests);
assert_equals(result, undefined, 'Cache.addAll() should succeed');
}, 'Cache.addAll should succeed when entries differ by vary header');
cache_test(async function(cache, test) {
const url = '../resources/vary.py?vary=x-shape';
let requests = [
new Request(url, { headers: { 'x-shape': 'circle' }}),
new Request(url, { headers: { 'x-shape': 'circle' }}),
];
await promise_rejects(
test,
'InvalidStateError',
cache.addAll(requests),
'Cache.addAll() should reject when entries are duplicate by vary header');
}, 'Cache.addAll should reject when entries are duplicate by vary header');
// VARY header matching is asymmetric. Determining if two entries are duplicate
// depends on which entry's response is used in the comparison. The target
// response's VARY header determines what request headers are examined. This
// test verifies that Cache.addAll() duplicate checking handles this asymmetric
// behavior correctly.
cache_test(async function(cache, test) {
const base_url = '../resources/vary.py';
// Define a request URL that sets a VARY header in the
// query string to be echoed back by the server.
const url = base_url + '?vary=x-size';
// Set a cookie to override the VARY header of the response
// when the request is made with credentials. This will
// take precedence over the query string vary param. This
// is a bit confusing, but it's necessary to construct a test
// where the URL is the same, but the VARY headers differ.
//
// Note, the test could also pass this information in additional
// request headers. If the cookie approach becomes too unwieldy
// this test could be rewritten to use that technique.
await fetch(base_url + '?set-vary-value-override-cookie=x-shape');
test.add_cleanup(_ => fetch(base_url + '?clear-vary-value-override-cookie'));
let requests = [
// This request will result in a Response with a "Vary: x-shape"
// header. This *will not* result in a duplicate match with the
// other entry.
new Request(url, { headers: { 'x-shape': 'circle',
'x-size': 'big' },
credentials: 'same-origin' }),
// This request will result in a Response with a "Vary: x-size"
// header. This *will* result in a duplicate match with the other
// entry.
new Request(url, { headers: { 'x-shape': 'square',
'x-size': 'big' },
credentials: 'omit' }),
];
await promise_rejects(
test,
'InvalidStateError',
cache.addAll(requests),
'Cache.addAll() should reject when one entry has a vary header ' +
'matching an earlier entry.');
// Test the reverse order now.
await promise_rejects(
test,
'InvalidStateError',
cache.addAll(requests.reverse()),
'Cache.addAll() should reject when one entry has a vary header ' +
'matching a later entry.');
}, 'Cache.addAll should reject when one entry has a vary header ' +
'matching another entry');
done();

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<body>
<script>
async_test(t => {
createHTML_policy(window)
.then(t.step_func_done(p => {
let html = p.createHTML(INPUTS.HTML);
let parser = new DOMParser();
let doc = parser.parseFromString(html, "text/html");
assert_equals(doc.body.innerText, RESULTS.HTML);
}));
}, "document.innerText assigned via policy (successful HTML transformation).");
test(t => {
var parser = new DOMParser();
var doc = parser.parseFromString(null, "text/html");
assert_equals(doc.body.innerText, "null");
}, "document.innerText = null.");
</script>

View file

@ -1,41 +0,0 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<meta http-equiv="Content-Security-Policy" content="require-trusted-types">
<body>
<script>
//HTML assignments don't throw
test(t => {
var html = TrustedHTML.escape(STRINGS.unescapedHTML);
var parser = new DOMParser();
var doc = parser.parseFromString(html, "text/html");
assert_equals(doc.body.innerText, STRINGS.unescapedHTML);
}, "innerTextOfDoc = TrustedHTML.escape().");
test(t => {
var html = TrustedHTML.unsafelyCreate(STRINGS.unescapedHTML);
var parser = new DOMParser();
var doc = parser.parseFromString(html, "text/html");
assert_equals(doc.body.innerText, STRINGS.unescapedText);
}, "innerTextOfDoc = TrustedHTML.unsafelyCreate().");
//Null assignment throws
test(t => {
var parser = new DOMParser();
assert_throws(new TypeError(), _ => {
var doc = parser.parseFromString(null, "text/html");
});
}, "'innerTextOfDoc = null' throws");
// String assignments throw.
test(t => {
var parser = new DOMParser();
assert_throws(new TypeError(), _ => {
var doc = parser.parseFromString("Fail", "text/html");
});
}, "`innerTextOfDoc = string` throws.");
</script>

View file

@ -1,28 +0,0 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<body>
<script>
test(t => {
var html = TrustedHTML.escape(STRINGS.unescapedHTML);
var parser = new DOMParser();
var doc = parser.parseFromString(html, "text/html");
assert_equals(doc.body.innerText, STRINGS.unescapedHTML);
}, "innerTextOfDoc = TrustedHTML.escape().");
test(t => {
var html = TrustedHTML.unsafelyCreate(STRINGS.unescapedHTML);
var parser = new DOMParser();
var doc = parser.parseFromString(html, "text/html");
assert_equals(doc.body.innerText, STRINGS.unescapedText);
}, "innerTextOfDoc = TrustedHTML.unsafelyCreate().");
test(t => {
var parser = new DOMParser();
var doc = parser.parseFromString(null, "text/html");
assert_equals(doc.body.innerText, "null");
}, "innerTextOfDoc = null.");
</script>

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<body>
<script>
async_test(t => {
createHTML_policy(window)
.then(t.step_func_done(p => {
let html = p.createHTML(INPUTS.HTML);
document.write(html);
assert_equals(document.body.innerText, RESULTS.HTML);
}));
}, "document.write with html assigned via policy (successful URL transformation).");
</script>

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<body>
<div id="container"></div>
<script>
var container = document.querySelector('#container');
async_test(t => {
createHTML_policy(window)
.then(t.step_func_done(p => {
let html = p.createHTML(INPUTS.HTML);
var d = document.createElement('div');
container.appendChild(d);
d.insertAdjacentHTML('beforebegin', html);
assert_equals(d.previousSibling.nodeType, Node.TEXT_NODE);
assert_equals(d.previousSibling.data, RESULTS.HTML);
d.insertAdjacentHTML('afterbegin', html);
assert_equals(d.firstChild.nodeType, Node.TEXT_NODE);
assert_equals(d.firstChild.data, RESULTS.HTML);
d.insertAdjacentHTML('beforeend', html);
assert_equals(d.lastChild.nodeType, Node.TEXT_NODE);
assert_equals(d.lastChild.data, RESULTS.HTML);
d.insertAdjacentHTML('afterend', html);
assert_equals(d.nextSibling.nodeType, Node.TEXT_NODE);
assert_equals(d.nextSibling.data, RESULTS.HTML);
while (container.firstChild)
container.firstChild.remove();
}));
}, "insertAdjacentHTML with html assigned via policy (successful HTML transformation).");
</script>

View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<body>
<div id="container"></div>
<script>
var container = document.querySelector('#container')
async_test(t => {
createHTML_policy(window)
.then(t.step_func_done(p => {
let html = p.createHTML(INPUTS.HTML);
var d = document.createElement('div');
document.querySelector('#container').appendChild(d);
d.outerHTML = html;
assert_equals(container.innerText, RESULTS.HTML);
while (container.firstChild)
container.firstChild.remove();
}));
}, "outerHTML with html assigned via policy (successful HTML transformation).");
</script>

View file

@ -24,9 +24,9 @@
];
testCases.forEach(c => {
test(t => {
assert_accepts_trusted_url(c[0], c[1]);
}, c[0] + "." + c[1] + " accepts TrustedURL");
async_test(t => {
assert_element_accepts_trusted_url(window, t, c[0], c[1], RESULTS.URL);
}, c[0] + "." + c[1] + " assigned via policy (successful URL transformation)");
});
// TrustedScriptURL Assignments
@ -36,8 +36,20 @@
];
scriptTestCases.forEach(c => {
test(t => {
assert_accepts_trusted_script_url(c[0], c[1]);
}, c[0] + "." + c[1] + " accepts TrustedScriptURL");
async_test(t => {
assert_element_accepts_trusted_script_url(window, t, c[0], c[1], RESULTS.SCRIPTURL);
}, c[0] + "." + c[1] + " assigned via policy (successful ScriptURL transformation)");
});
// TrustedHTML Assignments
let HTMLTestCases = [
[ 'div', 'innerHTML' ],
[ 'iframe', 'srcdoc' ]
];
HTMLTestCases.forEach(c => {
async_test(t => {
assert_element_accepts_trusted_html(window, t, c[0], c[1], RESULTS.HTML);
}, c[0] + "." + c[1] + " assigned via policy (successful HTML transformation)");
});
</script>

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<body>
<script>
async_test(t => {
createURL_policy(window)
.then(t.step_func_done(p => {
let url = p.createURL(location.href + "#xxx");
location.assign(url);
assert_equals("" + url, location.href, "location href");
}));
}, "location.assign via policy (successful URL transformation).");
</script>

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<body>
<script>
async_test(t => {
createURL_policy(window)
.then(t.step_func_done(p => {
let url = p.createURL(location.href + "#xxx");
location.href = url;
assert_equals("" + url, location.href, "location href");
}));
}, "location.href assigned via policy (successful URL transformation).");
</script>

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<body>
<script>
async_test(t => {
createURL_policy(window)
.then(t.step_func_done(p => {
let url = p.createURL(location.href + "#xxx");
location.replace(url);
assert_equals("" + url, location.href, "location href");
}));
}, "location.replace via policy (successful URL transformation).");
</script>

View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<body>
<script>
async_test(t => {
createHTML_policy(window)
.then(t.step_func_done(p => {
let html = p.createHTML(INPUTS.HTML);
var range = document.createRange();
range.selectNodeContents(document.documentElement);
var result = range.createContextualFragment(html);
assert_equals(result.textContent, RESULTS.HTML);
}));
}, "range.createContextualFragment assigned via policy (successful HTML transformation).");
</script>

View file

@ -1,17 +0,0 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<script>
test(t => {
var html = TrustedHTML.escape(STRINGS.unescapedHTML);
assert_equals(html.toString(), STRINGS.escapedHTML);
}, "Basic escaping.");
test(t => {
var html = TrustedHTML.unsafelyCreate(STRINGS.unescapedHTML);
assert_equals(html.toString(), STRINGS.unescapedHTML);
}, "Basic unsafe construction.");
</script>

View file

@ -1,23 +0,0 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<script>
test(t => {
var url = TrustedScriptURL.unsafelyCreate(URLS.safe);
assert_equals(url.toString(), URLS.safe);
}, "Basic processing: safe URL, unsafe construction.");
test(t => {
var url = TrustedScriptURL.unsafelyCreate(URLS.javascript);
assert_equals(url.toString(), URLS.javascript);
}, "Basic processing: javascript URL, unsafe construction.");
test(t => {
var url = TrustedScriptURL.unsafelyCreate(URLS.external);
assert_equals(url.toString(), URLS.external);
}, "Basic processing: external protocol URL, unsafe construction.");
</script>

View file

@ -4,11 +4,296 @@
<script src="support/helper.sub.js"></script>
<body>
<script>
//Policy name test
async_test(t => {
var policy = window.trustedTypes.createPolicy('SomeName')
window.trustedTypes.createPolicy('SomeName', { createHTML: s => s } )
.then(t.step_func_done(policy => {
assert_true(policy instanceof TrustedTypePolicy);
assert_equals(policy.name, 'SomeName');
}));
}, "policy.name = name");
//HTML tests
function createHTMLTest(policy, expectedHTML, t) {
window.trustedTypes.createPolicy('SomeName', policy)
.then(t.step_func_done(p => {
assert_true(p.createHTML('whatever') instanceof TrustedHTML);
assert_equals(p.createHTML('whatever') + "", expectedHTML);
}));
}
async_test(t => {
createHTMLTest( { createHTML: s => s }, 'whatever', t);
}, "html = identity function");
async_test(t => {
createHTMLTest( { createHTML: s => null }, "null", t);
}, "html = null");
var HTMLstr = 'well, ';
async_test(t => {
createHTMLTest( { createHTML: s => HTMLstr + s }, HTMLstr + 'whatever', t);
}, "html = string + global string");
var HTMLx = 'global';
async_test(t => {
window.trustedTypes.createPolicy('SomeName', {
createHTML: s => { HTMLx = s; return s; }
})
.then(t.step_func_done(p => {
assert_true(p.createHTML('whatever') instanceof TrustedHTML);
assert_equals(p.createHTML('whatever') + "", 'whatever');
assert_equals(HTMLx, 'whatever');
}));
}, "html = identity function, global string changed");
async_test(t => {
window.trustedTypes.createPolicy('SomeName', {
createHTML: s => { throw new Error(); }
})
.then(t.step_func_done(p => {
assert_throws(new Error(), _ => {
p.createHTML('whatever');
});
}));
}, "html = callback that throws");
var obj = {
"foo": "well,"
}
function getHTML(s) {
return this.foo + " " + s;
}
async_test(t => {
createHTMLTest( {
createHTML: getHTML.bind(obj)},
'well, whatever', t);
}, "html = this bound to an object");
var foo = "well,";
async_test(t => {
createHTMLTest( { createHTML: s => getHTML(s) }, 'well, whatever', t);
}, "html = this without bind");
async_test(t => {
window.trustedTypes.createPolicy('SomeName', null)
.then(t.step_func_done(p => {
assert_equals(p.createHTML('whatever'), null);
}));
}, "html - calling undefined callback");
//Script tests
function createScriptTest(policy, expectedScript, t) {
let p = window.trustedTypes.createPolicy('SomeName', policy)
.then(t.step_func_done(p => {
assert_true(p.createScript('whatever') instanceof TrustedScript);
assert_equals(p.createScript('whatever') + "", expectedScript);
}));
}
async_test(t => {
createScriptTest( { createScript: s => s }, 'whatever', t);
}, "script = identity function");
async_test(t => {
createScriptTest( { createScript: s => null }, "null", t);
}, "script = null");
var Scriptstr = 'well, ';
async_test(t => {
createScriptTest( { createScript: s => Scriptstr + s }, Scriptstr + 'whatever', t);
}, "script = string + global string");
var Scriptx = 'global';
async_test(t => {
let p = window.trustedTypes.createPolicy('SomeName', {
createScript: s => { Scriptx = s; return s; }
})
.then(t.step_func_done(p => {
assert_true(p.createScript('whatever') instanceof TrustedScript);
assert_equals(p.createScript('whatever') + "", 'whatever');
assert_equals(Scriptx, 'whatever');
}));
}, "script = identity function, global string changed");
async_test(t => {
let p = window.trustedTypes.createPolicy('SomeName', {
createScript: s => { throw new Error(); }
})
.then(t.step_func_done(p => {
assert_throws(new Error(), _ => {
p.createScript('whatever');
});
}));
}, "script = callback that throws");
var obj = {
"foo": "well,"
}
function getScript(s) {
return this.foo + " " + s;
}
async_test(t => {
createScriptTest( {
createScript: getScript.bind(obj)},
'well, whatever', t);
}, "script = this bound to an object");
var foo = "well,";
async_test(t => {
createScriptTest( { createScript: s => getScript(s) }, 'well, whatever', t);
}, "script = this without bind");
async_test(t => {
let p = window.trustedTypes.createPolicy('SomeName', null)
.then(t.step_func_done(p => {
assert_equals(p.createScript('whatever'), null);
}));
}, "script - calling undefined callback");
//ScriptURL tests
function createScriptURLTest(policy, expectedScriptURL, t) {
window.trustedTypes.createPolicy('SomeName', policy)
.then(t.step_func_done(p => {
assert_true(p.createScriptURL(INPUTS.SCRIPTURL) instanceof TrustedScriptURL);
assert_equals(p.createScriptURL(INPUTS.SCRIPTURL) + "", expectedScriptURL);
}));
}
async_test(t => {
createScriptURLTest( { createScriptURL: s => s }, INPUTS.SCRIPTURL, t);
}, "script_url = identity function");
async_test(t => {
createScriptURLTest( { createScriptURL: s => null }, "", t);
}, "script_url = null");
var scriptURLstr = '#duck';
async_test(t => {
createScriptURLTest( { createScriptURL: s => s + scriptURLstr }, INPUTS.SCRIPTURL + scriptURLstr, t);
}, "script_url = string + global string");
var scriptURLx = 'global';
async_test(t => {
window.trustedTypes.createPolicy('SomeName', {
createScriptURL: s => { ScriptURLx = s; return s; }
})
.then(t.step_func_done(p => {
assert_true(p.createScriptURL(INPUTS.SCRIPTURL) instanceof TrustedScriptURL);
assert_equals(p.createScriptURL(INPUTS.SCRIPTURL) + "", INPUTS.SCRIPTURL);
assert_equals(ScriptURLx, INPUTS.SCRIPTURL);
}));
}, "script_url = identity function, global string changed");
async_test(t => {
window.trustedTypes.createPolicy('SomeName', {
createScriptURL: s => { throw new Error(); }
})
.then(t.step_func_done(p => {
assert_throws(new Error(), _ => {
p.createScriptURL(INPUTS.SCRIPTURL);
});
}));
}, "script_url = callback that throws");
function getScriptURL(s) {
return s + this.baz;
}
var obj = {
"baz": "#duck"
}
async_test(t => {
createScriptURLTest( {
createScriptURL: getScriptURL.bind(obj)},
INPUTS.SCRIPTURL + "#duck", t);
}, "script_url = this bound to an object");
var baz = "#duck";
async_test(t => {
createScriptURLTest( { createScriptURL: s => getScriptURL(s) }, INPUTS.SCRIPTURL + baz, t);
}, "script_url = this without bind");
async_test(t => {
window.trustedTypes.createPolicy('SomeName', null)
.then(t.step_func_done(p => {
assert_equals(p.createScriptURL(INPUTS.SCRIPTURL), null);
}));
}, "script_url - calling undefined callback");
//URL tests
function createURLTest(policy, expectedURL, t) {
window.trustedTypes.createPolicy('SomeName', policy)
.then(t.step_func_done(p => {
assert_true(p.createURL(INPUTS.URL) instanceof TrustedURL);
assert_equals(p.createURL(INPUTS.URL) + "", expectedURL);
}));
}
async_test(t => {
createURLTest( { createURL: s => s }, INPUTS.URL, t);
}, "url = identity function");
async_test(t => {
createURLTest( { createURL: s => null }, "", t);
}, "url = null");
var URLstr = '#x';
async_test(t => {
createURLTest( { createURL: s => s + URLstr }, INPUTS.URL + URLstr, t);
}, "url = string + global string");
var URLx = 'global';
async_test(t => {
window.trustedTypes.createPolicy('SomeName', {
createURL: s => { URLx = s; return s; }
})
.then(t.step_func_done(p => {
assert_true(p.createURL(INPUTS.URL) instanceof TrustedURL);
assert_equals(p.createURL(INPUTS.URL) + "", INPUTS.URL);
assert_equals(URLx, INPUTS.URL);
}));
}, "url = identity function, global string changed");
async_test(t => {
window.trustedTypes.createPolicy('SomeName', {
createURL: s => { throw new Error(); }
})
.then(t.step_func_done(p => {
assert_throws(new Error(), _ => {
p.createURL(INPUTS.URL);
});
}));
}, "url = callback that throws");
function getURL(s) {
return s + this.bar;
}
var obj = {
"bar": "#x"
}
async_test(t => {
createURLTest( {
createURL: getURL.bind(obj)},
INPUTS.URL + "#x", t);
}, "url = this bound to an object");
var bar = "#x";
async_test(t => {
createURLTest( { createURL: s => getURL(s) }, INPUTS.URL + bar, t);
}, "url = this without bind");
async_test(t => {
window.trustedTypes.createPolicy('SomeName', null)
.then(t.step_func_done(p => {
assert_equals(p.createURL(INPUTS.URL), null);
}));
}, "url - calling undefined callback");
</script>

View file

@ -1,41 +0,0 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<script>
test(t => {
var url = TrustedURL.create(URLS.safe);
assert_equals(url.toString(), URLS.safe);
}, "Basic processing: safe URL, safe construction.");
test(t => {
var url = TrustedURL.unsafelyCreate(URLS.safe);
assert_equals(url.toString(), URLS.safe);
}, "Basic processing: safe URL, unsafe construction.");
test(t => {
var url = TrustedURL.create(URLS.javascript);
assert_equals(url.toString(), URLS.sanitized);
}, "Basic processing: javascript URL, safe construction.");
test(t => {
var url = TrustedURL.unsafelyCreate(URLS.javascript);
assert_equals(url.toString(), URLS.javascript);
}, "Basic processing: javascript URL, unsafe construction.");
test(t => {
var url = TrustedURL.create(URLS.external);
assert_equals(url.toString(), URLS.sanitized);
}, "Basic processing: external protocol URL, safe construction.");
test(t => {
var url = TrustedURL.unsafelyCreate(URLS.external);
assert_equals(url.toString(), URLS.external);
}, "Basic processing: external protocol URL, unsafe construction.");
</script>

View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<body>
<script>
// helper functions for the tests
function testWindowOpen(t, win) {
createURL_policy(window)
.then(t.step_func_done(p => {
let url = p.createURL(INPUTS.URL);
let child_window = win.open(url, "", "");
child_window.onload = t.step_func_done(_ => {
assert_equals(child_window.location.href, "" + url);
child_window.close();
});
}));
}
async_test(t => {
testWindowOpen(t, window);
}, "window.open via policy (successful URL transformation).");
async_test(t => {
testWindowOpen(t, document);
}, "document.open via policy (successful URL transformation).");
</script>

View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<meta http-equiv="Content-Security-Policy" content="require-trusted-types">
<body>
<script>
// Trusted HTML assignments do not throw.
async_test(t => {
createHTML_policy(window)
.then(t.step_func_done(p => {
let html = p.createHTML(INPUTS.HTML);
let parser = new DOMParser();
let doc = parser.parseFromString(html, "text/html");
assert_equals(doc.body.innerText, RESULTS.HTML);
}));
}, "document.innerText assigned via policy (successful HTML transformation).");
// String assignments throw.
test(t => {
var parser = new DOMParser();
assert_throws(new TypeError(), _ => {
var doc = parser.parseFromString("Fail", "text/html");
});
}, "`document.innerText = string` throws.");
// Null assignment throws.
test(t => {
var parser = new DOMParser();
assert_throws(new TypeError(), _ => {
var doc = parser.parseFromString(null, "text/html");
});
}, "'document.innerText = null' throws");
</script>

View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<meta http-equiv="Content-Security-Policy" content="require-trusted-types">
</head>
<body>
<script>
// TrustedURL assignments do not throw.
async_test(t => {
createHTML_policy(window)
.then(t.step_func_done(p => {
let html = p.createHTML(INPUTS.HTML);
document.write(html);
assert_equals(document.body.innerText, RESULTS.HTML);
}));
}, "document.write with html assigned via policy (successful URL transformation).");
// String assignments throw.
test(t => {
assert_throws(new TypeError(), _ => {
document.write('A string');
});
}, "`document.write(string)` throws");
// Null assignment throws.
test(t => {
assert_throws(new TypeError(), _ => {
document.write(null);
});
}, "`document.write(null)` throws");
</script>

View file

@ -0,0 +1,97 @@
<!DOCTYPE html>
<html>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<meta http-equiv="Content-Security-Policy" content="require-trusted-types">
</head>
<body>
<div id="container"></div>
<script>
var container = document.querySelector('#container');
// Trusted HTML assignments do not throw.
async_test(t => {
createHTML_policy(window)
.then(t.step_func_done(p => {
let html = p.createHTML(INPUTS.HTML);
var d = document.createElement('div');
container.appendChild(d);
d.insertAdjacentHTML('beforebegin', html);
assert_equals(d.previousSibling.nodeType, Node.TEXT_NODE);
assert_equals(d.previousSibling.data, RESULTS.HTML);
d.insertAdjacentHTML('afterbegin', html);
assert_equals(d.firstChild.nodeType, Node.TEXT_NODE);
assert_equals(d.firstChild.data, RESULTS.HTML);
d.insertAdjacentHTML('beforeend', html);
assert_equals(d.lastChild.nodeType, Node.TEXT_NODE);
assert_equals(d.lastChild.data, RESULTS.HTML);
d.insertAdjacentHTML('afterend', html);
assert_equals(d.nextSibling.nodeType, Node.TEXT_NODE);
assert_equals(d.nextSibling.data, RESULTS.HTML);
while (container.firstChild)
container.firstChild.remove();
}));
}, "insertAdjacentHTML with html assigned via policy (successful HTML transformation).");
// String assignments throw.
test(t => {
var d = document.createElement('div');
container.appendChild(d);
assert_throws(new TypeError(), _ => {
d.insertAdjacentHTML('beforebegin', "<p>Fail</p>");
});
assert_throws(new TypeError(), _ => {
d.insertAdjacentHTML('afterbegin', "<p>Fail</p>");
});
assert_throws(new TypeError(), _ => {
d.insertAdjacentHTML('beforeend', "<p>Fail</p>");
});
assert_throws(new TypeError(), _ => {
d.insertAdjacentHTML('afterend', "<p>Fail</p>");
});
assert_equals(d.previousSibling, null);
assert_equals(d.firstChild, null);
assert_equals(d.lastChild, null);
assert_equals(d.nextSibling, null);
while (container.firstChild)
container.firstChild.remove();
}, "`insertAdjacentHTML(string)` throws.");
// Null assignment throws.
test(t => {
var d = document.createElement('div');
container.appendChild(d);
assert_throws(new TypeError(), _ => {
d.insertAdjacentHTML('beforebegin', null);
});
assert_throws(new TypeError(), _ => {
d.insertAdjacentHTML('afterbegin', null);
});
assert_throws(new TypeError(), _ => {
d.insertAdjacentHTML('beforeend', null);
});
assert_throws(new TypeError(), _ => {
d.insertAdjacentHTML('afterend', null);
});
assert_equals(d.previousSibling, null);
assert_equals(d.firstChild, null);
assert_equals(d.lastChild, null);
assert_equals(d.nextSibling, null);
}, "`insertAdjacentHTML(null)` throws.");
</script>
</body>
</html>

View file

@ -12,6 +12,22 @@
<script>
var container = document.querySelector('#container')
// TrustedHTML assignments do not throw.
async_test(t => {
createHTML_policy(window)
.then(t.step_func_done(p => {
let html = p.createHTML(INPUTS.HTML);
var d = document.createElement('div');
document.querySelector('#container').appendChild(d);
d.outerHTML = html;
assert_equals(container.innerText, RESULTS.HTML);
while (container.firstChild)
container.firstChild.remove();
}));
}, "outerHTML with html assigned via policy (successful HTML transformation).");
// String assignments throw.
test(t => {
var d = document.createElement('div');
@ -24,30 +40,17 @@
container.firstChild.remove();
}, "`outerHTML = string` throws.");
// TrustedHTML assignments work.
// Null assignment throws.
test(t => {
var html = TrustedHTML.escape(STRINGS.unescapedHTML);
var d = document.createElement('div');
document.querySelector('#container').appendChild(d);
d.outerHTML = html;
assert_equals(container.innerText, STRINGS.unescapedHTML);
while (container.firstChild)
container.firstChild.remove();
}, "outerHTML = TrustedHTML.escape().");
test(t => {
var html = TrustedHTML.unsafelyCreate(STRINGS.unescapedHTML);
var d = document.createElement('div');
container.appendChild(d);
d.outerHTML = html;
assert_equals(container.innerText, STRINGS.unescapedText);
assert_throws(new TypeError(), _ => {
d.outerHTML = null;
});
assert_equals(container.innerText, "");
while (container.firstChild)
container.firstChild.remove();
}, "outerHTML = TrustedHTML.unsafelyCreate().");
}, "`outerHTML = null` throws.");
</script>
</body>
</html>

View file

@ -27,11 +27,11 @@
];
testCases.forEach(c => {
test(t => {
assert_accepts_trusted_url(c[0], c[1]);
async_test(t => {
assert_element_accepts_trusted_url(window, t, c[0], c[1], RESULTS.URL);
assert_throws_no_trusted_type(c[0], c[1], 'A string');
assert_throws_no_trusted_type(c[0], c[1], null);
}, c[0] + "." + c[1] + " accepts TrustedURL");
}, c[0] + "." + c[1] + " accepts only TrustedURL");
});
// TrustedScriptURL Assignments
@ -41,10 +41,24 @@
];
scriptTestCases.forEach(c => {
test(t => {
assert_accepts_trusted_script_url(c[0], c[1]);
async_test(t => {
assert_element_accepts_trusted_script_url(window, t, c[0], c[1], RESULTS.SCRIPTURL);
assert_throws_no_trusted_type(c[0], c[1], 'A string');
assert_throws_no_trusted_type(c[0], c[1], null);
}, c[0] + "." + c[1] + " accepts TrustedScriptURL");
}, c[0] + "." + c[1] + " accepts only TrustedScriptURL");
});
// TrustedHTML Assignments
let HTMLTestCases = [
[ 'div', 'innerHTML' ],
[ 'iframe', 'srcdoc' ]
];
HTMLTestCases.forEach(c => {
async_test(t => {
assert_element_accepts_trusted_html(window, t, c[0], c[1], RESULTS.HTML);
assert_throws_no_trusted_type(c[0], c[1], 'A string');
assert_throws_no_trusted_type(c[0], c[1], null);
}, c[0] + "." + c[1] + " accepts only TrustedHTML");
});
</script>

View file

@ -9,18 +9,15 @@
</head>
<body>
<script>
//TrustedURL assignments work
test(t => {
var url = TrustedURL.create(location.href + "#xxx");
// TrustedURL assignments do not throw.
async_test(t => {
createURL_policy(window)
.then(t.step_func_done(p => {
let url = p.createURL(location.href + "#xxx");
location.assign(url);
assert_equals("" + url, location.href, "location href");
}, "Basic processing: safe URL, safe construction.");
test(t => {
var url = TrustedURL.unsafelyCreate(location.href + "#xxx");
location.assign(url);
assert_equals("" + url, location.href, "location href");
}, "Basic processing: safe URL, unsafe construction.");
}));
}, "location.assign via policy (successful URL transformation).");
// String assignments throw.
test(t => {
@ -29,7 +26,7 @@
});
}, "`location.assign = string` throws");
//Null assignment throws
// Null assignment throws.
test(t => {
assert_throws(new TypeError(), _ => {
location.assign(null);

View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<meta http-equiv="Content-Security-Policy" content="require-trusted-types">
</head>
<body>
<script>
// TrustedURL assignments do not throw.
async_test(t => {
createURL_policy(window)
.then(t.step_func_done(p => {
let url = p.createURL(location.href + "#xxx");
location.href = url;
assert_equals("" + url, location.href, "location href");
}));
}, "location.href assigned via policy (successful URL transformation).");
// String assignments throw.
test(t => {
assert_throws(new TypeError(), _ => {
location.href = 'A string';
});
}, "`location.href = string` throws");
// Null assignment throws.
test(t => {
assert_throws(new TypeError(), _ => {
location.href = null;
});
}, "`location.href = null` throws");
</script>

View file

@ -9,18 +9,15 @@
</head>
<body>
<script>
//TrustedURL replacements work
test(t => {
var url = TrustedURL.create(location.href + "#xxx");
// TrustedURL replacements do not throw.
async_test(t => {
createURL_policy(window)
.then(t.step_func_done(p => {
let url = p.createURL(location.href + "#xxx");
location.replace(url);
assert_equals("" + url, location.href, "location href");
}, "Basic processing: safe URL, safe construction.");
test(t => {
var url = TrustedURL.unsafelyCreate(location.href + "#xxx");
location.replace(url);
assert_equals("" + url, location.href, "location href");
}, "Basic processing: safe URL, unsafe construction.");
}));
}, "location.replace via policy (successful URL transformation).");
// String replacements throw.
test(t => {
@ -29,7 +26,7 @@
});
}, "`location.replace = string` throws");
//Null replacement throws
// Null replacement throws.
test(t => {
assert_throws(new TypeError(), _ => {
location.replace(null);

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<meta http-equiv="Content-Security-Policy" content="require-trusted-types">
<body>
<script>
// TrustedHTML assignments do not throw.
async_test(t => {
createHTML_policy(window)
.then(t.step_func_done(p => {
let html = p.createHTML(INPUTS.HTML);
var range = document.createRange();
range.selectNodeContents(document.documentElement);
var result = range.createContextualFragment(html);
assert_equals(result.textContent, RESULTS.HTML);
}));
}, "range.createContextualFragment assigned via policy (successful HTML transformation).");
// String assignments throw.
test(t => {
var range = document.createRange();
range.selectNodeContents(document.documentElement);
assert_throws(new TypeError(), _ => {
var result = range.createContextualFragment("A string");
});
}, "`range.createContextualFragment(string)` throws.");
// Null assignment throws.
test(t => {
var range = document.createRange();
range.selectNodeContents(document.documentElement);
assert_throws(new TypeError(), _ => {
var result = range.createContextualFragment(null);
});
}, "`range.createContextualFragment(null)` throws.");
</script>

View file

@ -0,0 +1,63 @@
<!DOCTYPE html>
<html>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<meta http-equiv="Content-Security-Policy" content="require-trusted-types">
</head>
<body>
<script>
// helper functions for the tests
function testWindowOpen(t, win) {
createURL_policy(window)
.then(t.step_func_done(p => {
let url = p.createURL(INPUTS.URL);
let child_window = win.open(url, "", "");
child_window.onload = t.step_func_done(_ => {
assert_equals(child_window.location.href, "" + url);
child_window.close();
});
}));
}
function testWindowThrows(t, url, win) {
createURL_policy(window)
.then(t.step_func_done(p => {
assert_throws(new TypeError(), _ => {
let child_window = win.open(url, "", "");
child_window.close();
});
}));
}
// TrustedURL assignments do not throw.
async_test(t => {
testWindowOpen(t, window);
}, "window.open via policy (successful URL transformation).");
async_test(t => {
testWindowOpen(t, document);
}, "document.open via policy (successful URL transformation).");
// String assignments throw.
async_test(t => {
testWindowThrows(t, 'A string', window);
}, "`window.open(string)` throws.");
async_test(t => {
testWindowThrows(t, 'A string', document);
}, "`document.open(string)` throws.");
// Null assignment throws.
async_test(t => {
testWindowThrows(t, null, window);
}, "`window.open(null)` throws.");
async_test(t => {
testWindowThrows(t, null, document);
}, "`document.open(null)` throws.");
</script>
</body>
</html>

View file

@ -1,43 +0,0 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<meta http-equiv="Content-Security-Policy" content="require-trusted-types">
<body>
<script>
//TrustedHTML assignments work
test(t => {
var html = TrustedHTML.escape(STRINGS.unescapedHTML);
var range = document.createRange();
range.selectNodeContents(document.documentElement);
var result = range.createContextualFragment(html);
assert_equals(result.textContent, STRINGS.unescapedHTML);
}, "DocumentFragment.textContent = TrustedHTML.escape().");
test(t => {
var html = TrustedHTML.unsafelyCreate(STRINGS.unescapedHTML);
var range = document.createRange();
range.selectNodeContents(document.documentElement);
var result = range.createContextualFragment(html);
assert_equals(result.textContent, STRINGS.unescapedText);
}, "DocumentFragment.textContent = TrustedHTML.unsafelyCreate().");
//Null assignment throws
test(t => {
var range = document.createRange();
range.selectNodeContents(document.documentElement);
assert_throws(new TypeError(), _ => {
var result = range.createContextualFragment(null);
});
}, "`DocumentFragment.textContent = null` throws.");
// String assignments throw.
test(t => {
var range = document.createRange();
range.selectNodeContents(document.documentElement);
assert_throws(new TypeError(), _ => {
var result = range.createContextualFragment("A string");
});
}, "`DocumentFragment.textContent = string` throws.");
</script>

Some files were not shown because too many files have changed in this diff Show more