summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/idle-detection
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/idle-detection
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/idle-detection')
-rw-r--r--testing/web-platform/tests/idle-detection/META.yml5
-rw-r--r--testing/web-platform/tests/idle-detection/WEB_FEATURES.yml3
-rw-r--r--testing/web-platform/tests/idle-detection/basics.tentative.https.window.js98
-rw-r--r--testing/web-platform/tests/idle-detection/idle-detection-allowed-by-permissions-policy-attribute-redirect-on-load.https.sub.html52
-rw-r--r--testing/web-platform/tests/idle-detection/idle-detection-allowed-by-permissions-policy-attribute.https.sub.html48
-rw-r--r--testing/web-platform/tests/idle-detection/idle-detection-allowed-by-permissions-policy.https.sub.html57
-rw-r--r--testing/web-platform/tests/idle-detection/idle-detection-allowed-by-permissions-policy.https.sub.html.headers1
-rw-r--r--testing/web-platform/tests/idle-detection/idle-detection-default-permissions-policy.https.sub.html39
-rw-r--r--testing/web-platform/tests/idle-detection/idle-detection-detached-frame.https.html29
-rw-r--r--testing/web-platform/tests/idle-detection/idle-detection-disabled-by-permissions-policy.https.sub.html56
-rw-r--r--testing/web-platform/tests/idle-detection/idle-detection-disabled-by-permissions-policy.https.sub.html.headers1
-rw-r--r--testing/web-platform/tests/idle-detection/idle-permission.tentative.https.window.js34
-rw-r--r--testing/web-platform/tests/idle-detection/idlharness-worker.https.window.js10
-rw-r--r--testing/web-platform/tests/idle-detection/idlharness.https.window.js26
-rw-r--r--testing/web-platform/tests/idle-detection/interceptor.https.html378
-rw-r--r--testing/web-platform/tests/idle-detection/page-visibility.https.html79
-rw-r--r--testing/web-platform/tests/idle-detection/resources/idle-detection-allowed-by-permissions-policy-worker.js16
-rw-r--r--testing/web-platform/tests/idle-detection/resources/idle-detection-disabled-by-permissions-policy-worker.js22
-rw-r--r--testing/web-platform/tests/idle-detection/resources/idle-detection-helper.js14
-rw-r--r--testing/web-platform/tests/idle-detection/resources/idlharness-worker.js22
20 files changed, 990 insertions, 0 deletions
diff --git a/testing/web-platform/tests/idle-detection/META.yml b/testing/web-platform/tests/idle-detection/META.yml
new file mode 100644
index 0000000000..adbdc7bd93
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/META.yml
@@ -0,0 +1,5 @@
+spec: https://wicg.github.io/idle-detection/
+suggested_reviewers:
+ - goto
+ - jsbell
+ - reillyg \ No newline at end of file
diff --git a/testing/web-platform/tests/idle-detection/WEB_FEATURES.yml b/testing/web-platform/tests/idle-detection/WEB_FEATURES.yml
new file mode 100644
index 0000000000..1e208f268e
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: idle-detection
+ files: "**"
diff --git a/testing/web-platform/tests/idle-detection/basics.tentative.https.window.js b/testing/web-platform/tests/idle-detection/basics.tentative.https.window.js
new file mode 100644
index 0000000000..32cb6204b9
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/basics.tentative.https.window.js
@@ -0,0 +1,98 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: title=Idle Detection API: Basics
+
+'use strict';
+
+promise_setup(async t => {
+ await test_driver.set_permission({name: 'idle-detection'}, 'granted');
+})
+
+promise_test(async t => {
+ let detector = new IdleDetector();
+ let watcher = new EventWatcher(t, detector, ["change"]);
+ let initial_state = watcher.wait_for("change");
+
+ await detector.start();
+ await initial_state;
+
+ assert_true(['active', 'idle'].includes(detector.userState),
+ 'has a valid user state');
+ assert_true(['locked', 'unlocked'].includes(detector.screenState),
+ 'has a valid screen state');
+}, 'start() basics');
+
+promise_test(async t => {
+ let used = false;
+
+ const detector = new IdleDetector();
+ detector.start({
+ get threshold() {
+ used = true;
+ return 60000;
+ }
+ });
+
+ assert_true(used, 'start() options "threshold" member was used');
+}, 'start() uses threshold property');
+
+promise_test(async t => {
+ let used = false;
+
+ const controller = new AbortController();
+ const detector = new IdleDetector();
+ detector.start({
+ get signal() {
+ used = true;
+ return controller.signal;
+ }
+ });
+
+ assert_true(used, 'start() options "signal" member was used');
+}, 'start() uses signal property');
+
+
+promise_test(async t => {
+ const detector = new IdleDetector();
+ await promise_rejects_js(t, TypeError, detector.start({threshold: 0}));
+}, 'start() rejects with invalid threshold (0)');
+
+promise_test(async t => {
+ const detector = new IdleDetector();
+ await promise_rejects_js(t, TypeError, detector.start({threshold: 59000}));
+}, 'start() rejects with threshold below minimum (59000)');
+
+promise_test(async t => {
+ const detector = new IdleDetector();
+ await detector.start({threshold: 60000});
+}, 'start() rejects threshold (60000)');
+
+promise_test(async t => {
+ const detector = new IdleDetector();
+ await detector.start({threshold: 61000});
+}, 'start() allows threshold (61000)');
+
+promise_test(async t => {
+ const detector = new IdleDetector();
+ await promise_rejects_js(t, TypeError, detector.start({threshold: null}));
+}, 'start() rejects with invalid threshold (null)');
+
+promise_test(async t => {
+ const detector = new IdleDetector();
+ await promise_rejects_js(t, TypeError, detector.start({threshold: -1}));
+}, 'start() rejects with invalid threshold (-1)');
+
+promise_test(async t => {
+ const detector = new IdleDetector();
+ await promise_rejects_js(t, TypeError, detector.start({threshold: NaN}));
+}, 'start() rejects with invalid threshold (NaN)');
+
+promise_test(async t => {
+ const detector = new IdleDetector();
+ await detector.start();
+}, 'start() uses a default value for the threshold when none is passed');
+
+promise_test(async t => {
+ const detector = new IdleDetector();
+ await detector.start({threshold: undefined});
+}, 'start() uses a default value for the threshold');
diff --git a/testing/web-platform/tests/idle-detection/idle-detection-allowed-by-permissions-policy-attribute-redirect-on-load.https.sub.html b/testing/web-platform/tests/idle-detection/idle-detection-allowed-by-permissions-policy-attribute-redirect-on-load.https.sub.html
new file mode 100644
index 0000000000..e419840ccd
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/idle-detection-allowed-by-permissions-policy-attribute-redirect-on-load.https.sub.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<body>
+<script src=/resources/testdriver.js></script>
+<script src=/resources/testdriver-vendor.js></script>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/permissions-policy/resources/permissions-policy.js></script>
+<script>
+'use strict';
+
+const base_src = '/permissions-policy/resources/redirect-on-load.html#';
+const sub = 'https://{{domains[www]}}:{{ports[https][0]}}';
+const relative_path =
+ '/permissions-policy/resources/permissions-policy-idle-detection.html';
+const relative_worker_frame_path =
+ '/permissions-policy/resources/permissions-policy-idle-detection-worker.html';
+const same_origin_src = base_src + relative_path;
+const same_origin_worker_frame_src = base_src + relative_worker_frame_path;
+const cross_origin_src = base_src + sub + relative_path;
+const cross_origin_worker_frame_src = base_src + sub +
+ relative_worker_frame_path;
+
+promise_setup(async () => {
+ await test_driver.set_permission({ name: 'idle-detection' }, 'granted');
+});
+
+promise_test(async t => {
+ test_feature_availability('new IdleDetector().start()', t, same_origin_src,
+ expect_feature_available_default, 'idle-detection');
+}, 'Attribute allow="idle-detection" in top-level frame ' +
+ 'allows same-origin relocation.');
+
+promise_test(async t => {
+ test_feature_availability('new IdleDetector().start()', t, same_origin_worker_frame_src,
+ expect_feature_available_default, 'idle-detection');
+}, 'Attribute allow="idle-detection" in top-level frame ' +
+ 'allows workers in same-origin relocation.');
+
+promise_test(async t => {
+ test_feature_availability('new IdleDetector().start()', t, cross_origin_src,
+ expect_feature_unavailable_default, 'idle-detection');
+}, 'Attribute allow="idle-detection" in top-level frame ' +
+ 'disallows cross-origin relocation.');
+
+promise_test(async t => {
+ test_feature_availability('new IdleDetector().start()', t, cross_origin_worker_frame_src,
+ expect_feature_unavailable_default, 'idle-detection');
+}, 'Attribute allow="idle-detection" in top-level frame ' +
+ 'disallows workers in cross-origin relocation.');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/idle-detection/idle-detection-allowed-by-permissions-policy-attribute.https.sub.html b/testing/web-platform/tests/idle-detection/idle-detection-allowed-by-permissions-policy-attribute.https.sub.html
new file mode 100644
index 0000000000..e05772d9bc
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/idle-detection-allowed-by-permissions-policy-attribute.https.sub.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<body>
+<script src=/resources/testdriver.js></script>
+<script src=/resources/testdriver-vendor.js></script>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/permissions-policy/resources/permissions-policy.js></script>
+<script>
+'use strict';
+
+const sub = 'https://{{domains[www]}}:{{ports[https][0]}}';
+const same_origin_src =
+ '/permissions-policy/resources/permissions-policy-idle-detection.html'
+const same_origin_worker_frame_src =
+ '/permissions-policy/resources/permissions-policy-idle-detection-worker.html';
+const cross_origin_src = sub + same_origin_src;
+const cross_origin_worker_frame_src = sub + same_origin_worker_frame_src;
+
+promise_setup(async () => {
+ await test_driver.set_permission({ name: 'idle-detection' }, 'granted');
+});
+
+promise_test(async t => {
+ test_feature_availability('new IdleDetector().start()', t, same_origin_src,
+ expect_feature_available_default, 'idle-detection');
+}, 'Attribute allow="idle-detection" in top-level frame can be enabled ' +
+ 'in same-origin iframe using Permissions Policy "idle-detection".');
+
+promise_test(async t => {
+ test_feature_availability('new IdleDetector().start()', t, same_origin_worker_frame_src,
+ expect_feature_available_default, 'idle-detection');
+}, 'Attribute allow="idle-detection" in top-level frame can be enabled ' +
+ 'in a worker in same-origin iframe using Permissions Policy "idle-detection".');
+
+promise_test(async t => {
+ test_feature_availability('new IdleDetector().start()', t, cross_origin_src,
+ expect_feature_available_default, 'idle-detection');
+}, 'Attribute allow="idle-detection" in top-level frame can be enabled ' +
+ 'in cross-origin iframe using Permissions Policy "idle-detection".');
+
+promise_test(async t => {
+ test_feature_availability('new IdleDetector().start()', t, cross_origin_worker_frame_src,
+ expect_feature_available_default, 'idle-detection');
+}, 'Attribute allow="idle-detection" in top-level frame can be enabled ' +
+ 'in a worker in cross-origin iframe using Permissions Policy "idle-detection".');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/idle-detection/idle-detection-allowed-by-permissions-policy.https.sub.html b/testing/web-platform/tests/idle-detection/idle-detection-allowed-by-permissions-policy.https.sub.html
new file mode 100644
index 0000000000..6fae367730
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/idle-detection-allowed-by-permissions-policy.https.sub.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<body>
+<script src=/resources/testdriver.js></script>
+<script src=/resources/testdriver-vendor.js></script>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/permissions-policy/resources/permissions-policy.js></script>
+<script>
+'use strict';
+
+const sub = 'https://{{domains[www]}}:{{ports[https][0]}}';
+const same_origin_src =
+ '/permissions-policy/resources/permissions-policy-idle-detection.html'
+const same_origin_worker_frame_src =
+ '/permissions-policy/resources/permissions-policy-idle-detection-worker.html';
+const cross_origin_src = sub + same_origin_src;
+const cross_origin_worker_frame_src = sub + same_origin_worker_frame_src;
+
+promise_setup(async () => {
+ await test_driver.set_permission({ name: 'idle-detection' }, 'granted');
+});
+
+promise_test(async t => {
+ await new IdleDetector().start();
+},
+ 'Permissions-Policy idle-detection=* explicity set by top-level ' +
+ 'frame allows the top-level document.');
+
+promise_test(async t => {
+ test_feature_availability('new IdleDetector().start()', t, same_origin_src,
+ expect_feature_available_default);
+}, 'Permissions-Policy idle-detection=* explicity set by top-level ' +
+ 'frame allows same-origin iframes.');
+
+promise_test(async t => {
+ test_feature_availability('new IdleDetector().start()', t, same_origin_worker_frame_src,
+ expect_feature_available_default);
+}, 'Permissions-Policy idle-detection=* explicity set by top-level ' +
+ 'frame allows workers in same-origin iframes.');
+
+promise_test(async t => {
+ test_feature_availability('new IdleDetector().start()', t, cross_origin_src,
+ expect_feature_available_default);
+}, 'Permissions-Policy idle-detection=* explicity set by top-level ' +
+ 'frame allows cross-origin iframes.');
+
+promise_test(async t => {
+ test_feature_availability('new IdleDetector().start()', t, cross_origin_worker_frame_src,
+ expect_feature_available_default);
+}, 'Permissions-Policy idle-detection=* explicity set by top-level ' +
+ 'frame allows workers in cross-origin iframes.');
+
+fetch_tests_from_worker(new Worker(
+ 'resources/idle-detection-allowed-by-permissions-policy-worker.js'))
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/idle-detection/idle-detection-allowed-by-permissions-policy.https.sub.html.headers b/testing/web-platform/tests/idle-detection/idle-detection-allowed-by-permissions-policy.https.sub.html.headers
new file mode 100644
index 0000000000..2bf18afe5f
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/idle-detection-allowed-by-permissions-policy.https.sub.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: idle-detection=*
diff --git a/testing/web-platform/tests/idle-detection/idle-detection-default-permissions-policy.https.sub.html b/testing/web-platform/tests/idle-detection/idle-detection-default-permissions-policy.https.sub.html
new file mode 100644
index 0000000000..90cb7f88d3
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/idle-detection-default-permissions-policy.https.sub.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<body>
+<script src=/resources/testdriver.js></script>
+<script src=/resources/testdriver-vendor.js></script>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/permissions-policy/resources/permissions-policy.js></script>
+<script>
+'use strict';
+
+const same_origin_src =
+ '/permissions-policy/resources/permissions-policy-idle-detection.html'
+const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
+ same_origin_src;
+
+promise_setup(async () => {
+ await test_driver.set_permission({ name: 'idle-detection' }, 'granted');
+});
+
+promise_test(async t => {
+ await new IdleDetector().start()
+},
+ 'Default "idle-detection" permissions policy "self" ' +
+ 'allows the top-level document.');
+
+promise_test(async t => {
+ test_feature_availability('new IdleDetector().start()', t, same_origin_src,
+ expect_feature_available_default);
+}, 'Default "idle-detection" permissions policy "self" ' +
+ 'allows same-origin iframes.');
+
+promise_test(async t => {
+ test_feature_availability('new IdleDetector().start()', t, cross_origin_src,
+ expect_feature_unavailable_default);
+}, 'Default "idle-detection" permissions policy "self" ' +
+ 'disallows cross-origin iframes.');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/idle-detection/idle-detection-detached-frame.https.html b/testing/web-platform/tests/idle-detection/idle-detection-detached-frame.https.html
new file mode 100644
index 0000000000..062499b54d
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/idle-detection-detached-frame.https.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<body>
+<script src=/resources/testdriver.js></script>
+<script src=/resources/testdriver-vendor.js></script>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+
+<script>
+'use strict';
+
+promise_test(async t => {
+ await new Promise((resolve) => {
+ window.addEventListener('load', resolve);
+ });
+ await test_driver.set_permission({name: 'idle-detection'}, 'granted');
+
+ const frame = document.body.appendChild(document.createElement('iframe'));
+ const frameIdleDetector = frame.contentWindow.IdleDetector;
+ const frameDOMException = frame.contentWindow.DOMException;
+
+ let detector = new frameIdleDetector();
+ document.body.outerHTML = "";
+ await promise_rejects_dom(t, 'InvalidStateError', frameDOMException, detector.start());
+
+ detector = new frameIdleDetector();
+ return promise_rejects_dom(t, 'InvalidStateError', frameDOMException, detector.start());
+}, 'Using an IdleDetector from a detached frame');
+
+</script>
diff --git a/testing/web-platform/tests/idle-detection/idle-detection-disabled-by-permissions-policy.https.sub.html b/testing/web-platform/tests/idle-detection/idle-detection-disabled-by-permissions-policy.https.sub.html
new file mode 100644
index 0000000000..90317dece7
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/idle-detection-disabled-by-permissions-policy.https.sub.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<body>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/permissions-policy/resources/permissions-policy.js></script>
+<script>
+'use strict';
+
+const sub = 'https://{{domains[www]}}:{{ports[https][0]}}';
+const same_origin_src =
+ '/permissions-policy/resources/permissions-policy-idle-detection.html'
+const same_origin_worker_frame_src =
+ '/permissions-policy/resources/permissions-policy-idle-detection-worker.html';
+const cross_origin_src = sub + same_origin_src;
+const cross_origin_worker_frame_src = sub + same_origin_worker_frame_src;
+
+promise_test(async () => {
+ try {
+ let idleDetector = new IdleDetector();
+ await idleDetector.start();
+ assert_unreached('expected promise to reject with SecurityError');
+ } catch (error) {
+ assert_equals(error.name, 'SecurityError');
+ }
+}, 'Permissions-Policy idle-detection=() explicitly set by top-level frame ' +
+ 'disallows query in the top-level document.');
+
+async_test(t => {
+ test_feature_availability('new IdleDetector().start()', t, same_origin_src,
+ expect_feature_unavailable_default);
+}, 'Permissions-Policy idle-detection=() explicitly set by top-level frame ' +
+ 'disallows same-origin iframes.');
+
+async_test(t => {
+ test_feature_availability('new IdleDetector().start()', t, same_origin_worker_frame_src,
+ expect_feature_unavailable_default);
+}, 'Permissions-Policy idle-detection=() explicitly set by top-level frame ' +
+ 'disallows workers in same-origin iframes.');
+
+async_test(t => {
+ test_feature_availability('new IdleDetector().start()', t, cross_origin_src,
+ expect_feature_unavailable_default);
+}, 'Permissions-Policy idle-detection=() explicitly set by top-level frame ' +
+ 'disallows cross-origin iframes.');
+
+async_test(t => {
+ test_feature_availability('new IdleDetector().start()', t, cross_origin_worker_frame_src,
+ expect_feature_unavailable_default);
+}, 'Permissions-Policy idle-detection=() explicitly set by top-level frame ' +
+ 'disallows workers in cross-origin iframes.');
+
+fetch_tests_from_worker(new Worker(
+ 'resources/idle-detection-disabled-by-permissions-policy-worker.js'))
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/idle-detection/idle-detection-disabled-by-permissions-policy.https.sub.html.headers b/testing/web-platform/tests/idle-detection/idle-detection-disabled-by-permissions-policy.https.sub.html.headers
new file mode 100644
index 0000000000..289463c30d
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/idle-detection-disabled-by-permissions-policy.https.sub.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: idle-detection=()
diff --git a/testing/web-platform/tests/idle-detection/idle-permission.tentative.https.window.js b/testing/web-platform/tests/idle-detection/idle-permission.tentative.https.window.js
new file mode 100644
index 0000000000..524062f9f3
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/idle-permission.tentative.https.window.js
@@ -0,0 +1,34 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+'use strict';
+
+promise_test(async t => {
+ await test_driver.set_permission({name: 'idle-detection'}, 'denied');
+
+ let detector = new IdleDetector();
+ await promise_rejects_dom(t, 'NotAllowedError', detector.start());
+}, 'Denying idle-detection permission should block access.');
+
+promise_test(async t => {
+ await test_driver.set_permission({name: 'idle-detection'}, 'granted');
+
+ let detector = new IdleDetector();
+ await detector.start();
+
+ assert_true(
+ ['active', 'idle'].includes(detector.userState),
+ 'has a valid user state');
+ assert_true(
+ ['locked', 'unlocked'].includes(detector.screenState),
+ 'has a valid screen state');
+}, 'Granting idle-detection permission should allow access.');
+
+promise_test(async t => {
+ await test_driver.set_permission({name: 'idle-detection'}, 'prompt');
+
+ await promise_rejects_dom(t, 'NotAllowedError', IdleDetector.requestPermission());
+
+ await test_driver.bless('request permission');
+ let state = await IdleDetector.requestPermission();
+ assert_equals(state, 'prompt');
+}, 'The idle-detection permission cannot be requested without a user gesture');
diff --git a/testing/web-platform/tests/idle-detection/idlharness-worker.https.window.js b/testing/web-platform/tests/idle-detection/idlharness-worker.https.window.js
new file mode 100644
index 0000000000..e8fcf9ede6
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/idlharness-worker.https.window.js
@@ -0,0 +1,10 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+
+'use strict';
+
+promise_test(async t => {
+ await test_driver.set_permission({name: 'idle-detection'}, 'granted');
+
+ await fetch_tests_from_worker(new Worker('resources/idlharness-worker.js'));
+}, 'Run idlharness tests in a worker.');
diff --git a/testing/web-platform/tests/idle-detection/idlharness.https.window.js b/testing/web-platform/tests/idle-detection/idlharness.https.window.js
new file mode 100644
index 0000000000..2f1758098f
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/idlharness.https.window.js
@@ -0,0 +1,26 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+
+// https://github.com/samuelgoto/idle-detection
+
+'use strict';
+
+idl_test(
+ ['idle-detection'],
+ ['dom', 'html'],
+ async (idl_array, t) => {
+ await test_driver.set_permission({ name: 'idle-detection' }, 'granted');
+
+ self.idle = new IdleDetector();
+ let watcher = new EventWatcher(t, self.idle, ["change"]);
+ let initial_state = watcher.wait_for("change");
+ await self.idle.start();
+ await initial_state;
+
+ idl_array.add_objects({
+ IdleDetector: ['idle'],
+ });
+ }
+);
diff --git a/testing/web-platform/tests/idle-detection/interceptor.https.html b/testing/web-platform/tests/idle-detection/interceptor.https.html
new file mode 100644
index 0000000000..e9350ce8ce
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/interceptor.https.html
@@ -0,0 +1,378 @@
+<!DOCTYPE html>
+<link rel="help" href="https://github.com/samuelgoto/idle-detection">
+<title>Tests the Idle Detection API</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/test-only-api.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/idle-detection-helper.js"></script>
+<script>
+'use strict';
+
+promise_setup(async t => {
+ await test_driver.set_permission({ name: 'idle-detection' }, 'granted');
+ if (isChromiumBased) {
+ await loadChromiumResources();
+ }
+})
+
+promise_test(async t => {
+ // Basic test that expects start() to call internally
+ // addMonitor, which in turn return an ACTIVE state.
+ expect(addMonitor).andReturn(async (monitorPtr) => {
+ return {
+ error: IdleDetectorError.SUCCESS,
+ state: {
+ idleTime: null,
+ screenLocked: true
+ }
+ };
+ });
+
+ const controller = new AbortController();
+ const detector = new IdleDetector();
+ const watcher = new EventWatcher(t, detector, ["change"]);
+ const initial_state = watcher.wait_for("change");
+
+ await detector.start({ signal: controller.signal });
+ await initial_state;
+
+ assert_equals(detector.userState, "active");
+ assert_equals(detector.screenState, "locked");
+
+ controller.abort();
+}, 'start()');
+
+promise_test(async t => {
+ // Verifies that an event is thrown when a change of state from IDLE to ACTIVE
+ // is detected.
+ expect(addMonitor).andReturn(async (monitorPtr) => {
+ const first = {
+ error: IdleDetectorError.SUCCESS,
+ state: {
+ idleTime: null,
+ screenLocked: false
+ }
+ };
+
+ t.step_timeout(() => {
+ monitorPtr.update(
+ {
+ idleTime: { milliseconds: 0 },
+ screenLocked: false
+ },
+ /*is_overridden_by_devtools=*/true
+ );
+ }, 0);
+
+ return first;
+ });
+
+ const controller = new AbortController();
+ const detector = new IdleDetector();
+ const watcher = new EventWatcher(t, detector, ["change"]);
+ const initial_state = watcher.wait_for("change");
+
+ await detector.start({ signal: controller.signal });
+ await initial_state;
+ assert_equals(detector.userState, "active");
+ assert_equals(detector.screenState, "unlocked");
+
+ // Wait for the first change in state.
+ await watcher.wait_for("change");
+
+ assert_equals(detector.userState, "idle");
+ assert_equals(detector.screenState, "unlocked");
+
+ controller.abort();
+}, 'updates once');
+
+promise_test(async t => {
+ // Simulates the user being active, going idle and then going back active
+ // again.
+ expect(addMonitor).andReturn(async (monitorPtr) => {
+ const first = {
+ error: IdleDetectorError.SUCCESS,
+ state: {
+ idleTime: null,
+ screenLocked: false
+ }
+ };
+
+ // Updates the client once with the user idle.
+ t.step_timeout(() => {
+ monitorPtr.update(
+ {
+ idleTime: { milliseconds: 0 },
+ screenLocked: false
+ },
+ /*is_overridden_by_devtools=*/true
+ );
+ }, 0);
+
+ // Updates the client a second time with the user active.
+ t.step_timeout(() => {
+ monitorPtr.update(
+ {
+ idleTime: null,
+ screenLocked: false
+ },
+ /*is_overridden_by_devtools=*/true
+ );
+ }, 1);
+
+ return first;
+ });
+
+ const controller = new AbortController();
+ const detector = new IdleDetector();
+ const watcher = new EventWatcher(t, detector, ["change"]);
+ const initial_state = watcher.wait_for("change");
+
+ await detector.start({ signal: controller.signal });
+ await initial_state;
+
+ // Waits for the first event.
+ await watcher.wait_for("change");
+ assert_equals(detector.userState, "idle");
+
+ // Waits for the second event.
+ await watcher.wait_for("change");
+ assert_equals(detector.userState, "active");
+
+ controller.abort();
+}, 'updates twice');
+
+promise_test(async t => {
+ // Simulates a locked screen.
+ expect(addMonitor).andReturn(async (monitorPtr) => {
+ return {
+ error: IdleDetectorError.SUCCESS,
+ state: {
+ idleTime: null,
+ screenLocked: true
+ }
+ };
+ });
+
+ const controller = new AbortController();
+ const detector = new IdleDetector();
+ const watcher = new EventWatcher(t, detector, ["change"]);
+ const initial_state = watcher.wait_for("change");
+
+ await detector.start({ signal: controller.signal });
+ await initial_state;
+
+ assert_equals(detector.screenState, "locked");
+
+ controller.abort();
+}, 'locked screen');
+
+promise_test(async t => {
+ expect(addMonitor).andReturn(async (monitorPtr) => {
+ return {
+ error: IdleDetectorError.SUCCESS,
+ state: {
+ idleTime: null,
+ screenLocked: true
+ }
+ };
+ });
+
+ const controller = new AbortController();
+ const detector = new IdleDetector();
+
+ let event = new Promise((resolve, reject) => {
+ detector.onchange = resolve;
+ });
+
+ await detector.start({ signal: controller.signal });
+
+ // Waits for the first event.
+ await event;
+
+ assert_equals(detector.userState, "active");
+ assert_equals(detector.screenState, "locked");
+
+ controller.abort();
+}, 'IdleDetector.onchange');
+
+promise_test(async t => {
+ expect(addMonitor).andReturn(async (monitorPtr) => {
+ return {
+ error: IdleDetectorError.SUCCESS,
+ state: {
+ idleTime: null,
+ screenLocked: false
+ }
+ };
+ });
+
+ const controller = new AbortController();
+ const detector = new IdleDetector({ signal: controller.signal });
+
+ const watcher = new EventWatcher(t, detector, ["change"]);
+ const initial_state = watcher.wait_for("change");
+
+ // Only the first call to start() is allowed.
+ const start_promise = detector.start({ signal: controller.signal });
+ await promise_rejects_dom(t, 'InvalidStateError', detector.start());
+ await start_promise;
+
+ await initial_state;
+ assert_equals(detector.userState, "active");
+ assert_equals(detector.screenState, "unlocked");
+
+ // Calling abort() multiple times is safe.
+ controller.abort();
+ controller.abort();
+ controller.abort();
+ controller.abort();
+}, 'Calling start() and abort() multiple times');
+
+promise_test(async t => {
+ expect(addMonitor).andReturn(async (monitorPtr) => {
+ return {
+ error: IdleDetectorError.SUCCESS,
+ state: {
+ idleTime: null,
+ screenLocked: false
+ }
+ };
+ });
+
+ const controller = new AbortController();
+ const detector = new IdleDetector();
+
+ controller.abort();
+
+ await promise_rejects_dom(
+ t, 'AbortError', detector.start({ signal: controller.signal }));
+}, 'Calling abort() before start() makes it fail');
+
+promise_test(async t => {
+ expect(addMonitor).andReturn(async (monitorPtr) => {
+ return {
+ error: IdleDetectorError.SUCCESS,
+ state: {
+ idleTime: null,
+ screenLocked: false
+ }
+ };
+ });
+
+ const controller = new AbortController();
+ const detector = new IdleDetector();
+
+ const promise = promise_rejects_dom(
+ t, 'AbortError', detector.start({ signal: controller.signal }))
+ controller.abort();
+
+ await promise;
+}, 'Calling abort() after start() makes it fail');
+
+promise_test(async t => {
+ expect(addMonitor).andReturn(async (monitorPtr) => {
+ return {
+ error: IdleDetectorError.SUCCESS,
+ state: {
+ idleTime: null,
+ screenLocked: false
+ }
+ };
+ });
+
+ const detector = new IdleDetector();
+ const watcher = new EventWatcher(t, detector, ["change"]);
+
+ let controller = new AbortController();
+ const first_start = promise_rejects_dom(
+ t, 'AbortError', detector.start({ signal: controller.signal }))
+ controller.abort();
+
+ controller = new AbortController();
+ const initial_state = watcher.wait_for("change");
+ const second_start = detector.start({ signal: controller.signal });
+
+ await first_start;
+ await second_start;
+ await initial_state;
+ assert_equals(detector.userState, "active");
+ assert_equals(detector.screenState, "unlocked");
+
+ controller.abort();
+}, 'A start() that has been aborted can be retried');
+
+promise_test(async t => {
+ expect(addMonitor).andReturn(async (monitorPtr) => {
+ return {
+ error: IdleDetectorError.SUCCESS,
+ state: {
+ idleTime: null,
+ screenLocked: false
+ }
+ };
+ });
+
+ let controller = new AbortController();
+ const detector = new IdleDetector();
+ const watcher = new EventWatcher(t, detector, ["change"]);
+ let initial_state = watcher.wait_for("change");
+
+ await detector.start({ signal: controller.signal });
+ await initial_state;
+ assert_equals(detector.userState, "active");
+ assert_equals(detector.screenState, "unlocked");
+
+ controller.abort();
+
+ expect(addMonitor).andReturn(async (monitorPtr) => {
+ return {
+ error: IdleDetectorError.SUCCESS,
+ state: {
+ idleTime: { milliseconds: 0 },
+ screenLocked: true
+ }
+ };
+ });
+
+ // Restarting the monitor.
+ controller = new AbortController();
+
+ initial_state = watcher.wait_for("change");
+ await detector.start({ signal: controller.signal });
+ await initial_state;
+ assert_equals(detector.userState, "idle");
+ assert_equals(detector.screenState, "locked");
+
+ // Abort in a new task and restart the monitor again.
+ const p = new Promise((resolve) => {
+ t.step_timeout(resolve, 1);
+ });
+ await p;
+ controller.abort();
+
+ expect(addMonitor).andReturn(async (monitorPtr) => {
+ return {
+ error: IdleDetectorError.SUCCESS,
+ state: {
+ idleTime: { milliseconds: 0 },
+ screenLocked: false
+ }
+ };
+ });
+
+ // Restarting the monitor.
+ controller = new AbortController();
+
+ initial_state = watcher.wait_for("change");
+ await detector.start({ signal: controller.signal });
+ await initial_state;
+ assert_equals(detector.userState, "idle");
+ assert_equals(detector.screenState, "unlocked");
+
+ controller.abort();
+}, 'Calling start() after abort(): re-starting monitor.');
+
+</script>
diff --git a/testing/web-platform/tests/idle-detection/page-visibility.https.html b/testing/web-platform/tests/idle-detection/page-visibility.https.html
new file mode 100644
index 0000000000..550683f704
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/page-visibility.https.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<link rel="help" href="https://github.com/samuelgoto/idle-detection">
+<title>Tests the Idle Detection API</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/test-only-api.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/page-visibility/resources/window_state_context.js"></script>
+<script src="resources/idle-detection-helper.js"></script>
+<script>
+'use strict';
+
+promise_setup(async t => {
+ await test_driver.set_permission({ name: 'idle-detection' }, 'granted');
+ if (isChromiumBased) {
+ await loadChromiumResources();
+ }
+})
+
+promise_test(async t => {
+ let monitor;
+
+ expect(addMonitor).andReturn(async (monitorPtr) => {
+ monitor = monitorPtr;
+ return {
+ error: IdleDetectorError.SUCCESS,
+ state: {
+ idleTime: null,
+ screenLocked: false
+ }
+ };
+ });
+
+ const controller = new AbortController();
+ t.add_cleanup(() => {
+ controller.abort();
+ });
+ const detector = new IdleDetector();
+ const watcher = new EventWatcher(t, detector, ["change"]);
+ const initial_state = watcher.wait_for("change");
+
+ await detector.start({threshold: 60000, signal: controller.signal});
+ await initial_state;
+
+ assert_equals(detector.userState, "active");
+ assert_false(document.hidden);
+
+ const {minimize, restore} = window_state_context(t);
+
+ await minimize();
+ monitor.update(
+ {
+ idleTime: { milliseconds: 0 },
+ screenLocked: false
+ },
+ /*is_overridden_by_devtools=*/true
+ );
+
+ // Assert that the detector works while the page is not visible.
+ await watcher.wait_for("change");
+ assert_equals(detector.userState, "idle");
+ assert_true(document.hidden);
+
+ await restore();
+ monitor.update(
+ {
+ idleTime: null,
+ screenLocked: false
+ },
+ /*is_overridden_by_devtools=*/true
+ );
+
+ await watcher.wait_for("change");
+ assert_equals(detector.userState, "active");
+ assert_false(document.hidden);
+}, 'Page visibility.');
+
+</script>
diff --git a/testing/web-platform/tests/idle-detection/resources/idle-detection-allowed-by-permissions-policy-worker.js b/testing/web-platform/tests/idle-detection/resources/idle-detection-allowed-by-permissions-policy-worker.js
new file mode 100644
index 0000000000..1fe410ed11
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/resources/idle-detection-allowed-by-permissions-policy-worker.js
@@ -0,0 +1,16 @@
+'use strict';
+
+importScripts('/resources/testharness.js');
+
+let workerType;
+
+if (typeof postMessage === 'function') {
+ workerType = 'dedicated';
+}
+
+promise_test(async () => {
+ await new IdleDetector().start()
+},
+ `Inherited header permissions policy allows ${workerType} workers.`)
+
+done();
diff --git a/testing/web-platform/tests/idle-detection/resources/idle-detection-disabled-by-permissions-policy-worker.js b/testing/web-platform/tests/idle-detection/resources/idle-detection-disabled-by-permissions-policy-worker.js
new file mode 100644
index 0000000000..c30f7c188e
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/resources/idle-detection-disabled-by-permissions-policy-worker.js
@@ -0,0 +1,22 @@
+'use strict';
+
+importScripts('/resources/testharness.js');
+
+const header = 'Permissions-Policy header idle-detection=()';
+let workerType;
+
+if (typeof postMessage === 'function') {
+ workerType = 'dedicated';
+}
+
+promise_test(async () => {
+ try {
+ await new IdleDetector().start();
+ assert_unreached('expected start() to throw with SecurityError');
+ } catch (error) {
+ assert_equals(error.name, 'SecurityError');
+ }
+},
+`Inherited ${header} disallows ${workerType} workers.`);
+
+done();
diff --git a/testing/web-platform/tests/idle-detection/resources/idle-detection-helper.js b/testing/web-platform/tests/idle-detection/resources/idle-detection-helper.js
new file mode 100644
index 0000000000..f053e635e0
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/resources/idle-detection-helper.js
@@ -0,0 +1,14 @@
+'use strict';
+
+// These tests rely on the User Agent providing an implementation of
+// platform nfc backends.
+//
+// In Chromium-based browsers this implementation is provided by a polyfill
+// in order to reduce the amount of test-only code shipped to users. To enable
+// these tests the browser must be run with these options:
+//
+// --enable-blink-features=MojoJS,MojoJSTest
+
+async function loadChromiumResources() {
+ await import('/resources/chromium/mock-idle-detection.js');
+}
diff --git a/testing/web-platform/tests/idle-detection/resources/idlharness-worker.js b/testing/web-platform/tests/idle-detection/resources/idlharness-worker.js
new file mode 100644
index 0000000000..9733050284
--- /dev/null
+++ b/testing/web-platform/tests/idle-detection/resources/idlharness-worker.js
@@ -0,0 +1,22 @@
+'use strict';
+
+importScripts("/resources/testharness.js");
+importScripts("/resources/WebIDLParser.js", "/resources/idlharness.js");
+
+idl_test(
+ ['idle-detection'],
+ ['dom', 'html'],
+ async (idl_array, t) => {
+ self.idle = new IdleDetector();
+ let watcher = new EventWatcher(t, self.idle, ["change"]);
+ let initial_state = watcher.wait_for("change");
+ await self.idle.start();
+ await initial_state;
+
+ idl_array.add_objects({
+ IdleDetector: ['idle'],
+ });
+ }
+);
+
+done();