diff options
Diffstat (limited to '')
7 files changed, 316 insertions, 0 deletions
diff --git a/testing/web-platform/tests/infrastructure/channels/child_message.html b/testing/web-platform/tests/infrastructure/channels/child_message.html new file mode 100644 index 0000000000..6baf47b193 --- /dev/null +++ b/testing/web-platform/tests/infrastructure/channels/child_message.html @@ -0,0 +1,13 @@ +<!doctype html> +<script src="/resources/channel.sub.js"></script> +<script> +function handleMessage(msg) { + // We expect the message to be a SendChannel + respChannel = msg; + respChannel.send("PASS"); +} + +let channel = global_channel(); +channel.addMessageHandler(handleMessage); +channel.connect(); +</script> diff --git a/testing/web-platform/tests/infrastructure/channels/child_script.html b/testing/web-platform/tests/infrastructure/channels/child_script.html new file mode 100644 index 0000000000..1c10379bde --- /dev/null +++ b/testing/web-platform/tests/infrastructure/channels/child_script.html @@ -0,0 +1,10 @@ +<!doctype html> +<script src="/resources/channel.sub.js"></script> +<div id="test">FAIL</div> +<script> +(async function() { + await new Promise(resolve => onload = resolve); + document.getElementById("test").textContent = "PASS"; + await start_global_channel(); +})() +</script> diff --git a/testing/web-platform/tests/infrastructure/channels/serialize-data.js b/testing/web-platform/tests/infrastructure/channels/serialize-data.js new file mode 100644 index 0000000000..5c423ee160 --- /dev/null +++ b/testing/web-platform/tests/infrastructure/channels/serialize-data.js @@ -0,0 +1,37 @@ +let cyclicArray = [1]; +cyclicArray.push(cyclicArray); + +let cyclicObject = {key1: "data"}; +cyclicObject.key2 = cyclicObject; + +let cyclicSet = new Set([1]); +cyclicSet.add(cyclicSet); + +let cyclicMap = new Map([["key1", 1]]); +cyclicMap.set("key2", cyclicMap); + +const objects = { + "null": {input: null}, + "undefined": {input: undefined}, + "int": {input: 1}, + "Infinity": {input: Infinity}, + "-Infinity": {input: -Infinity}, + "NaN": {input: NaN}, + "string": {input: "foo"}, + "true": {input: true}, + "false": {input: false}, + "bigint": {input: 1n}, + "RegExp": {input: /abc/g}, + "Date": {input: new Date('December 17, 1995 03:24:00')}, + "Error": {"input": new Error("message")}, + "TypeError": {"input": new TypeError("TypeError message")}, + "array": {input: [1,"foo"], output: [1, "foo"]}, + "nested array": {input: [1,[2]]}, + "set": {input: new Set([1, "foo", null])}, + "object": {input: {key1: 1, key2: false}}, + "nested object": {input: {key1: 1, key2: false}}, + "map": {input: new Map([[1, 1], ["key2", false]])}, + "cyclic array": {input: cyclicArray}, + "cyclic object": {input: cyclicObject}, + "cyclic map": {input: cyclicMap}, +}; diff --git a/testing/web-platform/tests/infrastructure/channels/serialize_child.html b/testing/web-platform/tests/infrastructure/channels/serialize_child.html new file mode 100644 index 0000000000..6ad3accfee --- /dev/null +++ b/testing/web-platform/tests/infrastructure/channels/serialize_child.html @@ -0,0 +1,173 @@ +<!doctype html> +<script src="/resources/channel.sub.js"></script> +<script src="serialize-data.js"></script> +<script> + +let lastData; + +// Hack: these will be converted into testharness AssertionError instances in the test +// This means they will be treated identically to asserts raised by `assert_` in the harness +// In the long term we want to be able to use parts of testharness.js directly in remote +// contexts and automatically send the results over a channel. +function AssertionError(message) { + this.message = message; +} +AssertionError.prototype = Object.create(Error.prototype); + +function compareResult(name, actual) { + let obj = objects[name]; + // If there's an output property use that, otherwise assume the output is equal to the input + let expected = obj.hasOwnProperty("output") ? obj.output : obj.input; + seen = new Set(); + try { + compareValue(actual, expected, seen); + } catch(e) { + throw new AssertionError(e.message); + } + return true; +} + +function compareValue(actualValue, expectedValue, seen) { + let seenActual; + if (typeof actualValue != typeof expectedValue) { + throw new Error(`Types differ, expected ${typeof expectedValue}, got ${typeof actualValue}`); + } + if (["undefined", "string", "boolean", "number", "bigint"].includes(typeof expectedValue) || + actualValue === null) { + if (!Object.is(actualValue, expectedValue)) { + throw new Error(`Expected ${typeof expected} ${expected}, got ${actual}`); + } + return; + } + + if (expectedValue.constructor && actualValue.constructor && expectedValue.constructor.name !== actualValue.constructor.name) { + throw new Error(`Constructors differ, expected ${expectedValue.constructor.name}, got ${actualValue.constructor.name}`); + } + if (expectedValue.constructor && expectedValue.constructor.name === "SendChannel") { + if (expectedValue.uuid !== actualValue.uuid) { + throw new Error(`SendChannels differ, expected uuid ${expectedValue.uuid}, got ${actualValue.uuid}`); + } + } + else if (expectedValue.constructor && expectedValue.constructor.name === "RegExp") { + if (expectedValue.source !== actualValue.source || + expectedValue.flags !== actualValue.flags) { + throw new Error(`RegExps differ, expected ${expectedValue}, got ${actualValue}`); + } + } else if (expectedValue.constructor && expectedValue.constructor.name == "Date") { + if (expectedValue.valueOf() !== actualValue.valueOf()) { + throw new Error(`Dates differ, expected ${expectedValue.valueOf()} (${expectedValue.toDateString()}), ` + `got ${actualValue.valueOf()} (${actualValue.toDateString()})`); + } + } else if (expectedValue instanceof Error) { + if (expectedValue.message !== actualValue.message || + expectedValue.lineNumber !== actualValue.lineNumber || + expectedValue.columnNumber !== actualValue.columnNumber || + expectedValue.fileName !== actualValue.fileName) { + throw new Error(`Errors differ, expected ${expectedValue}, got ${actualValue}`); + } + } else if (Array.isArray(expectedValue)) { + seenActual = seen.has(actualValue); + seenExpected = seen.has(expectedValue) + if (seenActual && seenExpected) { + return; + } else if (seenExpected && !seenActual) { + throw new Error(`Expected cyclic array`); + } else if (!seenExpected && seenActual) { + throw new Error(`Got unexpected cyclic array`); + } + seen.add(actualValue); + seen.add(expectedValue); + + if (actualValue.length !== expectedValue.length) { + throw new Error(`Array lengths differ, expected ${expectedValue.length}, got ${actualValue.length}`); + } + for (let i=0; i<actualValue.length; i++) { + compareValue(actualValue[i], expectedValue[i], seen); + } + } else if (expectedValue.constructor && expectedValue.constructor.name === "Set") { + seenActual = seen.has(actualValue); + seenExpected = seen.has(expectedValue) + if (seenActual && seenExpected) { + return; + } else if (seenExpected && !seenActual) { + throw new Error(`Expected cyclic set`); + } else if (!seenExpected && seenActual) { + throw new Error(`Got unexpected cyclic set`); + } + seen.add(actualValue); + seen.add(expectedValue); + + + if (actualValue.size !== expectedValue.size) { + throw new Error(`Set sizes differ, expected ${expectedValue.size}, got ${actualValue.size}`); + } + // For an arbitary set it's complex to check if two sets are equivalent, since + // we'd need to compare every object in one set with every object in the + // other set, so we end up with quadratic complexity. Instead, just support sets + // containing primitives and rely on the other tests for correct handling of + // objects. + for (let entry of expectedValue) { + if (["undefined", "string", "boolean", "number", "bigint"].includes(typeof entry) || entry === null) { + if(!actualValue.has(entry)) { + throw new Error(`Set missing entry, expected ${entry}`); + } + } else { + throw new Error(`Can't compare non-primitive value ${entry} inside sets`); + } + } + } else if (expectedValue.constructor && expectedValue.constructor.name === "Map") { + seenActual = seen.has(actualValue); + seenExpected = seen.has(expectedValue) + if (seenActual && seenExpected) { + return; + } else if (seenExpected && !seenActual) { + throw new Error(`Expected cyclic map`); + } else if (!seenExpected && seenActual) { + throw new Error(`Got unexpected cyclic map`); + } + seen.add(actualValue); + seen.add(expectedValue); + + if (actualValue.size !== expectedValue.size) { + throw new Error(`Map sizes differ, expected ${expectedValue.size}, got ${actualValue.size}`); + } + // So for a set we can't really check if the values are the same + // except where they're primitives + for (let [key, value] of expectedValue.entries()) { + if(!actualValue.has(key)) { + throw new Error(`Map missing key, expected key ${key} with value ${value}`); + } + compareValue(actualValue.get(key), value, seen); + } + } else { + seenActual = seen.has(actualValue); + seenExpected = seen.has(expectedValue) + if (seenActual && seenExpected) { + return; + } else if (seenExpected && !seenActual) { + throw new Error(`Expected cyclic object`); + } else if (!seenExpected && seenActual) { + throw new Error(`Got unexpected cyclic object`); + } + seen.add(actualValue); + seen.add(expectedValue); + + + // Compare as a general Object + let expectedEntries = Object.entries(expectedValue); + if (Object.keys(actualValue).length !== expectedEntries.length) { + throw new Error(`Object keys differ, expected [${Object.keys(expectedValue).join(",")}], got [${Object.keys(actualValue).join(",")}]`); + } + // So for a set we can't really check if the values are the same + // except where they're primitives + for (let [name, entry] of expectedEntries) { + if(!actualValue.hasOwnProperty(name)) { + throw new Error(`Object missing key ${name}`); + } + compareValue(actualValue[name], entry, seen); + } + } +} + +ctx = start_global_channel(); +</script> diff --git a/testing/web-platform/tests/infrastructure/channels/test_call.html b/testing/web-platform/tests/infrastructure/channels/test_call.html new file mode 100644 index 0000000000..49beaea4ff --- /dev/null +++ b/testing/web-platform/tests/infrastructure/channels/test_call.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>call method</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/channel.sub.js"></script> + +<script> +setup({single_test: true}) +onload = async () => { + let remote = await new RemoteGlobal(); + + let url = `child_script.html?uuid=${remote.uuid}`; + win = window.open(url, "_blank", "noopener"); + + let result = await remote.call(async (elemId) => { + return document.getElementById(elemId).textContent; + }, ["test"]); + assert_equals(result.trim(), "PASS"); + done(); +} +</script> diff --git a/testing/web-platform/tests/infrastructure/channels/test_postMessage.html b/testing/web-platform/tests/infrastructure/channels/test_postMessage.html new file mode 100644 index 0000000000..473c8630a6 --- /dev/null +++ b/testing/web-platform/tests/infrastructure/channels/test_postMessage.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>postMessage method</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/channel.sub.js"></script> + +<script> +setup({single_test: true}); +(async () => { + let remote = await new RemoteGlobal(); + + let url = `child_message.html?uuid=${remote.uuid}`; + win = window.open(url, "_blank", "noopener"); + + let [recvChannel, sendChannel] = channel(); + await remote.postMessage(sendChannel); + await recvChannel.connect(); + let message = await recvChannel.nextMessage(); + assert_equals(message, "PASS"); + done(); +})(); +</script> diff --git a/testing/web-platform/tests/infrastructure/channels/test_serialize.html b/testing/web-platform/tests/infrastructure/channels/test_serialize.html new file mode 100644 index 0000000000..88a9ce5221 --- /dev/null +++ b/testing/web-platform/tests/infrastructure/channels/test_serialize.html @@ -0,0 +1,38 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>object serialization</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/channel.sub.js"></script> +<script src="serialize-data.js"></script> + +<script> +setup(() => { + remote = new RemoteGlobal(); + + let url = `serialize_child.html?uuid=${remote.uuid}`; + win = window.open(url); +}); + +for (let [name, obj] of Object.entries(objects)) { + promise_test(async t => { + let result = await remote.call( + (name, inputValue) => compareResult(name, inputValue), + name, + obj.input); + assert_true(result); + }, `Serialize ${name}`); +} + +promise_test(async t => { + let remoteValue = RemoteObject.from(document.head); + let result = await remote.call(inputValue => { + if (!inputValue instanceof RemoteObject) { + throw new AssertionError(`Expected RemoteObject`); + } + return inputValue; + }, remoteValue); + assert_equals(result, document.head); +}, "Serialize RemoteObject"); + +</script> |