summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/longtask-timing
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/longtask-timing
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/longtask-timing')
-rw-r--r--testing/web-platform/tests/longtask-timing/META.yml4
-rw-r--r--testing/web-platform/tests/longtask-timing/buffered-flag.window.js26
-rw-r--r--testing/web-platform/tests/longtask-timing/containerNames.html56
-rw-r--r--testing/web-platform/tests/longtask-timing/containerTypes.html67
-rw-r--r--testing/web-platform/tests/longtask-timing/idlharness.window.js36
-rw-r--r--testing/web-platform/tests/longtask-timing/long-microtask.window.js23
-rw-r--r--testing/web-platform/tests/longtask-timing/longtask-attributes.html48
-rw-r--r--testing/web-platform/tests/longtask-timing/longtask-before-observer.window.js16
-rw-r--r--testing/web-platform/tests/longtask-timing/longtask-in-childiframe-crossorigin.html57
-rw-r--r--testing/web-platform/tests/longtask-timing/longtask-in-childiframe.html64
-rw-r--r--testing/web-platform/tests/longtask-timing/longtask-in-externalscript.html59
-rw-r--r--testing/web-platform/tests/longtask-timing/longtask-in-parentiframe.html37
-rw-r--r--testing/web-platform/tests/longtask-timing/longtask-in-raf.html46
-rw-r--r--testing/web-platform/tests/longtask-timing/longtask-in-sibling-iframe-crossorigin.html40
-rw-r--r--testing/web-platform/tests/longtask-timing/longtask-in-sibling-iframe.html41
-rw-r--r--testing/web-platform/tests/longtask-timing/longtask-sync-xhr.html28
-rw-r--r--testing/web-platform/tests/longtask-timing/longtask-tojson.html74
-rw-r--r--testing/web-platform/tests/longtask-timing/resources/makelongtask.js3
-rw-r--r--testing/web-platform/tests/longtask-timing/resources/raflongtask.js5
-rw-r--r--testing/web-platform/tests/longtask-timing/resources/subframe-observing-longtask.html31
-rw-r--r--testing/web-platform/tests/longtask-timing/resources/subframe-with-longtask.html11
-rw-r--r--testing/web-platform/tests/longtask-timing/resources/utils.js13
-rw-r--r--testing/web-platform/tests/longtask-timing/shared-renderer/longtask-in-new-window.html48
-rw-r--r--testing/web-platform/tests/longtask-timing/shared-renderer/resources/frame-with-longtask.html14
-rw-r--r--testing/web-platform/tests/longtask-timing/spin-eventloop-not-longtask.html25
-rw-r--r--testing/web-platform/tests/longtask-timing/supported-longtask-types.window.js35
26 files changed, 907 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..91c07f9fd3
--- /dev/null
+++ b/testing/web-platform/tests/longtask-timing/META.yml
@@ -0,0 +1,4 @@
+spec: https://w3c.github.io/longtasks/
+suggested_reviewers:
+ - spanicker
+ - npm1
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..fd9a3f042f
--- /dev/null
+++ b/testing/web-platform/tests/longtask-timing/idlharness.window.js
@@ -0,0 +1,36 @@
+// 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 => {
+ const entries = Array.from(entryList.getEntries());
+ const attribution = entries.reduce(
+ (sum, e) => sum.concat(e.attribution || []), []);
+ idl_array.add_objects({
+ PerformanceLongTaskTiming: entries,
+ TaskAttributionTiming: attribution,
+ });
+ 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-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..d65f892818
--- /dev/null
+++ b/testing/web-platform/tests/longtask-timing/longtask-in-raf.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<meta charset=utf-8>
+<title>LongTask Timing: long task in rAF</title>
+<body>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/utils.js"></script>
+
+<h1>Long Task: requestAnimationFrame</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 = () => {
+ const script = document.createElement('script');
+ script.src = 'resources/raflongtask.js';
+ document.body.appendChild(script);
+ };
+}, '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-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..36bd6c7bc2
--- /dev/null
+++ b/testing/web-platform/tests/longtask-timing/resources/utils.js
@@ -0,0 +1,13 @@
+function checkLongTaskEntry(longtask, name='self') {
+ assert_equals(longtask.entryType, 'longtask');
+ assert_equals(longtask.name, name);
+ assert_true(Number.isInteger(longtask.duration));
+ assert_greater_than_equal(longtask.duration, 50);
+ assert_greater_than_equal(longtask.startTime, 0);
+ const currentTime = performance.now();
+ assert_less_than_equal(longtask.startTime, currentTime);
+}
+
+function hasUnrelatedTaskName(taskName, expectedTaskName) {
+ return (taskName !== expectedTaskName);
+}
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.`)