From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- testing/web-platform/tests/generic-sensor/META.yml | 5 + .../web-platform/tests/generic-sensor/README.md | 40 ++ .../SensorErrorEvent-constructor.https.html | 18 + .../generic-sensor-feature-policy-test.sub.js | 173 +++++++ .../generic-sensor-iframe-tests.sub.js | 186 +++++++ .../generic-sensor-permission.https.html | 32 ++ .../tests/generic-sensor/generic-sensor-tests.js | 553 +++++++++++++++++++++ .../generic-sensor/idlharness.https.window.js | 23 + .../resources/generic-sensor-helpers.js | 142 ++++++ .../resources/iframe_sensor_handler.html | 63 +++ 10 files changed, 1235 insertions(+) create mode 100644 testing/web-platform/tests/generic-sensor/META.yml create mode 100644 testing/web-platform/tests/generic-sensor/README.md create mode 100644 testing/web-platform/tests/generic-sensor/SensorErrorEvent-constructor.https.html create mode 100644 testing/web-platform/tests/generic-sensor/generic-sensor-feature-policy-test.sub.js create mode 100644 testing/web-platform/tests/generic-sensor/generic-sensor-iframe-tests.sub.js create mode 100644 testing/web-platform/tests/generic-sensor/generic-sensor-permission.https.html create mode 100644 testing/web-platform/tests/generic-sensor/generic-sensor-tests.js create mode 100644 testing/web-platform/tests/generic-sensor/idlharness.https.window.js create mode 100644 testing/web-platform/tests/generic-sensor/resources/generic-sensor-helpers.js create mode 100644 testing/web-platform/tests/generic-sensor/resources/iframe_sensor_handler.html (limited to 'testing/web-platform/tests/generic-sensor') diff --git a/testing/web-platform/tests/generic-sensor/META.yml b/testing/web-platform/tests/generic-sensor/META.yml new file mode 100644 index 0000000000..916bc8074f --- /dev/null +++ b/testing/web-platform/tests/generic-sensor/META.yml @@ -0,0 +1,5 @@ +spec: https://w3c.github.io/sensors/ +suggested_reviewers: + - riju + - rakuco + - Honry diff --git a/testing/web-platform/tests/generic-sensor/README.md b/testing/web-platform/tests/generic-sensor/README.md new file mode 100644 index 0000000000..250300b51e --- /dev/null +++ b/testing/web-platform/tests/generic-sensor/README.md @@ -0,0 +1,40 @@ +The `resources/generic-sensor-helpers.js` tests require an implementation of +the `GenericSensorTest` interface, which should emulate platform +sensor backends. The `GenericSensorTest` interface is defined as: + +``` + class MockSensor { + // Sets fake data that is used to deliver sensor reading updates. + async setSensorReading(FrozenArray readingData); + setStartShouldFail(boolean shouldFail); // Sets flag that forces sensor to fail. + getSamplingFrequency(); // Return the sampling frequency. + }; + + class MockSensorProvider { + // Sets flag that forces mock SensorProvider to fail when getSensor() is + // invoked. + setGetSensorShouldFail(DOMString sensorType, boolean shouldFail); + // Sets flag that forces mock SensorProvider to permissions denied when + // getSensor() is invoked. + setPermissionsDenied(DOMString sensorType, boolean permissionsDenied); + getCreatedSensor(DOMString sensorType); // Return `MockSensor` interface. + setMaximumSupportedFrequency(double frequency); // Sets the maximum frequency. + setMinimumSupportedFrequency(double frequency); // Sets the minimum frequency. + } + + class GenericSensorTest { + initialize(); // Sets up the testing environment. + async reset(); // Frees the resources. + getSensorProvider(); // Returns `MockSensorProvider` interface. + }; +``` + +The Chromium implementation of the `GenericSensorTest` interface is located in +[generic_sensor_mocks.js](../resources/chromium/generic_sensor_mocks.js). + +Other browser vendors should provide their own implementations of +the `GenericSensorTest` interface. + +[Known issue](https://github.com/web-platform-tests/wpt/issues/9686): a +WebDriver extension is a better approach for the Generic Sensor tests +automation. diff --git a/testing/web-platform/tests/generic-sensor/SensorErrorEvent-constructor.https.html b/testing/web-platform/tests/generic-sensor/SensorErrorEvent-constructor.https.html new file mode 100644 index 0000000000..2d68dec56d --- /dev/null +++ b/testing/web-platform/tests/generic-sensor/SensorErrorEvent-constructor.https.html @@ -0,0 +1,18 @@ + +SensorErrorEvent constructor + + + + diff --git a/testing/web-platform/tests/generic-sensor/generic-sensor-feature-policy-test.sub.js b/testing/web-platform/tests/generic-sensor/generic-sensor-feature-policy-test.sub.js new file mode 100644 index 0000000000..9bc46ae936 --- /dev/null +++ b/testing/web-platform/tests/generic-sensor/generic-sensor-feature-policy-test.sub.js @@ -0,0 +1,173 @@ +const feature_policies = { + "AmbientLightSensor" : ["ambient-light-sensor"], + "Accelerometer" : ["accelerometer"], + "LinearAccelerationSensor" : ["accelerometer"], + "GravitySensor" : ["accelerometer"], + "Gyroscope" : ["gyroscope"], + "GeolocationSensor" : ["geolocation"], + "Magnetometer" : ["magnetometer"], + "UncalibratedMagnetometer" : ["magnetometer"], + "AbsoluteOrientationSensor" : ["accelerometer", "gyroscope", "magnetometer"], + "RelativeOrientationSensor" : ["accelerometer", "gyroscope"] +}; + +const same_origin_src = + "/feature-policy/resources/feature-policy-generic-sensor.html#"; +const cross_origin_src = + "https://{{domains[www]}}:{{ports[https][0]}}" + same_origin_src; +const base_src = "/feature-policy/resources/redirect-on-load.html#"; + +function get_feature_policies_for_sensor(sensorType) { + return feature_policies[sensorType]; +} + +function run_fp_tests_disabled(sensorName) { + const sensorType = self[sensorName]; + const featureNameList = feature_policies[sensorName]; + const header = "Feature-Policy header " + featureNameList.join(" 'none';") + " 'none'"; + const desc = "'new " + sensorName + "()'"; + + test(() => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + assert_throws_dom("SecurityError", () => {new sensorType()}); + }, `${sensorName}: ${header} disallows the top-level document.`); + + async_test(t => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + test_feature_availability( + desc, + t, + same_origin_src + sensorName, + expect_feature_unavailable_default + ); + }, `${sensorName}: ${header} disallows same-origin iframes.`); + + async_test(t => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + test_feature_availability( + desc, + t, + cross_origin_src + sensorName, + expect_feature_unavailable_default + ); + }, `${sensorName}: ${header} disallows cross-origin iframes.`); +} + +function run_fp_tests_enabled(sensorName) { + const featureNameList = feature_policies[sensorName]; + const header = "Feature-Policy header " + featureNameList.join(" *;") + " *"; + const desc = "'new " + sensorName + "()'"; + + test(() => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + }, `${sensorName}: ${header} allows the top-level document.`); + + async_test(t => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + test_feature_availability( + desc, + t, + same_origin_src + sensorName, + expect_feature_available_default + ); + }, `${sensorName}: ${header} allows same-origin iframes.`); + + // Set allow="feature;feature;..." on iframe element to delegate features + // under test to cross origin subframe. + async_test(t => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + test_feature_availability( + desc, + t, + cross_origin_src + sensorName, + expect_feature_available_default, + feature_policies[sensorName].join(";") + ); + }, `${sensorName}: ${header} allows cross-origin iframes.`); +} + +function run_fp_tests_enabled_by_attribute(sensorName) { + const featureNameList = feature_policies[sensorName]; + const header = "Feature-Policy allow='" + featureNameList.join(" ") + "' attribute"; + const desc = "'new " + sensorName + "()'"; + + async_test(t => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + test_feature_availability( + desc, + t, + same_origin_src + sensorName, + expect_feature_available_default, + featureNameList.join(";") + ); + }, `${sensorName}: ${header} allows same-origin iframe`); + + async_test(t => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + test_feature_availability( + desc, + t, + cross_origin_src + sensorName, + expect_feature_available_default, + featureNameList.join(";") + ); + }, `${sensorName}: ${header} allows cross-origin iframe`); +} + +function run_fp_tests_enabled_by_attribute_redirect_on_load(sensorName) { + const featureNameList = feature_policies[sensorName]; + const header = "Feature-Policy allow='" + featureNameList.join(" ") + "' attribute"; + const desc = "'new " + sensorName + "()'"; + + async_test(t => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + test_feature_availability( + desc, + t, + base_src + same_origin_src + sensorName, + expect_feature_available_default, + featureNameList.join(";") + ); + }, `${sensorName}: ${header} allows same-origin relocation`); + + async_test(t => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + test_feature_availability( + desc, + t, + base_src + cross_origin_src + sensorName, + expect_feature_unavailable_default, + featureNameList.join(";") + ); + }, `${sensorName}: ${header} disallows cross-origin relocation`); +} + +function run_fp_tests_enabled_on_self_origin(sensorName) { + const featureNameList = feature_policies[sensorName]; + const header = "Feature-Policy header " + featureNameList.join(" 'self';") + " 'self'"; + const desc = "'new " + sensorName + "()'"; + + test(() => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + }, `${sensorName}: ${header} allows the top-level document.`); + + async_test(t => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + test_feature_availability( + desc, + t, + same_origin_src + sensorName, + expect_feature_available_default + ); + }, `${sensorName}: ${header} allows same-origin iframes.`); + + async_test(t => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + test_feature_availability( + desc, + t, + cross_origin_src + sensorName, + expect_feature_unavailable_default + ); + }, `${sensorName}: ${header} disallows cross-origin iframes.`); +} diff --git a/testing/web-platform/tests/generic-sensor/generic-sensor-iframe-tests.sub.js b/testing/web-platform/tests/generic-sensor/generic-sensor-iframe-tests.sub.js new file mode 100644 index 0000000000..1d1a012380 --- /dev/null +++ b/testing/web-platform/tests/generic-sensor/generic-sensor-iframe-tests.sub.js @@ -0,0 +1,186 @@ +function send_message_to_iframe(iframe, message, reply) { + if (reply === undefined) { + reply = 'success'; + } + + return new Promise((resolve, reject) => { + window.addEventListener('message', (e) => { + if (e.data.command !== message.command) { + reject(`Expected reply with command '${message.command}', got '${e.data.command}' instead`); + return; + } + if (e.data.result === reply) { + resolve(); + } else { + reject(`Got unexpected reply '${e.data.result}' to command '${message.command}', expected '${reply}'`); + } + }, { once: true }); + iframe.contentWindow.postMessage(message, '*'); + }); +} + +function run_generic_sensor_iframe_tests(sensorName) { + const sensorType = self[sensorName]; + const featurePolicies = get_feature_policies_for_sensor(sensorName); + + sensor_test(async t => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + const iframe = document.createElement('iframe'); + iframe.allow = featurePolicies.join(';') + ';'; + iframe.src = 'https://{{domains[www1]}}:{{ports[https][0]}}/generic-sensor/resources/iframe_sensor_handler.html'; + + // Create sensor inside cross-origin nested browsing context. + const iframeLoadWatcher = new EventWatcher(t, iframe, 'load'); + document.body.appendChild(iframe); + t.add_cleanup(async () => { + await send_message_to_iframe(iframe, { command: 'reset_sensor_backend' }); + iframe.parentNode.removeChild(iframe); + }); + await iframeLoadWatcher.wait_for('load'); + await send_message_to_iframe(iframe, {command: 'create_sensor', + type: sensorName}); + + // Focus on the main frame and test that sensor receives readings. + window.focus(); + const sensor = new sensorType(); + const sensorWatcher = new EventWatcher(t, sensor, ['reading', 'error']); + sensor.start(); + + await sensorWatcher.wait_for('reading'); + const cachedTimeStamp = sensor.timestamp; + + // Focus on the cross-origin frame and verify that sensor reading updates in + // the top level browsing context are suspended. + iframe.contentWindow.focus(); + await send_message_to_iframe(iframe, {command: 'start_sensor'}); + + // Focus on the main frame, verify that sensor reading updates are resumed. + window.focus(); + await sensorWatcher.wait_for('reading'); + assert_greater_than(sensor.timestamp, cachedTimeStamp); + sensor.stop(); + + // Verify that sensor in cross-origin frame is suspended. + await send_message_to_iframe(iframe, {command: 'is_sensor_suspended'}, true); + }, `${sensorName}: sensor is suspended and resumed when focus traverses from\ + to cross-origin frame`); + + sensor_test(async t => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + const iframe = document.createElement('iframe'); + iframe.allow = featurePolicies.join(';') + ';'; + iframe.src = 'https://{{host}}:{{ports[https][0]}}/generic-sensor/resources/iframe_sensor_handler.html'; + + // Create sensor inside same-origin nested browsing context. + const iframeLoadWatcher = new EventWatcher(t, iframe, 'load'); + document.body.appendChild(iframe); + t.add_cleanup(async () => { + await send_message_to_iframe(iframe, { command: 'reset_sensor_backend' }); + iframe.parentNode.removeChild(iframe); + }); + await iframeLoadWatcher.wait_for('load'); + await send_message_to_iframe(iframe, {command: 'create_sensor', + type: sensorName}); + + // Focus on main frame and test that sensor receives readings. + window.focus(); + const sensor = new sensorType({ + // generic_sensor_mocks.js uses a default frequency of 5Hz for sensors. + // We deliberately use a higher frequency here to make it easier to spot + // spurious, unexpected 'reading' events caused by the main frame's + // sensor not stopping early enough. + // TODO(rakuco): Create a constant with the 5Hz default frequency instead + // of using magic numbers. + frequency: 15 + }); + const sensorWatcher = new EventWatcher(t, sensor, ['reading', 'error']); + sensor.start(); + await sensorWatcher.wait_for('reading'); + let cachedTimeStamp = sensor.timestamp; + + // Stop sensor in main frame, so that sensorWatcher would not receive + // readings while sensor in iframe is started. Sensors that are active and + // belong to the same-origin context are not suspended automatically when + // focus changes to another same-origin iframe, so if we do not explicitly + // stop them we may receive extra 'reading' events that cause the test to + // fail (see e.g. https://crbug.com/857520). + sensor.stop(); + + iframe.contentWindow.focus(); + await send_message_to_iframe(iframe, {command: 'start_sensor'}); + + // Start sensor on main frame, verify that readings are updated. + window.focus(); + sensor.start(); + await sensorWatcher.wait_for('reading'); + assert_greater_than(sensor.timestamp, cachedTimeStamp); + cachedTimeStamp = sensor.timestamp; + sensor.stop(); + + // Verify that sensor in nested browsing context is not suspended. + await send_message_to_iframe(iframe, {command: 'is_sensor_suspended'}, false); + + // Verify that sensor in top level browsing context is receiving readings. + iframe.contentWindow.focus(); + sensor.start(); + await sensorWatcher.wait_for('reading'); + assert_greater_than(sensor.timestamp, cachedTimeStamp); + sensor.stop(); + }, `${sensorName}: sensor is not suspended when focus traverses from\ + to same-origin frame`); + + sensor_test(async t => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + const iframe = document.createElement('iframe'); + iframe.allow = featurePolicies.join(';') + ';'; + iframe.src = 'https://{{host}}:{{ports[https][0]}}/generic-sensor/resources/iframe_sensor_handler.html'; + + // Create sensor in the iframe (we do not care whether this is a + // cross-origin nested context in this test). + const iframeLoadWatcher = new EventWatcher(t, iframe, 'load'); + document.body.appendChild(iframe); + await iframeLoadWatcher.wait_for('load'); + await send_message_to_iframe(iframe, {command: 'create_sensor', + type: sensorName}); + iframe.contentWindow.focus(); + await send_message_to_iframe(iframe, {command: 'start_sensor'}); + + // Remove iframe from main document and change focus. When focus changes, + // we need to determine whether a sensor must have its execution suspended + // or resumed (section 4.2.3, "Focused Area" of the Generic Sensor API + // spec). In Blink, this involves querying a frame, which might no longer + // exist at the time of the check. + // Note that we cannot send the "reset_sensor_backend" command because the + // iframe is discarded with the removeChild call. + iframe.parentNode.removeChild(iframe); + window.focus(); + }, `${sensorName}: losing a document's frame with an active sensor does not crash`); + + sensor_test(async t => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + const iframe = document.createElement('iframe'); + iframe.allow = featurePolicies.join(';') + ';'; + iframe.src = 'https://{{host}}:{{ports[https][0]}}/generic-sensor/resources/iframe_sensor_handler.html'; + + // Create sensor in the iframe (we do not care whether this is a + // cross-origin nested context in this test). + const iframeLoadWatcher = new EventWatcher(t, iframe, 'load'); + document.body.appendChild(iframe); + await iframeLoadWatcher.wait_for('load'); + + // The purpose of this message is to initialize the mock backend in the + // iframe. We are not going to use the sensor created there. + await send_message_to_iframe(iframe, {command: 'create_sensor', + type: sensorName}); + + const iframeSensor = new iframe.contentWindow[sensorName](); + assert_not_equals(iframeSensor, null); + + // Remove iframe from main document. |iframeSensor| no longer has a + // non-null browsing context. Calling start() should probably throw an + // error when called from a non-fully active document, but that depends on + // https://github.com/w3c/sensors/issues/415 + iframe.parentNode.removeChild(iframe); + iframeSensor.start(); + }, `${sensorName}: calling start() in a non-fully active document does not crash`); +} diff --git a/testing/web-platform/tests/generic-sensor/generic-sensor-permission.https.html b/testing/web-platform/tests/generic-sensor/generic-sensor-permission.https.html new file mode 100644 index 0000000000..5edc80026d --- /dev/null +++ b/testing/web-platform/tests/generic-sensor/generic-sensor-permission.https.html @@ -0,0 +1,32 @@ + + +sensor: permission + + + + + + \ No newline at end of file diff --git a/testing/web-platform/tests/generic-sensor/generic-sensor-tests.js b/testing/web-platform/tests/generic-sensor/generic-sensor-tests.js new file mode 100644 index 0000000000..3c8f478c54 --- /dev/null +++ b/testing/web-platform/tests/generic-sensor/generic-sensor-tests.js @@ -0,0 +1,553 @@ +'use strict'; + +// Run a set of tests for a given |sensorName|. +// |readingData| is an object with 3 keys, all of which are arrays of arrays: +// 1. "readings". Each value corresponds to one raw reading that will be +// processed by a sensor. +// 2. "expectedReadings". Each value corresponds to the processed value a +// sensor will make available to users (i.e. a capped or rounded value). +// Its length must match |readings|'. +// 3. "expectedRemappedReadings" (optional). Similar to |expectedReadings|, but +// used only by spatial sensors, whose reference frame can change the values +// returned by a sensor. +// Its length should match |readings|'. +// |verificationFunction| is called to verify that a given reading matches a +// value in |expectedReadings|. +// |featurePolicies| represents |sensorName|'s associated sensor feature name. + +function runGenericSensorTests(sensorName, + readingData, + verificationFunction, + featurePolicies) { + const sensorType = self[sensorName]; + + function validateReadingFormat(data) { + return Array.isArray(data) && data.every(element => Array.isArray(element)); + } + + const { readings, expectedReadings, expectedRemappedReadings } = readingData; + if (!validateReadingFormat(readings)) { + throw new TypeError('readingData.readings must be an array of arrays.'); + } + if (!validateReadingFormat(expectedReadings)) { + throw new TypeError('readingData.expectedReadings must be an array of ' + + 'arrays.'); + } + if (readings.length < expectedReadings.length) { + throw new TypeError('readingData.readings\' length must be bigger than ' + + 'or equal to readingData.expectedReadings\' length.'); + } + if (expectedRemappedReadings && + !validateReadingFormat(expectedRemappedReadings)) { + throw new TypeError('readingData.expectedRemappedReadings must be an ' + + 'array of arrays.'); + } + if (expectedRemappedReadings && + expectedReadings.length != expectedRemappedReadings.length) { + throw new TypeError('readingData.expectedReadings and ' + + 'readingData.expectedRemappedReadings must have the same ' + + 'length.'); + } + + sensor_test(async (t, sensorProvider) => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + sensorProvider.setGetSensorShouldFail(sensorName, true); + const sensor = new sensorType; + const sensorWatcher = new EventWatcher(t, sensor, ["reading", "error"]); + sensor.start(); + + const event = await sensorWatcher.wait_for("error"); + + assert_false(sensor.activated); + assert_equals(event.error.name, 'NotReadableError'); + }, `${sensorName}: Test that onerror is sent when sensor is not supported.`); + + sensor_test(async (t, sensorProvider) => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + sensorProvider.setPermissionsDenied(sensorName, true); + const sensor = new sensorType; + const sensorWatcher = new EventWatcher(t, sensor, ["reading", "error"]); + sensor.start(); + + const event = await sensorWatcher.wait_for("error"); + + assert_false(sensor.activated); + assert_equals(event.error.name, 'NotAllowedError'); + }, `${sensorName}: Test that onerror is sent when permissions are not\ + granted.`); + + sensor_test(async (t, sensorProvider) => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + const sensor = new sensorType({frequency: 560}); + const sensorWatcher = new EventWatcher(t, sensor, ["reading", "error"]); + sensor.start(); + + const mockSensor = await sensorProvider.getCreatedSensor(sensorName); + mockSensor.setStartShouldFail(true); + + const event = await sensorWatcher.wait_for("error"); + + assert_false(sensor.activated); + assert_equals(event.error.name, 'NotReadableError'); + }, `${sensorName}: Test that onerror is send when start() call has failed.`); + + sensor_test(async (t, sensorProvider) => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + const sensor = new sensorType({frequency: 560}); + const sensorWatcher = new EventWatcher(t, sensor, ["activate", "error"]); + sensor.start(); + + const mockSensor = await sensorProvider.getCreatedSensor(sensorName); + + await sensorWatcher.wait_for("activate"); + + assert_less_than_equal(mockSensor.getSamplingFrequency(), 60); + sensor.stop(); + assert_false(sensor.activated); + }, `${sensorName}: Test that frequency is capped to allowed maximum.`); + + sensor_test(async (t, sensorProvider) => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + const maxSupportedFrequency = 5; + sensorProvider.setMaximumSupportedFrequency(maxSupportedFrequency); + const sensor = new sensorType({frequency: 50}); + const sensorWatcher = new EventWatcher(t, sensor, ["activate", "error"]); + sensor.start(); + + const mockSensor = await sensorProvider.getCreatedSensor(sensorName); + + await sensorWatcher.wait_for("activate"); + + assert_equals(mockSensor.getSamplingFrequency(), maxSupportedFrequency); + sensor.stop(); + assert_false(sensor.activated); + }, `${sensorName}: Test that frequency is capped to the maximum supported\ + frequency.`); + + sensor_test(async (t, sensorProvider) => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + const minSupportedFrequency = 2; + sensorProvider.setMinimumSupportedFrequency(minSupportedFrequency); + const sensor = new sensorType({frequency: -1}); + const sensorWatcher = new EventWatcher(t, sensor, ["activate", "error"]); + sensor.start(); + + const mockSensor = await sensorProvider.getCreatedSensor(sensorName); + + await sensorWatcher.wait_for("activate"); + + assert_equals(mockSensor.getSamplingFrequency(), minSupportedFrequency); + sensor.stop(); + assert_false(sensor.activated); + }, `${sensorName}: Test that frequency is limited to the minimum supported\ + frequency.`); + + promise_test(async t => { + assert_implements(sensorName in self, `${sensorName} is not supported.`); + const iframe = document.createElement('iframe'); + iframe.allow = featurePolicies.join(' \'none\'; ') + ' \'none\';'; + iframe.srcdoc = ' + -- cgit v1.2.3