mirror of
https://github.com/servo/servo.git
synced 2025-06-28 19:13:41 +01:00
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:
commit
cd0e7e7ebb
140 changed files with 4328 additions and 1419 deletions
File diff suppressed because it is too large
Load diff
|
@ -1,4 +0,0 @@
|
|||
[015.html]
|
||||
[global scope unchanged]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
[no-new-global.window.html]
|
||||
[BarProp maintains its prototype and properties through open()]
|
||||
expected: FAIL
|
|
@ -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>
|
|
@ -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");
|
||||
}
|
|
@ -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}` : "";
|
||||
}
|
|
@ -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}`);
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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');
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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);
|
||||
|
|
|
@ -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.");
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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)
|
||||
|
|
31
tests/wpt/web-platform-tests/docs/_appendix/reverting.md
Normal file
31
tests/wpt/web-platform-tests/docs/_appendix/reverting.md
Normal 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
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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();
|
||||
|
|
|
@ -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()});
|
||||
|
|
|
@ -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");
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
|
@ -0,0 +1,4 @@
|
|||
<!doctype html>
|
||||
<script>
|
||||
hey = "You";
|
||||
</script>
|
|
@ -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");
|
|
@ -54,7 +54,7 @@ enum NFCPushTarget {
|
|||
|
||||
dictionary NFCWatchOptions {
|
||||
USVString url = "";
|
||||
NFCRecordType? recordType;
|
||||
NFCRecordType recordType;
|
||||
USVString mediaType = "";
|
||||
NFCWatchMode mode = "web-nfc-only";
|
||||
};
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
suggested_reviewers:
|
||||
- dcreager
|
74
tests/wpt/web-platform-tests/network-error-logging/README.md
Normal file
74
tests/wpt/web-platform-tests/network-error-logging/README.md
Normal 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.
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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 |
|
@ -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}
|
|
@ -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")
|
|
@ -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 |
|
@ -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}
|
|
@ -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 |
|
@ -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}
|
|
@ -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"
|
|
@ -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();
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
|
@ -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>
|
|
@ -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);
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue