diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /testing/web-platform/tests/longtask-timing | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/longtask-timing')
28 files changed, 976 insertions, 0 deletions
diff --git a/testing/web-platform/tests/longtask-timing/META.yml b/testing/web-platform/tests/longtask-timing/META.yml new file mode 100644 index 0000000000..357ab18b24 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/META.yml @@ -0,0 +1,4 @@ +spec: https://w3c.github.io/longtasks/ +suggested_reviewers: + - noamr + - yoavweiss diff --git a/testing/web-platform/tests/longtask-timing/buffered-flag.window.js b/testing/web-platform/tests/longtask-timing/buffered-flag.window.js new file mode 100644 index 0000000000..a0ba728ed2 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/buffered-flag.window.js @@ -0,0 +1,26 @@ +// META: script=resources/utils.js + +async_test(t => { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + new PerformanceObserver(t.step_func((entryList, obs) => { + const observer = new PerformanceObserver(t.step_func_done(list => { + let longtaskObserved = false; + list.getEntries().forEach(entry => { + if (entry.entryType === 'mark') + return; + checkLongTaskEntry(entry); + longtaskObserved = true; + }); + assert_true(longtaskObserved, 'Did not observe buffered longtask.'); + })); + observer.observe({type: 'longtask', buffered: true}); + // Observer mark so that we can flush the observer callback. + observer.observe({type: 'mark'}); + performance.mark('m'); + // Disconnect the embedding observer so this callback only runs once. + obs.disconnect(); + })).observe({entryTypes: ['longtask']}); + // Create a long task. + const begin = window.performance.now(); + while (window.performance.now() < begin + 60); +}, 'PerformanceObserver with buffered flag can see previous longtask entries.'); diff --git a/testing/web-platform/tests/longtask-timing/containerNames.html b/testing/web-platform/tests/longtask-timing/containerNames.html new file mode 100644 index 0000000000..e6a9335dc7 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/containerNames.html @@ -0,0 +1,56 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>LongTask Timing: long tasks in long-name iframe containers</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/utils.js"></script> +<h1>Longtasks in iframe</h1> +<div id="log"></div> +<script> +const longContainerName = 'iframeWithLongNameMoreThan100CharactersSpaceHolderSpaceHolderSpaceHolderSpaceHolderSpaceHolderSpaceHolder'; + +promise_test(async t => { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + const initialTime = performance.now(); + const performanceObserverTimeout = 5 * 1000; + const longTasksPromise = new Promise(resolve => { + const observer = new PerformanceObserver(t.step_func(entryList => { + const entries = entryList.getEntries(); + entries.forEach(longtask => { + assert_equals(longtask.entryType, 'longtask'); + if (hasUnrelatedTaskName(longtask.name, 'same-origin-descendant')) { + return; + } + checkLongTaskEntry(longtask, 'same-origin-descendant'); + // Assert the TaskAttributionTiming entry in attribution. + assert_equals(longtask.attribution.length, 1, + 'Exactly one attribution entry is expected'); + const attribution = longtask.attribution[0]; + assert_equals(attribution.entryType, 'taskattribution'); + assert_equals(attribution.name, 'unknown'); + assert_equals(attribution.duration, 0); + assert_equals(attribution.startTime, 0); + assert_equals(attribution.containerId, longContainerName + '-id'); + assert_equals(attribution.containerName, longContainerName + '-name'); + assert_equals(attribution.containerSrc, 'resources/subframe-with-longtask.html'); + observer.disconnect(); + resolve(); + }) + })); + observer.observe({entryTypes: ['longtask']}); + const iframe = document.createElement('iframe'); + iframe.id = longContainerName + '-id'; + iframe.name = longContainerName + '-name'; + iframe.src = 'resources/subframe-with-longtask.html'; + document.body.appendChild(iframe); + }); + const timeout = new Promise( + (resolve, reject) => t.step_timeout( + () => { reject(new Error('observer failed to find any entries')) }, + performanceObserverTimeout) + ) + return Promise.race([longTasksPromise, timeout]); +}, `Performance longtask entries in ${longContainerName} are observable in parent.`); +</script> +</body> diff --git a/testing/web-platform/tests/longtask-timing/containerTypes.html b/testing/web-platform/tests/longtask-timing/containerTypes.html new file mode 100644 index 0000000000..0e25805041 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/containerTypes.html @@ -0,0 +1,67 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>LongTask Timing: long tasks in various containers</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/utils.js"></script> +<h1>Longtasks in iframe, frame, object, and embed</h1> +<div id="log"></div> +<script> +function Container(name, src) { + this.name = name; + this.src = src; +} + +const Containers = [ + new Container('iframe', 'src'), + new Container('frame', 'src'), + new Container('object', 'data'), + new Container('embed', 'src'), +]; +Containers.forEach(container => { + promise_test(async t => { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + const initialTime = performance.now(); + const performanceObserverTimeout = 5 * 1000; + const testLongTaskEntry = new Promise(resolve => { + const observer = new PerformanceObserver(t.step_func(entryList => { + const entries = entryList.getEntries(); + entries.forEach(longtask => { + assert_equals(longtask.entryType, 'longtask'); + if (hasUnrelatedTaskName(longtask.name, 'same-origin-descendant')) { + return; + } + checkLongTaskEntry(longtask, 'same-origin-descendant'); + // Assert the TaskAttributionTiming entry in attribution. + assert_equals(longtask.attribution.length, 1, + 'Exactly one attribution entry is expected'); + const attribution = longtask.attribution[0]; + assert_equals(attribution.entryType, 'taskattribution'); + assert_equals(attribution.name, 'unknown'); + assert_equals(attribution.duration, 0); + assert_equals(attribution.startTime, 0); + assert_equals(attribution.containerId, container.name + '-id'); + assert_equals(attribution.containerName, container.name + '-name'); + assert_equals(attribution.containerSrc, 'resources/subframe-with-longtask.html'); + observer.disconnect(); + resolve(); + }); + })); + observer.observe({ entryTypes: ['longtask'], buffered: false }); + const containerObject = document.createElement(container.name); + containerObject.id = container.name + '-id'; + containerObject.name = container.name + '-name'; + containerObject[container.src] = 'resources/subframe-with-longtask.html'; + document.body.appendChild(containerObject); + }); + const timeout = new Promise( + (resolve, reject) => t.step_timeout( + () => { reject(new Error('observer failed to find any entries')) }, + performanceObserverTimeout) + ); + return Promise.race([testLongTaskEntry, timeout]); + }, `Performance longtask entries in ${container.name} are observable in parent.`); +}); +</script> +</body> diff --git a/testing/web-platform/tests/longtask-timing/idlharness.window.js b/testing/web-platform/tests/longtask-timing/idlharness.window.js new file mode 100644 index 0000000000..af2e622197 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/idlharness.window.js @@ -0,0 +1,33 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js + +// https://w3c.github.io/longtasks/ + +'use strict'; + +idl_test( + ['longtasks'], + ['performance-timeline', 'hr-time'], + (idl_array, t) => new Promise((resolve, reject) => { + const longTask = () => { + const begin = self.performance.now(); + while (self.performance.now() < begin + 100); + } + t.step_timeout(longTask, 0); + + const observer = new PerformanceObserver((entryList, observer) => { + const entries = Array.from(entryList.getEntries()); + idl_array.add_objects({ + PerformanceLongTaskTiming: entries.slice(0, 1), + TaskAttributionTiming: entries[0].attribution, + }); + observer.disconnect(); + resolve(); + }); + observer.observe({entryTypes: ['longtask']}); + + t.step_timeout(() => { + reject('longtask entry was not observed'); + }, 1000); + }) +); diff --git a/testing/web-platform/tests/longtask-timing/long-microtask.window.js b/testing/web-platform/tests/longtask-timing/long-microtask.window.js new file mode 100644 index 0000000000..b69a1fd9e6 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/long-microtask.window.js @@ -0,0 +1,23 @@ +// META: script=resources/utils.js + +async_test(function (t) { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + new PerformanceObserver( + t.step_func_done(entryList => { + const entries = entryList.getEntries(); + assert_equals(entries.length, 1, + 'Exactly one entry is expected.'); + const longtask = entries[0]; + checkLongTaskEntry(longtask); + t.done(); + }) + ).observe({entryTypes: ['longtask']}); + + window.onload = () => { + /* Generate a slow microtask */ + Promise.resolve().then(() => { + const begin = window.performance.now(); + while (window.performance.now() < begin + 60); + }); + }; +}, 'A short task followed by a long microtask is observable.'); diff --git a/testing/web-platform/tests/longtask-timing/longtask-attributes.html b/testing/web-platform/tests/longtask-timing/longtask-attributes.html new file mode 100644 index 0000000000..0825ef757f --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/longtask-attributes.html @@ -0,0 +1,48 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>LongTask Timing: validate long task attributes</title> +<body> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/utils.js"></script> + +<h1>Long Task Attributes</h1> +<div id="log"></div> +<script> + async_test(function (t) { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + const observer = new PerformanceObserver( + t.step_func(function (entryList) { + const entries = entryList.getEntries(); + assert_equals(entries.length, 1, + 'Exactly one entry is expected.'); + const longtask = entries[0]; + checkLongTaskEntry(longtask); + // Assert the TaskAttributionTiming entry in attribution. + assert_equals(longtask.attribution.length, 1, + 'Exactly one attribution entry is expected'); + const attribution = longtask.attribution[0]; + assert_equals(attribution.entryType, 'taskattribution'); + assert_equals(attribution.name, 'unknown'); + assert_equals(attribution.duration, 0); + assert_equals(attribution.startTime, 0); + assert_equals(attribution.containerType, 'window'); + assert_equals(attribution.containerId, ''); + assert_equals(attribution.containerName, ''); + assert_equals(attribution.containerSrc, ''); + observer.disconnect(); + t.done(); + }) + ); + observer.observe({entryTypes: ['longtask']}); + + window.onload = () => { + /* Generate a slow task */ + const begin = window.performance.now(); + while (window.performance.now() < begin + 60); + }; +}, 'Performance longtask entries are observable.'); +</script> + +</body> diff --git a/testing/web-platform/tests/longtask-timing/longtask-before-observer.window.js b/testing/web-platform/tests/longtask-timing/longtask-before-observer.window.js new file mode 100644 index 0000000000..79d6990cf8 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/longtask-before-observer.window.js @@ -0,0 +1,16 @@ +// META: script=resources/utils.js + +async_test(t => { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + // Create a long task before any observer. + const begin = window.performance.now(); + while (window.performance.now() < begin + 60); + // After a timeout, add an observer with buffered flag. + t.step_timeout(() => { + new PerformanceObserver(t.step_func_done(list => { + list.getEntries().forEach(entry => { + checkLongTaskEntry(entry); + }); + })).observe({type: 'longtask', buffered: true}); + }, 0); +}, 'PerformanceObserver with buffered flag can see previous longtask entries.'); diff --git a/testing/web-platform/tests/longtask-timing/longtask-detach-frame.html b/testing/web-platform/tests/longtask-timing/longtask-detach-frame.html new file mode 100644 index 0000000000..94d0ad18f9 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/longtask-detach-frame.html @@ -0,0 +1,25 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>LongTask Timing: long task in nested child iframe</title> +<body> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/utils.js"></script> + +<h1>Long Tasks with detached iframe</h1> +<div id="log"></div> +<script> + promise_test(async t => { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + const iframe = document.createElement("iframe"); + document.body.appendChild(iframe); + t.add_cleanup(() => iframe.remove()); + t.step_timeout(() => { + busyWait(); + iframe.remove(); + }); +}, 'Performance longtask entries dont crash when a frame is detached.'); +</script> + +</body> diff --git a/testing/web-platform/tests/longtask-timing/longtask-in-childiframe-crossorigin.html b/testing/web-platform/tests/longtask-timing/longtask-in-childiframe-crossorigin.html new file mode 100644 index 0000000000..b8607f90dd --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/longtask-in-childiframe-crossorigin.html @@ -0,0 +1,57 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>LongTask Timing: long task in nested child iframe</title> +<body> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src='resources/utils.js'></script> + +<h1>Long Task in Nested Cross-Origin Child Iframe</h1> +<div id="log"></div> +<script> + async_test(function (t) { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + const observer = new PerformanceObserver( + t.step_func(function (entryList) { + const entries = entryList.getEntries(); + assert_equals(entries.length, 1, + 'Exactly one entry is expected.'); + const longtask = entries[0]; + assert_equals(longtask.entryType, 'longtask'); + if (longtask.name == 'self' || + longtask.name == 'multiple-contexts' || + longtask.name == 'unknown') + return; + checkLongTaskEntry(longtask, 'cross-origin-descendant'); + // Assert the TaskAttributionTiming entry in attribution. + assert_equals(longtask.attribution.length, 1, + 'Exactly one attribution entry is expected'); + const attribution = longtask.attribution[0]; + assert_equals(attribution.entryType, 'taskattribution'); + assert_equals(attribution.name, 'unknown'); + assert_equals(attribution.duration, 0); + assert_equals(attribution.startTime, 0); + assert_equals(attribution.containerType, 'iframe'); + assert_equals(attribution.containerId, 'child-iframe-id'); + assert_equals(attribution.containerName, 'child-iframe-name'); + assert_equals(attribution.containerSrc, + 'resources/subframe-with-longtask.html'); + observer.disconnect(); + t.done(); + }) + ); + observer.observe({entryTypes: ['longtask']}); + window.onload = () => { + const iframe = document.createElement('iframe'); + iframe.id = 'child-iframe-id'; + iframe.name = 'child-iframe-name'; + // Simulate cross-origin by using sandbox. + iframe.sandbox = "allow-scripts"; + document.body.appendChild(iframe); + iframe.src = 'resources/subframe-with-longtask.html'; + }; +}, 'Performance longtask entries in cross-origin child iframe are observable in parent.'); +</script> + +</body> diff --git a/testing/web-platform/tests/longtask-timing/longtask-in-childiframe.html b/testing/web-platform/tests/longtask-timing/longtask-in-childiframe.html new file mode 100644 index 0000000000..6618a88b89 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/longtask-in-childiframe.html @@ -0,0 +1,64 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>LongTask Timing: long task in nested child iframe</title> +<body> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/utils.js"></script> + +<h1>Long Task in Nested Child Iframe</h1> +<div id="log"></div> +<script> + promise_test(async (t) => { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + const initialTime = performance.now(); + const performanceObserverTimeout = 5 * 1000; + const longTasksPromise = new Promise(resolve => { + const observer = new PerformanceObserver( + t.step_func(function (entryList) { + const entries = entryList.getEntries(); + entries.forEach(longtask => { + assert_equals(longtask.entryType, 'longtask'); + if (hasUnrelatedTaskName(longtask.name, 'same-origin-descendant')) { + return; + } + checkLongTaskEntry(longtask, 'same-origin-descendant'); + // Assert the TaskAttributionTiming entry in attribution. + assert_equals(longtask.attribution.length, 1, + 'Exactly one attribution entry is expected'); + const attribution = longtask.attribution[0]; + assert_equals(attribution.entryType, 'taskattribution'); + assert_equals(attribution.name, 'unknown'); + assert_equals(attribution.duration, 0); + assert_equals(attribution.startTime, 0); + assert_equals(attribution.containerType, 'iframe'); + assert_equals(attribution.containerId, 'child-iframe-id'); + assert_equals(attribution.containerName, 'child-iframe-name'); + assert_equals(attribution.containerSrc, 'resources/subframe-with-longtask.html'); + observer.disconnect(); + resolve(); + }) + }) + ); + observer.observe({ + entryTypes: ['longtask'] + }); + const iframe = document.createElement('iframe'); + iframe.id = 'child-iframe-id'; + iframe.name = 'child-iframe-name'; + document.body.appendChild(iframe); + iframe.src = 'resources/subframe-with-longtask.html'; + }); + const timeout = new Promise( + (resolve, reject) => t.step_timeout( + () => { + reject(new Error('observer failed to find any entries')) + }, + performanceObserverTimeout) + ) + return Promise.race([longTasksPromise, timeout]); +}, 'Performance longtask entries in child iframe are observable in parent.'); +</script> + +</body> diff --git a/testing/web-platform/tests/longtask-timing/longtask-in-externalscript.html b/testing/web-platform/tests/longtask-timing/longtask-in-externalscript.html new file mode 100644 index 0000000000..0d8f5ccb67 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/longtask-in-externalscript.html @@ -0,0 +1,59 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>LongTask Timing: long task in external script</title> +<body> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/utils.js"></script> + +<h1>Long Task: External Script</h1> +<div id="log"></div> +<script> +promise_test(function(t) { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + const performanceObserverTimeout = 5 * 1000; + const longTasksPromise = new Promise(resolve => { + const observer = new PerformanceObserver( + t.step_func(function(entryList) { + const entries = entryList.getEntries(); + entries.forEach(longtask => { + assert_equals(longtask.entryType, 'longtask'); + if (hasUnrelatedTaskName(longtask.name, 'self')) { + return; + } + checkLongTaskEntry(longtask); + // Assert the TaskAttributionTiming entry in attribution. + assert_equals(longtask.attribution.length, 1, + 'Exactly one attribution entry is expected'); + const attribution = longtask.attribution[0]; + assert_equals(attribution.entryType, 'taskattribution'); + assert_equals(attribution.name, 'unknown'); + assert_equals(attribution.duration, 0); + assert_equals(attribution.startTime, 0); + assert_equals(attribution.containerType, 'window'); + assert_equals(attribution.containerId, ''); + assert_equals(attribution.containerName, ''); + assert_equals(attribution.containerSrc, ''); + observer.disconnect(); + resolve(); + }) + })); + observer.observe({ + entryTypes: ['longtask'] + }); + const script = document.createElement('script'); + script.src = 'resources/makelongtask.js'; + document.body.appendChild(script); + }); + const timeout = new Promise( + (resolve, reject) => t.step_timeout( + () => { + reject(new Error('observer failed to find any entries')) + }, + performanceObserverTimeout) + ) + return Promise.race([longTasksPromise, timeout]); +}, 'Performance longtask entries are observable.'); +</script> +</body> diff --git a/testing/web-platform/tests/longtask-timing/longtask-in-parentiframe.html b/testing/web-platform/tests/longtask-timing/longtask-in-parentiframe.html new file mode 100644 index 0000000000..7fd5fb672b --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/longtask-in-parentiframe.html @@ -0,0 +1,37 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>LongTask Timing: long task in nested child iframe</title> +<body> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> + const t = async_test(t => { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + window.addEventListener('message', t.step_func(e => { + assert_equals(e.data['entryType'], 'longtask'); + assert_equals(e.data['frame-attribution'], 'same-origin-ancestor'); + assert_equals(e.data['task-attribution'], 'unknown'); + assert_equals(e.data['containerType'], 'window'); + assert_equals(e.data['containerId'], ''); + assert_equals(e.data['containerName'], ''); + assert_equals(e.data['containerSrc'], ''); + t.done(); + })); + }, 'Performance longtask entries in parent are observable in child iframe.'); + + const iframe = document.createElement('iframe'); + iframe.id = 'child-iframe-id'; + iframe.name = 'child-iframe-name'; + document.body.appendChild(iframe); + iframe.src = 'resources/subframe-observing-longtask.html'; + iframe.onload = () => { + t.step_timeout( () => { + const begin = window.performance.now(); + while (window.performance.now() < begin + 60); + }, 50); + }; +</script> + +</body> diff --git a/testing/web-platform/tests/longtask-timing/longtask-in-raf.html b/testing/web-platform/tests/longtask-timing/longtask-in-raf.html new file mode 100644 index 0000000000..169843a742 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/longtask-in-raf.html @@ -0,0 +1,52 @@ +<!DOCTYPE HTML> +<head> + <meta charset=utf-8> + <title>LongTask Timing: long task in rAF</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/utils.js"></script> +</head> +<body> + <h1>Long Task: requestAnimationFrame</h1> + <div id="log"></div> + <script> + promise_test(async () => { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + await new Promise(resolve => { + window.addEventListener('load', resolve); + }); + + let entries = await new Promise(resolve => { + new PerformanceObserver( + entryList => { + const entries = entryList.getEntries().filter( + e => e.name == 'self' && e.attribution[0].containerType == 'window'); + if (entries) { + resolve(entries); + } + }).observe({ entryTypes: ['longtask'] }); + + const script = document.createElement('script'); + script.src = 'resources/raflongtask.js'; + document.body.appendChild(script); + }); + + assert_equals(entries.length, 1, + 'Exactly one entry is expected.'); + const longtask = entries[0]; + checkLongTaskEntry(longtask); + // Assert the TaskAttributionTiming entry in attribution. + assert_equals(longtask.attribution.length, 1, + 'Exactly one attribution entry is expected'); + const attribution = longtask.attribution[0]; + assert_equals(attribution.entryType, 'taskattribution'); + assert_equals(attribution.name, 'unknown'); + assert_equals(attribution.duration, 0); + assert_equals(attribution.startTime, 0); + assert_equals(attribution.containerType, 'window'); + assert_equals(attribution.containerId, ''); + assert_equals(attribution.containerName, ''); + assert_equals(attribution.containerSrc, ''); + }, 'Performance longtask entries are observable.'); + </script> +</body> diff --git a/testing/web-platform/tests/longtask-timing/longtask-in-sibling-iframe-crossorigin.html b/testing/web-platform/tests/longtask-timing/longtask-in-sibling-iframe-crossorigin.html new file mode 100644 index 0000000000..d66fe0c63b --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/longtask-in-sibling-iframe-crossorigin.html @@ -0,0 +1,40 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>LongTask Timing: long task in cross-origin sibling iframe</title> +<body> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> + async_test(t => { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + window.addEventListener('message', t.step_func(e => { + assert_equals(e.data['entryType'], 'longtask'); + assert_equals(e.data['frame-attribution'], 'cross-origin-unreachable'); + assert_equals(e.data['task-attribution'], 'unknown'); + assert_equals(e.data['containerType'], 'window'); + assert_equals(e.data['containerId'], ''); + assert_equals(e.data['containerName'], ''); + assert_equals(e.data['containerSrc'], ''); + t.done(); + })); + const observingFrame = document.createElement('iframe'); + observingFrame.id = 'observing-iframe-id'; + observingFrame.name = 'observing-iframe-name'; + document.body.appendChild(observingFrame); + observingFrame.src = 'resources/subframe-observing-longtask.html' + + observingFrame.onload = () => { + /* Create a cross-origin iframe that generates a long task. */ + const longtaskFrame = document.createElement('iframe'); + longtaskFrame.id = 'longtask-iframe-id'; + longtaskFrame.name = 'longtask-iframe-name'; + // Simulate cross-origin by using sandbox. + longtaskFrame.sandbox = "allow-scripts"; + document.body.appendChild(longtaskFrame); + longtaskFrame.src = 'resources/subframe-with-longtask.html' + }; +}, 'Performance longtask entries from cross-origin iframe are observable in its sibling.'); +</script> +</body> diff --git a/testing/web-platform/tests/longtask-timing/longtask-in-sibling-iframe.html b/testing/web-platform/tests/longtask-timing/longtask-in-sibling-iframe.html new file mode 100644 index 0000000000..396a9beeea --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/longtask-in-sibling-iframe.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>LongTask Timing: long task in sibling iframe</title> +<body> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> + async_test(t => { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + window.addEventListener('message', t.step_func(e => { + assert_equals(e.data['entryType'], 'longtask'); + // Ignore any long task that may be produced by the top-level frame. + if (e.data['frame-attribution'] === 'same-origin-ancestor') + return; + + assert_equals(e.data['frame-attribution'], 'same-origin'); + assert_equals(e.data['task-attribution'], 'unknown'); + assert_equals(e.data['containerType'], 'iframe'); + assert_equals(e.data['containerId'], 'longtask-iframe-id'); + assert_equals(e.data['containerName'], 'longtask-iframe-name'); + assert_equals(e.data['containerSrc'], 'resources/subframe-with-longtask.html'); + t.done(); + })); + const observingFrame = document.createElement('iframe'); + observingFrame.id = 'observing-iframe-id'; + observingFrame.name = 'observing-iframe-name'; + document.body.appendChild(observingFrame); + observingFrame.src = 'resources/subframe-observing-longtask.html' + + observingFrame.onload = () => { + const longtaskFrame = document.createElement('iframe'); + longtaskFrame.id = 'longtask-iframe-id'; + longtaskFrame.name = 'longtask-iframe-name'; + document.body.appendChild(longtaskFrame); + longtaskFrame.src = 'resources/subframe-with-longtask.html' + }; +}, 'Performance longtask entries are observable in sibling iframe.'); +</script> +</body> diff --git a/testing/web-platform/tests/longtask-timing/longtask-promise.html b/testing/web-platform/tests/longtask-timing/longtask-promise.html new file mode 100644 index 0000000000..762511524b --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/longtask-promise.html @@ -0,0 +1,36 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>LongTask Timing: Promise resolvers</title> +<body> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/utils.js"></script> + +<h1>Long Task: promise resolvers</h1> +<script> + function test_promise_long_task(name, promise) { + promise_test(async t => { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + const longTaskPromise = new Promise(resolve => { + const observer = new PerformanceObserver(t.step_func(entryList => { + observer.disconnect(); + resolve(entryList.getEntries()); + })); + observer.observe({entryTypes: ['longtask']}); + }); + + await promise().catch(() => {}); + busyWait(); + const entries = await longTaskPromise; + assert_greater_than_equal(entries.length, 1); + }, `Performance longtask entries after a promise: ${name}`); + } + + test_promise_long_task("successful fetch", () => fetch("/common/dummy.xml")); + test_promise_long_task("Response.text()", () => + fetch("/common/dummy.xml").then(r => r.text())); + test_promise_long_task("rejected fetch", () => fetch("/common/non-existent.xml")); + test_promise_long_task("JSON error", () => fetch("/common/dummy.xml").then(r => r.json())); +</script> +</body> diff --git a/testing/web-platform/tests/longtask-timing/longtask-sync-xhr.html b/testing/web-platform/tests/longtask-timing/longtask-sync-xhr.html new file mode 100644 index 0000000000..da223cca2a --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/longtask-sync-xhr.html @@ -0,0 +1,28 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>LongTask Timing: synchronous XHR</title> +<body> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/utils.js"></script> + +<h1>Long Task: synchronous XHR</h1> +<div id="log"></div> +<script> +setup(() => assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.')); + +promise_test(async t => { + const receivedLongTask = new Promise(resolve => + new PerformanceObserver(entries => resolve(entries.getEntries())).observe({entryTypes: ['longtask']})); + await new Promise(resolve => window.addEventListener('load', () => { + const xhr = new XMLHttpRequest(); + xhr.open('GET', '/resource-timing/resources/delay-css.py?delay=100', false /* synchronous xhr */); + xhr.send(); + resolve(); + })); + const entries = await receivedLongTask; + assert_equals(entries.length, 1); +}, 'A long synchronous XHR is a longtask'); +</script> +</body> diff --git a/testing/web-platform/tests/longtask-timing/longtask-tojson.html b/testing/web-platform/tests/longtask-timing/longtask-tojson.html new file mode 100644 index 0000000000..b1f9b3c9b1 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/longtask-tojson.html @@ -0,0 +1,74 @@ +<!doctype html> +<html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<script> + async_test(function (t) { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + const observer = new PerformanceObserver( + t.step_func(function (entryList) { + const entries = entryList.getEntries(); + assert_greater_than_equal(entries.length, 1); + const entry = entries[0]; + assert_equals(typeof(entry.toJSON), 'function'); + const entryJSON = entry.toJSON(); + assert_equals(typeof(entryJSON), 'object'); + // Check attributes inheritted from PerformanceEntry. + const performanceEntryKeys = [ + 'name', + 'entryType', + 'startTime', + 'duration' + ]; + for (const key of performanceEntryKeys) { + assert_equals(entryJSON[key], entry[key], + `entry.toJSON().${key} should match entry.${key}`); + } + + // Check PerformanceLongTaskTiming specific entries. + assert_equals(typeof(entryJSON.attribution), 'object'); + const entryJsonAttribution = entryJSON.attribution[0]; + assert_equals(typeof(entryJsonAttribution), 'object'); + assert_equals(entryJSON.attribution.length, entry.attribution.length); + + // Check TaskAttributionTiming toJSON. + const entryAttribution = entry.attribution[0]; + assert_equals(typeof(entryAttribution.toJSON), 'function'); + const entryAttributionJSON = entryAttribution.toJSON(); + assert_equals(typeof(entryAttributionJSON), 'object'); + // Check TaskAttributionTiming attributes, from both: + // 1) |entryJsonAttribution| from PerformanceLongTaskTiming. + // 2) |entryAttributionJSON| from TaskAttributionTiming. + const taskAttributionTimingKeys = [ + 'name', + 'entryType', + 'startTime', + 'duration', + 'containerType', + 'containerSrc', + 'containerId', + 'containerName' + ]; + for (const key of taskAttributionTimingKeys) { + assert_equals(entryAttributionJSON[key], entryAttribution[key], + `attribution.toJSON().${key} should match attribution.${key}`); + assert_equals(entryJsonAttribution[key], entryAttribution[key], + `entry.toJSON().attribution[0].${key} should match attribution.${key}`); + } + t.done(); + }) + ); + observer.observe({entryTypes: ['longtask']}); + + window.onload = () => { + // Trigger a long task. + const begin = window.performance.now(); + while (window.performance.now() < begin + 60); + }; + }, 'Test toJSON() in PerformanceLongTaskTiming and TaskAttributionTiming'); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/longtask-timing/resources/makelongtask.js b/testing/web-platform/tests/longtask-timing/resources/makelongtask.js new file mode 100644 index 0000000000..75de5453b5 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/resources/makelongtask.js @@ -0,0 +1,3 @@ +/* Generate a slow task. */ +const begin = window.performance.now(); +while (window.performance.now() < begin + 60); diff --git a/testing/web-platform/tests/longtask-timing/resources/raflongtask.js b/testing/web-platform/tests/longtask-timing/resources/raflongtask.js new file mode 100644 index 0000000000..ec39cb896e --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/resources/raflongtask.js @@ -0,0 +1,5 @@ +window.requestAnimationFrame(function() { + /* Generate a slow task. */ + const begin = window.performance.now(); + while (window.performance.now() < begin + 60); +}); diff --git a/testing/web-platform/tests/longtask-timing/resources/subframe-observing-longtask.html b/testing/web-platform/tests/longtask-timing/resources/subframe-observing-longtask.html new file mode 100644 index 0000000000..125ff1e4cb --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/resources/subframe-observing-longtask.html @@ -0,0 +1,31 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<meta name="viewport" content="width=device-width"> +<title>Child Iframe</title> +<h1>Child Iframe observing long tasks</h1> + +<script> + const observer = new PerformanceObserver(function(entryList) { + for (i = 0; i < entryList.getEntries().length; i++) { + const longtask = entryList.getEntries()[i]; + // Ignore long task generated within here, as part of making this iframe. + // Ignore multiple-contexts and unknown because they cause longtask-in-parentiframe test to be flaky. + if (longtask.name == 'self' || + longtask.name == 'multiple-contexts' || longtask.name == 'unknown') + return; + // TODO(panicker): include containerType. + const attribution = longtask.attribution[0]; + const entryContents = { + 'entryType': longtask.entryType, + 'frame-attribution': longtask.name, + 'task-attribution': attribution.name, + 'containerType': attribution.containerType, + 'containerId': attribution.containerId, + 'containerName': attribution.containerName, + 'containerSrc': attribution.containerSrc + }; + top.postMessage(entryContents, '*'); + } + }); + observer.observe({entryTypes: ['longtask']}); +</script> diff --git a/testing/web-platform/tests/longtask-timing/resources/subframe-with-longtask.html b/testing/web-platform/tests/longtask-timing/resources/subframe-with-longtask.html new file mode 100644 index 0000000000..298b252d18 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/resources/subframe-with-longtask.html @@ -0,0 +1,11 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<meta name="viewport" content="width=device-width"> + +<title>Long Task Iframe</title> +<h1>Long Task in Inline Script</h1> + +<script> + const begin = window.performance.now(); + while (window.performance.now() < begin + 60); +</script> diff --git a/testing/web-platform/tests/longtask-timing/resources/utils.js b/testing/web-platform/tests/longtask-timing/resources/utils.js new file mode 100644 index 0000000000..5498aa9a7b --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/resources/utils.js @@ -0,0 +1,18 @@ +function checkLongTaskEntry(longtask, name = 'self') { + assert_equals(longtask.entryType, 'longtask', 'The entryType should be longtask'); + assert_equals(longtask.name, name, 'Name should be ' + name + '.'); + assert_true(Number.isInteger(longtask.duration, 'The duration should be an integer.')); + assert_greater_than_equal(longtask.duration, 50, 'The Duration should be greater than or equal to 50.'); + assert_greater_than_equal(longtask.startTime, 0, 'The startTime should be greater than or equal to 0.'); + const currentTime = performance.now(); + assert_less_than_equal(longtask.startTime, currentTime, 'The startTime should be less than or equal to current time.'); +} + +function hasUnrelatedTaskName(taskName, expectedTaskName) { + return (taskName !== expectedTaskName); +} + +function busyWait() { + const deadline = performance.now() + 100; + while (performance.now() < deadline) {} +} diff --git a/testing/web-platform/tests/longtask-timing/shared-renderer/longtask-in-new-window.html b/testing/web-platform/tests/longtask-timing/shared-renderer/longtask-in-new-window.html new file mode 100644 index 0000000000..7668d995d8 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/shared-renderer/longtask-in-new-window.html @@ -0,0 +1,48 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>LongTask Timing: long task in another window</title> +<body> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +/* This test should pass even when windows share a single renderer process. + This window opens a new window which contains a longtask. We test that the + longtask from the new window is not observed by the observer of this window. */ +async_test(t => { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + const observer = new PerformanceObserver( + t.step_func(function (entryList) { + const entries = entryList.getEntries(); + let markFound = false; + for (let i = 0; i < entries.length; ++i) { + const entry = entries[i]; + // We do not expect to observe longtasks but the work being made in this window may produce a longtask. + assert_true(entry.entryType === 'longtask' || + entry.entryType === 'mark'); + if (entry.entryType === 'mark') { + markFound = true; + continue; + } + // If a longtask is observed, it must come from this window. + assert_equals(entry.name, 'self'); + } + // If we found the mark, then the other window longtask is done. + if (markFound) + t.done(); + }) + ); + observer.observe({entryTypes: ['mark', 'longtask']}); + + window.onload = () => { + // Open a window with a longtask. + const other_window = window.open('resources/frame-with-longtask.html'); + window.addEventListener('message', t.step_func(e => { + // Do a mark (after the other window's longtask) to fire the callback. + self.performance.mark('mark1'); + })); + }; +}, 'A longtask in a frame from window.open is not reported in original frame'); +</script> +</body> diff --git a/testing/web-platform/tests/longtask-timing/shared-renderer/resources/frame-with-longtask.html b/testing/web-platform/tests/longtask-timing/shared-renderer/resources/frame-with-longtask.html new file mode 100644 index 0000000000..9d0273e192 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/shared-renderer/resources/frame-with-longtask.html @@ -0,0 +1,14 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<meta name="viewport" content="width=device-width"> + +<title>Long Task Frame</title> +<body> +<h1>Long Task plus PostMessage</h1> + +<script> + const begin = window.performance.now(); + while (window.performance.now() < begin + 60); + window.opener.postMessage('Finished.', '*'); +</script> +</body> diff --git a/testing/web-platform/tests/longtask-timing/spin-eventloop-not-longtask.html b/testing/web-platform/tests/longtask-timing/spin-eventloop-not-longtask.html new file mode 100644 index 0000000000..9c83b14e31 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/spin-eventloop-not-longtask.html @@ -0,0 +1,25 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>LongTask Timing: synchronous XHR</title> +<body> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/utils.js"></script> +<link rel="stylesheet" href="/resource-timing/resources/delay-css.py?delay=1000" /> +<h1>Long Task: Spin event loop</h1> +<div id="log"></div> +<script> +setup(() => assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.')); + +promise_test(async t => { + const didReceiveLongTask = false; + new PerformanceObserver(() => { + didReceiveLongTask = true; + }).observe({entryTypes: ['longtask']}); + + await new Promise(resolve => window.addEventListener('load', resolve)); + assert_false(didReceiveLongTask); +}, 'Waiting for load event (spinning an event loop), is not a longtask'); +</script> +</body> diff --git a/testing/web-platform/tests/longtask-timing/supported-longtask-types.window.js b/testing/web-platform/tests/longtask-timing/supported-longtask-types.window.js new file mode 100644 index 0000000000..efb393ad84 --- /dev/null +++ b/testing/web-platform/tests/longtask-timing/supported-longtask-types.window.js @@ -0,0 +1,35 @@ +test(() => { + assert_implements(typeof PerformanceObserver.supportedEntryTypes !== "undefined", 'supportedEntryTypes is not supported'); + const types = PerformanceObserver.supportedEntryTypes; + assert_true(types.includes("longtask"), + "There should be 'longtask' in PerformanceObserver.supportedEntryTypes"); + assert_false(types.includes("taskattribution"), + "There should NOT be 'taskattribution' in PerformanceObserver.supportedEntryTypes"); +}, "supportedEntryTypes contains 'longtask' but not 'taskattribution'."); + +function syncWait(waitDuration) { + if (waitDuration <= 0) + return; + + const startTime = performance.now(); + let unused = ''; + for (let i = 0; i < 10000; i++) + unused += '' + Math.random(); + + return syncWait(waitDuration - (performance.now() - startTime)); +} + +const entryType = "longtask"; +promise_test(async () => { + assert_implements(typeof PerformanceObserver.supportedEntryTypes !== "undefined", 'supportedEntryTypes is not supported'); + assert_implements(typeof PerformanceObserver.supportedEntryTypes.includes(entryType), `supportedEntryTypes does not include '${entryType}'`); + await new Promise((resolve) => { + new PerformanceObserver(function (list, observer) { + observer.disconnect(); + resolve(); + }).observe({entryTypes: [entryType]}); + + // Force the PerformanceEntry. + syncWait(50); + }) +}, `'${entryType}' entries should be observable.`) |