mirror of
https://github.com/servo/servo.git
synced 2025-06-25 17:44:33 +01:00
186 lines
8.3 KiB
JavaScript
186 lines
8.3 KiB
JavaScript
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`);
|
|
}
|