summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/hr-time
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/hr-time')
-rw-r--r--testing/web-platform/tests/hr-time/META.yml4
-rw-r--r--testing/web-platform/tests/hr-time/basic.any.js37
-rw-r--r--testing/web-platform/tests/hr-time/clamped-time-origin-isolated.https.html14
-rw-r--r--testing/web-platform/tests/hr-time/clamped-time-origin-isolated.https.html.headers2
-rw-r--r--testing/web-platform/tests/hr-time/clamped-time-origin.html14
-rw-r--r--testing/web-platform/tests/hr-time/cross-origin-isolated-timing-attack.https.html22
-rw-r--r--testing/web-platform/tests/hr-time/cross-origin-isolated-timing-attack.https.html.headers2
-rw-r--r--testing/web-platform/tests/hr-time/idlharness-shadowrealm.window.js2
-rw-r--r--testing/web-platform/tests/hr-time/idlharness.any.js23
-rw-r--r--testing/web-platform/tests/hr-time/monotonic-clock.any.js13
-rw-r--r--testing/web-platform/tests/hr-time/navigation-start-post-before-unload.html33
-rw-r--r--testing/web-platform/tests/hr-time/performance-tojson.html76
-rw-r--r--testing/web-platform/tests/hr-time/resources/clamped-time-origin.js30
-rw-r--r--testing/web-platform/tests/hr-time/resources/now_frame.html9
-rw-r--r--testing/web-platform/tests/hr-time/resources/post.html4
-rw-r--r--testing/web-platform/tests/hr-time/resources/timing-attack.js42
-rw-r--r--testing/web-platform/tests/hr-time/resources/unload-a.html13
-rw-r--r--testing/web-platform/tests/hr-time/resources/unload-b.html13
-rw-r--r--testing/web-platform/tests/hr-time/resources/unload-c.html13
-rw-r--r--testing/web-platform/tests/hr-time/resources/unload.js51
-rw-r--r--testing/web-platform/tests/hr-time/test_cross_frame_start.html59
-rw-r--r--testing/web-platform/tests/hr-time/timeOrigin.html45
-rw-r--r--testing/web-platform/tests/hr-time/timing-attack.html22
-rw-r--r--testing/web-platform/tests/hr-time/unload-manual.html73
-rw-r--r--testing/web-platform/tests/hr-time/window-worker-timeOrigin.window.js30
25 files changed, 646 insertions, 0 deletions
diff --git a/testing/web-platform/tests/hr-time/META.yml b/testing/web-platform/tests/hr-time/META.yml
new file mode 100644
index 0000000000..779d5b4af0
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/META.yml
@@ -0,0 +1,4 @@
+spec: https://w3c.github.io/hr-time/
+suggested_reviewers:
+ - plehegar
+ - igrigorik
diff --git a/testing/web-platform/tests/hr-time/basic.any.js b/testing/web-platform/tests/hr-time/basic.any.js
new file mode 100644
index 0000000000..4cd6e42dfc
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/basic.any.js
@@ -0,0 +1,37 @@
+test(function() {
+ assert_true((self.performance !== undefined), "self.performance exists");
+ assert_equals(typeof self.performance, "object", "self.performance is an object");
+ assert_equals((typeof self.performance.now), "function", "self.performance.now() is a function");
+ assert_equals(typeof self.performance.now(), "number", "self.performance.now() returns a number");
+}, "self.performance.now() is a function that returns a number");
+
+test(function() {
+ assert_true(self.performance.now() > 0);
+}, "self.performance.now() returns a positive number");
+
+test(function() {
+ var now1 = self.performance.now();
+ var now2 = self.performance.now();
+ assert_true((now2-now1) >= 0);
+ }, "self.performance.now() difference is not negative");
+
+async_test(function() {
+ // Check whether the performance.now() method is close to Date() within 30ms (due to inaccuracies)
+ var initial_hrt = self.performance.now();
+ var initial_date = Date.now();
+ this.step_timeout(function() {
+ var final_hrt = self.performance.now();
+ var final_date = Date.now();
+ assert_approx_equals(final_hrt - initial_hrt, final_date - initial_date, 30, 'High resolution time value increased by approximately the same amount as time from date object');
+ this.done();
+ }, 2000);
+}, 'High resolution time has approximately the right relative magnitude');
+
+test(function() {
+ var didHandle = false;
+ self.performance.addEventListener("testEvent", function() {
+ didHandle = true;
+ }, { once: true} );
+ self.performance.dispatchEvent(new Event("testEvent"));
+ assert_true(didHandle, "Performance extends EventTarget, so event dispatching should work.");
+}, "Performance interface extends EventTarget.");
diff --git a/testing/web-platform/tests/hr-time/clamped-time-origin-isolated.https.html b/testing/web-platform/tests/hr-time/clamped-time-origin-isolated.https.html
new file mode 100644
index 0000000000..ce30698b77
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/clamped-time-origin-isolated.https.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<html>
+<head>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/clamped-time-origin.js"></script>
+</head>
+<body>
+<script>
+// Isolated contexts should be clamped to 5 microseconds.
+run_test(/*isolated=*/true);
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/hr-time/clamped-time-origin-isolated.https.html.headers b/testing/web-platform/tests/hr-time/clamped-time-origin-isolated.https.html.headers
new file mode 100644
index 0000000000..5f8621ef83
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/clamped-time-origin-isolated.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/hr-time/clamped-time-origin.html b/testing/web-platform/tests/hr-time/clamped-time-origin.html
new file mode 100644
index 0000000000..1f438e9fef
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/clamped-time-origin.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<html>
+<head>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/clamped-time-origin.js"></script>
+</head>
+<body>
+<script>
+// Non-isolated contexts should be clamped to 100 microseconds.
+run_test(/*isolated=*/false);
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/hr-time/cross-origin-isolated-timing-attack.https.html b/testing/web-platform/tests/hr-time/cross-origin-isolated-timing-attack.https.html
new file mode 100644
index 0000000000..88848740a9
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/cross-origin-isolated-timing-attack.https.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>window.performance.now should not enable timing attacks</title>
+<link rel="author" title="W3C" href="http://www.w3.org/" />
+<link rel="help" href="http://w3c.github.io/hr-time/#privacy-security"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/timing-attack.js"></script>
+<script>
+run_test(/*isolated=*/true);
+</script>
+</head>
+<body>
+<h1>Description</h1>
+<p>The recommended minimum resolution of the Performance interface should be set to 5 microseconds.</p>
+
+<div id="log"></div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/hr-time/cross-origin-isolated-timing-attack.https.html.headers b/testing/web-platform/tests/hr-time/cross-origin-isolated-timing-attack.https.html.headers
new file mode 100644
index 0000000000..5f8621ef83
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/cross-origin-isolated-timing-attack.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/hr-time/idlharness-shadowrealm.window.js b/testing/web-platform/tests/hr-time/idlharness-shadowrealm.window.js
new file mode 100644
index 0000000000..3209db5f41
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/idlharness-shadowrealm.window.js
@@ -0,0 +1,2 @@
+// META: script=/resources/idlharness-shadowrealm.js
+idl_test_shadowrealm(["hr-time"], ["html", "dom"]);
diff --git a/testing/web-platform/tests/hr-time/idlharness.any.js b/testing/web-platform/tests/hr-time/idlharness.any.js
new file mode 100644
index 0000000000..6676b001a8
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/idlharness.any.js
@@ -0,0 +1,23 @@
+// META: global=window,worker
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+// META: timeout=long
+
+'use strict';
+
+// https://w3c.github.io/hr-time/
+
+idl_test(
+ ['hr-time'],
+ ['html', 'dom'],
+ async idl_array => {
+ if (self.GLOBAL.isWorker()) {
+ idl_array.add_objects({ WorkerGlobalScope: ['self'] });
+ } else {
+ idl_array.add_objects({ Window: ['self'] });
+ }
+ idl_array.add_objects({
+ Performance: ['performance'],
+ });
+ }
+);
diff --git a/testing/web-platform/tests/hr-time/monotonic-clock.any.js b/testing/web-platform/tests/hr-time/monotonic-clock.any.js
new file mode 100644
index 0000000000..c53b04d844
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/monotonic-clock.any.js
@@ -0,0 +1,13 @@
+// The time values returned when calling the now method MUST be monotonically increasing and not subject to system clock adjustments or system clock skew.
+test(function() {
+ assert_true(self.performance.now() > 0, "self.performance.now() returns positive numbers");
+}, "self.performance.now() returns a positive number");
+
+// The difference between any two chronologically recorded time values returned from the now method MUST never be negative.
+test(function() {
+ var now1 = self.performance.now();
+ var now2 = self.performance.now();
+ assert_true((now2-now1) >= 0, "self.performance.now() difference is not negative");
+ },
+ "self.performance.now() difference is not negative"
+);
diff --git a/testing/web-platform/tests/hr-time/navigation-start-post-before-unload.html b/testing/web-platform/tests/hr-time/navigation-start-post-before-unload.html
new file mode 100644
index 0000000000..88ee5db77e
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/navigation-start-post-before-unload.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<html>
+<head>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script>
+ function busyWait(millis) {
+ const start = performance.now();
+ while (performance.now() < start + millis) {}
+ }
+ promise_test(async t => {
+ const delay = 3000;
+ const iframe = document.createElement('iframe');
+ iframe.src = './resources/now_frame.html';
+ document.body.appendChild(iframe);
+ await new Promise(resolve => iframe.addEventListener('load', resolve));
+ iframe.contentWindow.addEventListener('beforeunload', () => {
+ busyWait(delay);
+ });
+ iframe.src = './resources/post.html';
+ await new Promise(resolve => this.addEventListener('message', ({data}) => {
+ if (data === 'done')
+ resolve();
+ }));
+
+ const entry = iframe.contentWindow.performance.getEntriesByType('navigation')[0];
+ assert_less_than(entry.fetchStart, delay);
+ }, 'timeOrigin should be set after beforeunload');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/hr-time/performance-tojson.html b/testing/web-platform/tests/hr-time/performance-tojson.html
new file mode 100644
index 0000000000..fd8049cb9a
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/performance-tojson.html
@@ -0,0 +1,76 @@
+<!doctype html>
+<html>
+<head>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script>
+
+test(() => {
+ // Check Performance attributes.
+ assert_equals(typeof(performance.toJSON), 'function');
+ const json = performance.toJSON();
+ assert_equals(typeof(json), 'object');
+ assert_equals(json.timeOrigin, performance.timeOrigin,
+ 'performance.toJSON().timeOrigin should match performance.timeOrigin');
+
+ // Check PerformanceTiming toJSON.
+ const jsonTiming = json.timing;
+ const timing = performance.timing;
+ assert_equals(typeof(timing.toJSON), 'function');
+ const timingJSON = timing.toJSON();
+ assert_equals(typeof(timingJSON), 'object');
+ // Check PerformanceTiming attributes, from both:
+ // 1) |jsonTiming| from Performance.
+ // 2) |timingJSON| from PerformanceTiming.
+ const performanceTimingKeys = [
+ 'navigationStart',
+ 'unloadEventStart',
+ 'unloadEventEnd',
+ 'redirectStart',
+ 'redirectEnd',
+ 'fetchStart',
+ 'domainLookupStart',
+ 'domainLookupEnd',
+ 'connectStart',
+ 'connectEnd',
+ 'secureConnectionStart',
+ 'requestStart',
+ 'responseStart',
+ 'responseEnd',
+ 'domLoading',
+ 'domInteractive',
+ 'domContentLoadedEventStart',
+ 'domContentLoadedEventEnd',
+ 'domComplete',
+ 'loadEventStart',
+ 'loadEventEnd'
+ ];
+ for (const key of performanceTimingKeys) {
+ assert_equals(jsonTiming[key], timing[key],
+ `performance.toJSON().timing.${key} should match performance.timing.${key}`);
+ assert_equals(timingJSON[key], timing[key],
+ `performance.timing.toJSON().${key} should match performance.timing.${key}`);
+ }
+
+ // Check PerformanceNavigation toJSON.
+ const jsonNavigation = json.navigation;
+ const navigation = performance.navigation;
+ assert_equals(typeof(navigation.toJSON), 'function');
+ const navigationJSON = navigation.toJSON();
+ assert_equals(typeof(navigationJSON), 'object');
+ // Check PerformanceNavigation attributes, from both:
+ // 1) |jsonNavigation| from Performance.
+ // 2) |navigationJSON| from PerformanceNavigation.
+ let performanceNavigationKeys = ['type', 'redirectCount'];
+ for (const key of performanceNavigationKeys) {
+ assert_equals(jsonNavigation[key], navigation[key],
+ `performance.toJSON().navigation.${key} should match performance.navigation.${key}`);
+ assert_equals(navigationJSON[key], navigation[key],
+ `performance.navigation.toJSON().${key} should match performance.navigation.${key}`);
+ }
+}, 'Test performance.toJSON()');
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/hr-time/resources/clamped-time-origin.js b/testing/web-platform/tests/hr-time/resources/clamped-time-origin.js
new file mode 100644
index 0000000000..09967ed6d1
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/resources/clamped-time-origin.js
@@ -0,0 +1,30 @@
+const run_test = isolated => {
+ // Multiplier to convert the clamped timestamps to microseconds.
+ const multiplier = 1000;
+ const windowOrigin = performance.timeOrigin;
+ // Clamp to at least 5 microseconds in isolated contexts and at least 100 in
+ // non-isolated ones.
+ const resolution = isolated ? 5 : 100;
+
+ const create_worker = () => {
+ return new Promise(resolve => {
+ const workerScript = 'postMessage({timeOrigin: performance.timeOrigin})';
+ const blob = new Blob([workerScript]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', event => {
+ resolve(event.data.timeOrigin);
+ });
+ });
+ };
+ promise_test(async t => {
+ assert_equals(self.crossOriginIsolated, isolated,
+ "crossOriginIsolated is properly set");
+ let prev = windowOrigin;
+ let current;
+ for (let i = 1; i < 100; ++i) {
+ current = await create_worker();
+ assert_true(current === prev || current - prev > resolution / 1000);
+ prev = current;
+ }
+ }, 'timeOrigins are clamped.');
+};
diff --git a/testing/web-platform/tests/hr-time/resources/now_frame.html b/testing/web-platform/tests/hr-time/resources/now_frame.html
new file mode 100644
index 0000000000..5bec688af9
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/resources/now_frame.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
+ <title>window.performance.now frame</title>
+ <link rel="author" title="Google" href="http://www.google.com/" />
+ </head>
+ <body></body>
+</html>
diff --git a/testing/web-platform/tests/hr-time/resources/post.html b/testing/web-platform/tests/hr-time/resources/post.html
new file mode 100644
index 0000000000..b8541016dd
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/resources/post.html
@@ -0,0 +1,4 @@
+<!DOCTYPE HTML>
+<script>
+ window.parent.postMessage('done');
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/hr-time/resources/timing-attack.js b/testing/web-platform/tests/hr-time/resources/timing-attack.js
new file mode 100644
index 0000000000..f1fc786903
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/resources/timing-attack.js
@@ -0,0 +1,42 @@
+function run_test(isolated) {
+ let resolution = 100;
+ if (isolated) {
+ resolution = 5;
+ }
+ test(function() {
+ function check_resolutions(times, length) {
+ const end = length - 2;
+
+ // we compare each value with the following ones
+ for (let i = 0; i < end; i++) {
+ const h1 = times[i];
+ for (let j = i+1; j < end; j++) {
+ const h2 = times[j];
+ const diff = h2 - h1;
+ assert_true((diff === 0) || ((diff * 1000) >= resolution),
+ "Differences smaller than ' + resolution + ' microseconds: " + diff);
+ }
+ }
+ return true;
+ }
+
+ const times = new Array(10);
+ let index = 0;
+ let hrt1, hrt2, hrt;
+ assert_equals(self.crossOriginIsolated, isolated, "Document cross-origin isolated value matches");
+
+ // rapid firing of performance.now
+ hrt1 = performance.now();
+ hrt2 = performance.now();
+ times[index++] = hrt1;
+ times[index++] = hrt2;
+
+ // ensure that we get performance.now() to return a different value
+ do {
+ hrt = performance.now();
+ times[index++] = hrt;
+ } while ((hrt - hrt1) === 0);
+
+ assert_true(check_resolutions(times, index), 'Difference should be at least ' + resolution + ' microseconds.');
+ }, 'The recommended minimum resolution of the Performance interface has been set to ' + resolution + ' microseconds for cross-origin isolated contexts.');
+}
diff --git a/testing/web-platform/tests/hr-time/resources/unload-a.html b/testing/web-platform/tests/hr-time/resources/unload-a.html
new file mode 100644
index 0000000000..40c1d06183
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/resources/unload-a.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Helper page for ../unload-manual.html</title>
+</head>
+<body>
+ <script src="./unload.js"></script>
+ <script>
+ setupListeners("a", "./unload-b.html");
+ </script>
+ <button id="proceed">Click me!</button>
+</body>
+</html>
diff --git a/testing/web-platform/tests/hr-time/resources/unload-b.html b/testing/web-platform/tests/hr-time/resources/unload-b.html
new file mode 100644
index 0000000000..7c2d90df27
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/resources/unload-b.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Helper page for ../unload-manual.html</title>
+</head>
+<body>
+ <script src="./unload.js"></script>
+ <script>
+ setupListeners("b", "./unload-c.html");
+ </script>
+ <button id="proceed">Click me again!</button>
+</body>
+</html>
diff --git a/testing/web-platform/tests/hr-time/resources/unload-c.html b/testing/web-platform/tests/hr-time/resources/unload-c.html
new file mode 100644
index 0000000000..731da9db75
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/resources/unload-c.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Helper page for ../unload-manual.html</title>
+</head>
+<body>
+ <script src="./unload.js"></script>
+ <script>
+ setupListeners("c", null);
+ </script>
+ <button id="proceed">Click me, one last time!</button>
+</body>
+</html>
diff --git a/testing/web-platform/tests/hr-time/resources/unload.js b/testing/web-platform/tests/hr-time/resources/unload.js
new file mode 100644
index 0000000000..ab6b121c2b
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/resources/unload.js
@@ -0,0 +1,51 @@
+const syncDelay = ms => {
+ const start = performance.now();
+ let elapsedTime;
+ do {
+ elapsedTime = performance.now() - start;
+ } while (elapsedTime < ms);
+};
+
+const markTime = (docName, lifecycleEventName) => {
+ // Calculating these values before the below `mark` invocation ensures that delays in
+ // reaching across to the other window object doesn't interfere with the correctness
+ // of the test.
+ const dateNow = Date.now();
+ const performanceNow = performance.now();
+
+ window.opener.mark({
+ docName,
+ lifecycleEventName,
+ performanceNow: performanceNow,
+ dateNow: dateNow
+ });
+};
+
+const setupUnloadPrompt = (docName, msg) => {
+ window.addEventListener("beforeunload", ev => {
+ markTime(docName, "beforeunload");
+ return ev.returnValue = msg || "Click OK to continue test."
+ });
+};
+
+const setupListeners = (docName, nextDocument) => {
+ window.addEventListener("load", () => {
+ markTime(docName, "load");
+ document.getElementById("proceed").addEventListener("click", ev => {
+ ev.preventDefault();
+ if (nextDocument) {
+ document.location = nextDocument;
+ } else {
+ window.close();
+ }
+ })
+ });
+
+ setupUnloadPrompt(docName);
+
+ window.addEventListener("unload", () => {
+ markTime(docName, "unload");
+ if (docName !== "c") { syncDelay(1000); }
+ });
+};
+
diff --git a/testing/web-platform/tests/hr-time/test_cross_frame_start.html b/testing/web-platform/tests/hr-time/test_cross_frame_start.html
new file mode 100644
index 0000000000..30e804bd73
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/test_cross_frame_start.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" >
+ <title>window.performance.now across frames</title>
+ <link rel="author" title="Google" href="http://www.google.com/">
+ <link rel="help" href="http://www.w3.org/TR/hr-time/#sec-extenstions-performance-interface">
+
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+
+ <script type="text/javascript">
+ setup({explicit_done: true});
+
+ var setup_frame = async_test("Setup the frame");
+
+ function start_test() {
+ setup_frame.step_timeout(function () {
+ var iframe = document.createElement('iframe');
+ iframe.id = 'frameContext';
+ iframe.onload = finish_test;
+ iframe.src = "resources/now_frame.html";
+ document.body.appendChild(iframe);
+ setup_frame.done();
+ }, 1000);
+ }
+
+ function finish_test() {
+ var childWindow = document.getElementById('frameContext').contentWindow;
+
+ // Verify a positive number is returned for both the frame and parent.
+ test(function() { assert_true(window.performance.now() > 0); }, 'parent performance.now() > 0');
+ test(function() { assert_true(childWindow.performance.now() > 0); }, 'child performance.now() > 0');
+
+ // Verify that the test properly created the child at least a second after the parent.
+ test(function () { assert_true(childWindow.performance.timing.navigationStart > (window.performance.timing.navigationStart + 1000)); },
+ 'Child created at least 1 second after parent');
+
+ test(function () {
+ var parentNow = window.performance.now();
+ var childNow = childWindow.performance.now();
+ var childParentSkew = Math.abs(childNow - parentNow);
+ assert_true(childParentSkew > 1000, 'Child and parent\'s now()s have different bases (skewed more than 1 second)');
+
+ var childLoadTime = childWindow.performance.timing.loadEventStart - childWindow.performance.timing.navigationStart;
+ assert_true(1000 > (childNow - childLoadTime), 'Child\'s now() is based on its document\'s navigationStart');
+ }, 'Child and parent time bases are correct');
+
+ done();
+ }
+ </script>
+
+ </head>
+ <body onload="start_test()">
+ <h1>Description</h1>
+ <p>This test validates the values of the window.performance.now() are based on the current document's navigationStart.</p>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/hr-time/timeOrigin.html b/testing/web-platform/tests/hr-time/timeOrigin.html
new file mode 100644
index 0000000000..20aea75084
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/timeOrigin.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<html>
+<head>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script>
+const windowOrigin = performance.timeOrigin;
+
+test(() => {
+ // Use a 30ms cushion when comparing with Date() to account for inaccuracy.
+ const startTime = Date.now();
+ assert_greater_than_equal(startTime + 30, windowOrigin, 'Date.now() should be at least as large as the window timeOrigin.');
+ const startNow = performance.now();
+ assert_less_than_equal(startTime, windowOrigin + startNow + 30, 'Date.now() should be close to window timeOrigin.');
+}, 'Window timeOrigin is close to Date.now() when there is no system clock adjustment.');
+
+const workerScript = 'postMessage({timeOrigin: performance.timeOrigin})';
+const blob = new Blob([workerScript]);
+
+async_test(function(t) {
+ const beforeWorkerCreation = performance.now();
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', t.step_func_done(function(event) {
+ const workerOrigin = event.data.timeOrigin;
+ assert_greater_than_equal(workerOrigin, windowOrigin + beforeWorkerCreation, 'Worker timeOrigin should be greater than the window timeOrigin.');
+ const afterWorkerCreation = performance.now();
+ assert_less_than_equal(workerOrigin - windowOrigin, afterWorkerCreation, 'Window and worker timeOrigins should be close.');
+ }));
+}, 'Window and worker timeOrigins are close when created one after another.');
+
+async_test(function(t) {
+ this.step_timeout(function() {
+ const workerCreation = performance.now();
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', t.step_func_done(function(event) {
+ const workerOrigin = event.data.timeOrigin;
+ assert_greater_than_equal(workerOrigin - windowOrigin, 200, 'We waited 200ms to spawn the second worker, so its timeOrigin should be greater than that of the window.');
+ }));
+ }, 200);
+}, 'Window and worker timeOrigins differ when worker is created after a delay.');
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/hr-time/timing-attack.html b/testing/web-platform/tests/hr-time/timing-attack.html
new file mode 100644
index 0000000000..6352b4dbe3
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/timing-attack.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>window.performance.now should not enable timing attacks</title>
+<link rel="author" title="W3C" href="http://www.w3.org/" />
+<link rel="help" href="http://w3c.github.io/hr-time/#privacy-security"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/timing-attack.js"></script>
+<script>
+run_test(/*isolated=*/false);
+</script>
+</head>
+<body>
+<h1>Description</h1>
+<p>The recommended minimum resolution of the Performance interface should be set to 100 microseconds for non-isolated contexts.</p>
+
+<div id="log"></div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/hr-time/unload-manual.html b/testing/web-platform/tests/hr-time/unload-manual.html
new file mode 100644
index 0000000000..18c4e0dc32
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/unload-manual.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>time origin value manual test</title>
+ <link rel="help" href="https://w3c.github.io/hr-time/#time-origin-1">
+ <link rel="prefetch" href="./resources/unload-a.html">
+ <link rel="prefetch" href="./resources/unload-b.html">
+ <link rel="prefetch" href="./resources/unload-c.html">
+</head>
+<body>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script>
+ setup({ explicit_timeout: true });
+
+ const ACCEPTABLE_VARIANCE = 400; // ms
+
+ const isRoughlyEqual = (a, b) => Math.abs(a - b) < ACCEPTABLE_VARIANCE;
+
+ const timings = { a: {}, b: {}, c: {} };
+ const t = async_test("hr-time time origin");
+
+ window.mark = msg => {
+ timings[msg.docName][msg.lifecycleEventName] = {
+ performanceNow: msg.performanceNow,
+ dateNow: msg.dateNow
+ };
+
+ if (msg.docName === "c" && msg.lifecycleEventName === "unload") {
+ setTimeout(makeAssertions, 0);
+ }
+ };
+
+ function makeAssertions () {
+ t.step(() => {
+ const loadTimeBetweenAandB = timings.b.load.dateNow - timings.a.unload.dateNow;
+ const loadTimeBetweenBandC = timings.c.load.dateNow - timings.b.unload.dateNow;
+
+ assert_true(
+ isRoughlyEqual(loadTimeBetweenAandB, timings.b.load.performanceNow),
+ "Document in reused window's time origin should be time of close of pop-up box."
+ );
+ assert_true(
+ isRoughlyEqual(loadTimeBetweenBandC, timings.c.load.performanceNow),
+ "Document in reused window's time origin should be time of close of pop-up box."
+ );
+ assert_true(
+ !isRoughlyEqual(timings.a.unload.performanceNow, 0),
+ "Time origin during unload event should match that of rest of document."
+ );
+ assert_true(
+ !isRoughlyEqual(timings.b.unload.performanceNow, 0),
+ "Time origin during unload event should match that of rest of document."
+ );
+ assert_true(
+ !isRoughlyEqual(timings.c.unload.performanceNow, 0),
+ "Time origin during unload event should match that of rest of document."
+ );
+ });
+ t.done();
+ }
+ </script>
+
+ <h2>Description</h2>
+ <p>This test validates the behavior of <code>performance.now()</code> with respect to its time origin.</p>
+ <div id="log">
+ <h2>Manual Test Steps</h2>
+ <ol>
+ <li><a href="resources/unload-a.html" target="_blank">Click here</a>
+ </ol>
+ </div>
+</body>
+<html>
diff --git a/testing/web-platform/tests/hr-time/window-worker-timeOrigin.window.js b/testing/web-platform/tests/hr-time/window-worker-timeOrigin.window.js
new file mode 100644
index 0000000000..1e5ef1cdff
--- /dev/null
+++ b/testing/web-platform/tests/hr-time/window-worker-timeOrigin.window.js
@@ -0,0 +1,30 @@
+"use strict"
+// https://w3c.github.io/hr-time/#time-origin
+
+async_test(function(test) {
+ // Cache global time before starting worker
+ const globalTimeOrigin = performance.timeOrigin;
+ const globalNowBeforeWorkerStart = performance.now();
+
+ // Start worker and retrieve time
+ const workerScript = "postMessage({timeOrigin: performance.timeOrigin, now: performance.now()})";
+ const blob = new Blob([workerScript]);
+ let worker = new Worker(URL.createObjectURL(blob));
+
+ worker.addEventListener("message", test.step_func_done(function(event) {
+ const workerTimeOrigin = event.data.timeOrigin;
+ const workerNow = event.data.now;
+
+ assert_not_equals(workerTimeOrigin, 0, "worker timeOrigin must not be 0");
+ assert_not_equals(performance.timeOrigin, 0, "Document timeOrigin must not be 0");
+
+ assert_equals(globalTimeOrigin, performance.timeOrigin, "timeOrigin should not be changed in same document mode");
+ assert_less_than(globalTimeOrigin, workerTimeOrigin, "Document timeOrigin must be earlier than worker timeOrigin");
+
+ // Document and worker's now() start from their respective timeOrigins.
+ const timeDiff = workerTimeOrigin - globalTimeOrigin; // convert worker's time to Document time.
+ assert_less_than(globalTimeOrigin + globalNowBeforeWorkerStart, globalTimeOrigin + timeDiff + workerNow, "Document old now is earlier than worker now.");
+
+ // Comparing timing between Document and worker threads could be delicate as it relies on the thread implementation and could be subject to race conditions.
+ }));
+}, 'timeOrigin and now() should be correctly ordered between window and worker');