diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/orientation-event/resources/orientation-event-helpers.js | |
parent | Initial commit. (diff) | |
download | firefox-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/orientation-event/resources/orientation-event-helpers.js')
-rw-r--r-- | testing/web-platform/tests/orientation-event/resources/orientation-event-helpers.js | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/testing/web-platform/tests/orientation-event/resources/orientation-event-helpers.js b/testing/web-platform/tests/orientation-event/resources/orientation-event-helpers.js new file mode 100644 index 0000000000..01e91c62ae --- /dev/null +++ b/testing/web-platform/tests/orientation-event/resources/orientation-event-helpers.js @@ -0,0 +1,274 @@ +'use strict'; + +// @class SensorTestHelper +// +// SensorTestHelper is a helper utilities for orientation event tests. +// +// Usage example with device orientation: +// const helper = new SensorTestHelper(t, 'deviceorientation'); +// await helper.grantSensorsPermissions(); +// await helper.initializeSensors(); +// const generatedData = generateOrientationData(1, 2, 3, false); +// await helper.setData(generatedData); +// await waitForEvent(getExpectedOrientationEvent(generatedData)); +class SensorTestHelper { + #eventName; + #sensorsEnabledByDefault; + #enabledSensors; + #disabledSensors; + #testObject; + + // @param {object} t - A testharness.js subtest instance. + // @param {string} eventName - A name of event. Accepted values are + // devicemotion, deviceorientation or + // deviceorientationabsolute. + constructor(t, eventName) { + this.#eventName = eventName; + this.#testObject = t; + this.#testObject.add_cleanup(() => this.reset()); + + switch (this.#eventName) { + case 'devicemotion': + this.#sensorsEnabledByDefault = + new Set(['accelerometer', 'gyroscope', 'linear-acceleration']); + break; + case 'deviceorientation': + this.#sensorsEnabledByDefault = new Set(['relative-orientation']); + break; + case 'deviceorientationabsolute': + this.#sensorsEnabledByDefault = new Set(['absolute-orientation']); + break; + default: + throw new Error(`Invalid event name ${this.#eventName}`); + } + } + + // Creates virtual sensors that will be used in tests. + // + // This function must be called before event listeners are added or calls + // to setData() or waitForEvent() are made. + // + // The |options| parameter is an object that accepts the following entries: + // - enabledSensors: A list of virtual sensor names that will be created + // instead of the default ones for a given event type. + // - disabledSensors: A list of virtual sensor names that will be created + // in a disabled state, so that creating a sensor of + // a given type is guaranteed to fail. + // An Error is thrown if the same name is passed to both options. + // + // A default list of virtual sensors based on the |eventName| parameter passed + // to the constructor is used if |options| is not specified. + // + // Usage examples + // Use default sensors for the given event type: + // await helper.initializeSensors() + // Enable specific sensors: + // await helper.initializeSensors({ + // enabledSensors: ['accelerometer', 'gyroscope'] + // }) + // Disable some sensors, make some report as not available: + // await helper.initializeSensors({ + // disabledSensors: ['gyroscope'] + // }) + // Enable some sensors, make some report as not available: + // await helper.initializeSensors({ + // enabledSensors: ['accelerometer'], + // disabledSensors: ['gyroscope'] + // }) + async initializeSensors(options = {}) { + this.#disabledSensors = new Set(options.disabledSensors || []); + // Check that a sensor name is not in both |options.enabledSensors| and + // |options.disabledSensors|. + for (const sensor of (options.enabledSensors || [])) { + if (this.#disabledSensors.has(sensor)) { + throw new Error(`${sensor} can be defined only as enabledSensors or disabledSensors`); + } + } + + this.#enabledSensors = new Set(options.enabledSensors || this.#sensorsEnabledByDefault); + // Remove sensors from enabledSensors that are in disabledSensors + for (const sensor of this.#disabledSensors) { + this.#enabledSensors.delete(sensor); + } + + const createVirtualSensorPromises = []; + for (const sensor of this.#enabledSensors) { + createVirtualSensorPromises.push( + test_driver.create_virtual_sensor(sensor)); + } + for (const sensor of this.#disabledSensors) { + createVirtualSensorPromises.push( + test_driver.create_virtual_sensor(sensor, {connected: false})); + } + await Promise.all(createVirtualSensorPromises); + } + + // Updates virtual sensor with given data. + // @param {object} data - Generated data by generateMotionData or + // generateOrientationData which is passed to + // test_driver.update_virtual_sensor(). + async setData(data) { + // WebDriver expects numbers for all values in the readings it receives. We + // convert null to zero here, but any other numeric value would work, as it + // is the presence of one or more sensors in initializeSensors()' + // options.disabledSensors that cause null to be reported in one or more + // event attributes. + const nullToZero = x => (x === null ? 0 : x); + if (this.#eventName === 'devicemotion') { + const degToRad = Math.PI / 180; + await Promise.all([ + test_driver.update_virtual_sensor('accelerometer', { + 'x': nullToZero(data.accelerationIncludingGravityX), + 'y': nullToZero(data.accelerationIncludingGravityY), + 'z': nullToZero(data.accelerationIncludingGravityZ), + }), + test_driver.update_virtual_sensor('linear-acceleration', { + 'x': nullToZero(data.accelerationX), + 'y': nullToZero(data.accelerationY), + 'z': nullToZero(data.accelerationZ), + }), + test_driver.update_virtual_sensor('gyroscope', { + 'x': nullToZero(data.rotationRateAlpha) * degToRad, + 'y': nullToZero(data.rotationRateBeta) * degToRad, + 'z': nullToZero(data.rotationRateGamma) * degToRad, + }), + ]); + } else { + const sensorType = + data.absolute ? 'absolute-orientation' : 'relative-orientation'; + await test_driver.update_virtual_sensor(sensorType, { + alpha: nullToZero(data.alpha), + beta: nullToZero(data.beta), + gamma: nullToZero(data.gamma), + }); + } + } + + // Grants permissions to sensors. Depending on |eventName|, requests + // permission to use either the DeviceMotionEvent or the + // DeviceOrientationEvent API. + async grantSensorsPermissions() { + // Required by all event types. + await test_driver.set_permission({name: 'accelerometer'}, 'granted'); + await test_driver.set_permission({name: 'gyroscope'}, 'granted'); + if (this.#eventName == 'deviceorientationabsolute') { + await test_driver.set_permission({name: 'magnetometer'}, 'granted'); + } + + const interfaceName = this.#eventName == 'devicemotion' ? + DeviceMotionEvent : + DeviceOrientationEvent; + await test_driver.bless('enable user activation', async () => { + const permission = await interfaceName.requestPermission(); + assert_equals(permission, 'granted'); + }); + } + + // Resets SensorTestHelper to default state. Removes all created virtual + // sensors. + async reset() { + const createdVirtualSensors = + new Set([...this.#enabledSensors, ...this.#disabledSensors]); + + const sensorRemovalPromises = []; + for (const sensor of createdVirtualSensors) { + sensorRemovalPromises.push(test_driver.remove_virtual_sensor(sensor)); + } + await Promise.all(sensorRemovalPromises); + } +} + +function generateMotionData( + accelerationX, accelerationY, accelerationZ, accelerationIncludingGravityX, + accelerationIncludingGravityY, accelerationIncludingGravityZ, + rotationRateAlpha, rotationRateBeta, rotationRateGamma, interval = 16) { + const motionData = { + accelerationX: accelerationX, + accelerationY: accelerationY, + accelerationZ: accelerationZ, + accelerationIncludingGravityX: accelerationIncludingGravityX, + accelerationIncludingGravityY: accelerationIncludingGravityY, + accelerationIncludingGravityZ: accelerationIncludingGravityZ, + rotationRateAlpha: rotationRateAlpha, + rotationRateBeta: rotationRateBeta, + rotationRateGamma: rotationRateGamma, + interval: interval + }; + return motionData; +} + +function generateOrientationData(alpha, beta, gamma, absolute) { + const orientationData = + {alpha: alpha, beta: beta, gamma: gamma, absolute: absolute}; + return orientationData; +} + +function assertEventEquals(actualEvent, expectedEvent) { + // If two doubles differ by less than this amount, we can consider them + // to be effectively equal. + const EPSILON = 1e-8; + + for (let key1 of Object.keys(Object.getPrototypeOf(expectedEvent))) { + if (typeof expectedEvent[key1] === 'object' && + expectedEvent[key1] !== null) { + assertEventEquals(actualEvent[key1], expectedEvent[key1]); + } else if (typeof expectedEvent[key1] === 'number') { + assert_approx_equals( + actualEvent[key1], expectedEvent[key1], EPSILON, key1); + } else { + assert_equals(actualEvent[key1], expectedEvent[key1], key1); + } + } +} + +function getExpectedOrientationEvent(expectedOrientationData) { + return new DeviceOrientationEvent('deviceorientation', { + alpha: expectedOrientationData.alpha, + beta: expectedOrientationData.beta, + gamma: expectedOrientationData.gamma, + absolute: expectedOrientationData.absolute, + }); +} + +function getExpectedAbsoluteOrientationEvent(expectedOrientationData) { + return new DeviceOrientationEvent('deviceorientationabsolute', { + alpha: expectedOrientationData.alpha, + beta: expectedOrientationData.beta, + gamma: expectedOrientationData.gamma, + absolute: expectedOrientationData.absolute, + }); +} + +function getExpectedMotionEvent(expectedMotionData) { + return new DeviceMotionEvent('devicemotion', { + acceleration: { + x: expectedMotionData.accelerationX, + y: expectedMotionData.accelerationY, + z: expectedMotionData.accelerationZ, + }, + accelerationIncludingGravity: { + x: expectedMotionData.accelerationIncludingGravityX, + y: expectedMotionData.accelerationIncludingGravityY, + z: expectedMotionData.accelerationIncludingGravityZ, + }, + rotationRate: { + alpha: expectedMotionData.rotationRateAlpha, + beta: expectedMotionData.rotationRateBeta, + gamma: expectedMotionData.rotationRateGamma, + }, + interval: expectedMotionData.interval, + }); +} + +function waitForEvent(expected_event) { + return new Promise((resolve, reject) => { + window.addEventListener(expected_event.type, (event) => { + try { + assertEventEquals(event, expected_event); + resolve(); + } catch (e) { + reject(e); + } + }, {once: true}); + }); +} |