mirror of
https://github.com/servo/servo.git
synced 2025-08-10 16:05:43 +01:00
Update web-platform-tests to revision 74bae78af4b95a2f0ca3a81df9c7fe3143f24bbc
This commit is contained in:
parent
fb95f9df9c
commit
02c1eed999
150 changed files with 2395 additions and 829 deletions
|
@ -3,6 +3,7 @@
|
|||
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/web-animations/testcommon.js"></script>
|
||||
<script src="common.js"></script>
|
||||
|
||||
<style>
|
||||
|
@ -47,7 +48,7 @@ async_test(t => {
|
|||
animation.play();
|
||||
|
||||
assert_equals(data, '0.4');
|
||||
waitTwoAnimationFrames(t.step_func_done(() => {
|
||||
waitForAsyncAnimationFrames(1).then(t.step_func_done(() => {
|
||||
assert_equals(getComputedStyle(target).opacity, '0.5');
|
||||
}));
|
||||
});
|
||||
|
|
|
@ -8,26 +8,25 @@ function registerPassthroughAnimator() {
|
|||
`);
|
||||
}
|
||||
|
||||
function registerConstantLocalTimeAnimator(localTime) {
|
||||
return runInAnimationWorklet(`
|
||||
registerAnimator('constant_time', class {
|
||||
animate(currentTime, effect) { effect.localTime = ${localTime}; }
|
||||
});
|
||||
`);
|
||||
}
|
||||
|
||||
|
||||
function runInAnimationWorklet(code) {
|
||||
return CSS.animationWorklet.addModule(
|
||||
URL.createObjectURL(new Blob([code], {type: 'text/javascript'}))
|
||||
);
|
||||
}
|
||||
|
||||
function waitForAnimationFrames(count, callback) {
|
||||
function rafCallback() {
|
||||
if (count <= 0) {
|
||||
callback();
|
||||
} else {
|
||||
count -= 1;
|
||||
window.requestAnimationFrame(rafCallback);
|
||||
}
|
||||
}
|
||||
rafCallback();
|
||||
};
|
||||
|
||||
// Wait for two main thread frames to guarantee that compositor has produced
|
||||
// at least one frame. Note that this is a Chrome-only concept.
|
||||
function waitTwoAnimationFrames(callback) {
|
||||
waitForAnimationFrames(2, callback);
|
||||
};
|
||||
function waitForAsyncAnimationFrames(count) {
|
||||
// In Chrome, waiting for N+1 main thread frames guarantees that compositor has produced
|
||||
// at least N frames.
|
||||
// TODO(majidvp): re-evaluate this choice once other browsers have implemented
|
||||
// AnimationWorklet.
|
||||
return waitForAnimationFrames(count + 1);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
background-color: #00ff00;
|
||||
}
|
||||
</style>
|
||||
<script src="/web-animations/testcommon.js"></script>
|
||||
<script src="../common.js"></script>
|
||||
|
||||
<script id="iframe_worklet" type="text/worklet">
|
||||
|
@ -32,7 +33,7 @@ runInAnimationWorklet(
|
|||
const effect = new KeyframeEffect(target, [{ opacity: 0 }], { duration: 1000 });
|
||||
const animation = new WorkletAnimation('iframe_animator', effect);
|
||||
animation.play();
|
||||
waitTwoAnimationFrames( _ => {
|
||||
waitForAnimationFrames(2).then(_ => {
|
||||
window.parent.postMessage(getComputedStyle(target).opacity, '*');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,15 +3,9 @@
|
|||
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/web-animations/testcommon.js"></script>
|
||||
<script src="common.js"></script>
|
||||
|
||||
<script id="worklet_code" type="text/worklet">
|
||||
registerAnimator("test_animator", class {
|
||||
animate(currentTime, effect) {
|
||||
effect.localTime = currentTime;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// Creates a DOM structure like:
|
||||
|
@ -63,15 +57,14 @@ function createAndPlayTestAnimation(elements, timeline_orientation) {
|
|||
timeRange: 1000,
|
||||
orientation: timeline_orientation
|
||||
});
|
||||
const animation = new WorkletAnimation('test_animator', effect, timeline);
|
||||
const animation = new WorkletAnimation('passthrough', effect, timeline);
|
||||
animation.play();
|
||||
}
|
||||
|
||||
setup(setupAndRegisterTests, {explicit_done: true});
|
||||
|
||||
function setupAndRegisterTests() {
|
||||
const worklet_code = document.getElementById('worklet_code').textContent;
|
||||
runInAnimationWorklet(worklet_code).then(() => {
|
||||
registerPassthroughAnimator().then(() => {
|
||||
// Note that block horizontal-tb is tested implicitly in the basic
|
||||
// ScrollTimeline tests (as it is the default).
|
||||
async_test(
|
||||
|
@ -104,7 +97,7 @@ function block_vertical_lr(t) {
|
|||
elements.scroller.scrollWidth - elements.scroller.clientWidth;
|
||||
elements.scroller.scrollLeft = 0.25 * maxScroll;
|
||||
|
||||
waitForAnimationFrames(3, t.step_func_done(() => {
|
||||
waitForAsyncAnimationFrames(2).then(t.step_func_done(() => {
|
||||
assert_equals(
|
||||
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)');
|
||||
}));
|
||||
|
@ -120,7 +113,7 @@ function block_vertical_rl(t) {
|
|||
elements.scroller.scrollWidth - elements.scroller.clientWidth;
|
||||
elements.scroller.scrollLeft = 0.75 * maxScroll;
|
||||
|
||||
waitForAnimationFrames(3, t.step_func_done(() => {
|
||||
waitForAsyncAnimationFrames(2).then(t.step_func_done(() => {
|
||||
assert_equals(
|
||||
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)');
|
||||
}));
|
||||
|
@ -136,7 +129,7 @@ function inline_horizontal_tb_rtl(t) {
|
|||
elements.scroller.scrollWidth - elements.scroller.clientWidth;
|
||||
elements.scroller.scrollLeft = 0.75 * maxScroll;
|
||||
|
||||
waitForAnimationFrames(3, t.step_func_done(() => {
|
||||
waitForAsyncAnimationFrames(2).then(t.step_func_done(() => {
|
||||
assert_equals(
|
||||
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)');
|
||||
}));
|
||||
|
@ -151,7 +144,7 @@ function inline_vertical_writing_mode_ltr(t) {
|
|||
elements.scroller.scrollHeight - elements.scroller.clientHeight;
|
||||
elements.scroller.scrollTop = 0.25 * maxScroll;
|
||||
|
||||
waitForAnimationFrames(3, t.step_func_done(() => {
|
||||
waitForAsyncAnimationFrames(2).then(t.step_func_done(() => {
|
||||
assert_equals(
|
||||
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)');
|
||||
}));
|
||||
|
@ -167,7 +160,7 @@ function inline_vertical_writing_mode_rtl(t) {
|
|||
elements.scroller.scrollHeight - elements.scroller.clientHeight;
|
||||
elements.scroller.scrollTop = 0.75 * maxScroll;
|
||||
|
||||
waitForAnimationFrames(3, t.step_func_done(() => {
|
||||
waitForAsyncAnimationFrames(2).then(t.step_func_done(() => {
|
||||
assert_equals(
|
||||
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)');
|
||||
}));
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/web-animations/testcommon.js"></script>
|
||||
<script src="common.js"></script>
|
||||
|
||||
<style>
|
||||
|
@ -15,33 +16,21 @@
|
|||
|
||||
<script>
|
||||
function CreateTest(target, effect, verify, test_name) {
|
||||
async_test(t => {
|
||||
runInAnimationWorklet(
|
||||
document.getElementById('simple_animate').textContent
|
||||
).then(_ => {
|
||||
const animation = new WorkletAnimation('test_animator', effect);
|
||||
promise_test(async function() {
|
||||
await registerConstantLocalTimeAnimator(2000);
|
||||
const animation = new WorkletAnimation('constant_time', effect);
|
||||
animation.play();
|
||||
|
||||
waitTwoAnimationFrames(() => {
|
||||
// waitTwoAnimationFrames guarantees a compositor frame that could update
|
||||
// the opacity value in the worklet. Meanwhile, getComputedStyle needs an
|
||||
// extra frame to fetch the updated value.
|
||||
window.requestAnimationFrame(t.step_func_done(() => {
|
||||
verify();
|
||||
animation.cancel();
|
||||
}));
|
||||
});
|
||||
});
|
||||
await waitForAsyncAnimationFrames(1);
|
||||
// waitTwoAnimationFrames guarantees a compositor frame that could update
|
||||
// the opacity value in the worklet. Meanwhile, getComputedStyle needs an
|
||||
// extra frame to fetch the updated value.
|
||||
await waitForNextFrame();
|
||||
verify();
|
||||
animation.cancel();
|
||||
}, test_name);
|
||||
}
|
||||
</script>
|
||||
<script id="simple_animate" type="text/worklet">
|
||||
registerAnimator("test_animator", class {
|
||||
animate(currentTime, effect) {
|
||||
effect.localTime = 2000;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="target1" class='target'></div>
|
||||
<div id="target2" class='target'></div>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/web-animations/testcommon.js"></script>
|
||||
<script src="common.js"></script>
|
||||
|
||||
<style>
|
||||
|
@ -17,8 +18,8 @@
|
|||
<script>
|
||||
'use strict';
|
||||
|
||||
test(function() {
|
||||
registerPassthroughAnimator();
|
||||
promise_test(async function() {
|
||||
await registerPassthroughAnimator();
|
||||
let playFunc = function() {
|
||||
let effect = new KeyframeEffect(
|
||||
document.getElementById('target'),
|
||||
|
|
|
@ -8,19 +8,22 @@
|
|||
'use strict';
|
||||
const test_desc = 'HeartRate device properties';
|
||||
|
||||
bluetooth_test(() => getHealthThermometerService()
|
||||
.then(({service}) => Promise.all([
|
||||
service.getCharacteristic('temperature_measurement'),
|
||||
service.getCharacteristic('measurement_interval')]))
|
||||
.then(([temperature_measurement, measurement_interval]) => {
|
||||
let tm_expected_properties =
|
||||
new TestCharacteristicProperties(['indicate']);
|
||||
assert_properties_equal(temperature_measurement.properties,
|
||||
tm_expected_properties);
|
||||
bluetooth_test(
|
||||
() => getHealthThermometerService()
|
||||
.then(({service}) => Promise.all([
|
||||
service.getCharacteristic('temperature_measurement'),
|
||||
service.getCharacteristic('measurement_interval')
|
||||
]))
|
||||
.then(([temperature_measurement, measurement_interval]) => {
|
||||
let tm_expected_properties =
|
||||
new TestCharacteristicProperties(['indicate']);
|
||||
assert_properties_equal(
|
||||
temperature_measurement.properties, tm_expected_properties);
|
||||
|
||||
let mi_expected_properties =
|
||||
new TestCharacteristicProperties(['read', 'write', 'indicate']);
|
||||
assert_properties_equal(measurement_interval.properties,
|
||||
mi_expected_properties);
|
||||
}), test_desc);
|
||||
let mi_expected_properties = new TestCharacteristicProperties(
|
||||
['read', 'write', 'indicate']);
|
||||
assert_properties_equal(
|
||||
measurement_interval.properties, mi_expected_properties);
|
||||
}),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -8,12 +8,14 @@
|
|||
'use strict';
|
||||
const test_desc = 'Same parent service returned from multiple characteristics.';
|
||||
|
||||
bluetooth_test(() => getHealthThermometerService()
|
||||
.then(({service}) => Promise.all([
|
||||
service.getCharacteristic('measurement_interval'),
|
||||
service.getCharacteristic('temperature_measurement')
|
||||
]))
|
||||
.then(characteristics =>
|
||||
assert_equals(characteristics[0].service, characteristics[1].service)),
|
||||
bluetooth_test(
|
||||
() => getHealthThermometerService()
|
||||
.then(({service}) => Promise.all([
|
||||
service.getCharacteristic('measurement_interval'),
|
||||
service.getCharacteristic('temperature_measurement')
|
||||
]))
|
||||
.then(
|
||||
characteristics => assert_equals(
|
||||
characteristics[0].service, characteristics[1].service)),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
<script>
|
||||
'use strict';
|
||||
const test_desc = '[SameObject] test for BluetoothRemoteGATTCharacteristic ' +
|
||||
'service.';
|
||||
'service.';
|
||||
|
||||
bluetooth_test(() => getMeasurementIntervalCharacteristic()
|
||||
.then(({characteristic}) =>
|
||||
assert_equals(characteristic.service, characteristic.service)),
|
||||
bluetooth_test(
|
||||
() => getMeasurementIntervalCharacteristic().then(
|
||||
({characteristic}) =>
|
||||
assert_equals(characteristic.service, characteristic.service)),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
const test_desc = 'Bluetooth IDL test';
|
||||
|
||||
test(() => {
|
||||
assert_throws(new TypeError(), () => new Bluetooth(),
|
||||
'the constructor should not be callable with "new"');
|
||||
assert_throws(new TypeError(), () => Bluetooth(),
|
||||
'the constructor should not be callable');
|
||||
assert_throws(
|
||||
new TypeError(), () => new Bluetooth(),
|
||||
'the constructor should not be callable with "new"');
|
||||
assert_throws(
|
||||
new TypeError(), () => Bluetooth(),
|
||||
'the constructor should not be callable');
|
||||
|
||||
// Bluetooth implements BluetoothDiscovery;
|
||||
assert_true('requestDevice' in navigator.bluetooth);
|
||||
|
|
|
@ -9,23 +9,28 @@
|
|||
const test_desc_idl = 'BluetoothDevice IDL test.';
|
||||
|
||||
test(() => {
|
||||
assert_throws(new TypeError(), () => new BluetoothDevice(),
|
||||
assert_throws(
|
||||
new TypeError(), () => new BluetoothDevice(),
|
||||
'the constructor should not be callable with "new"');
|
||||
assert_throws(new TypeError(), () => BluetoothDevice(),
|
||||
assert_throws(
|
||||
new TypeError(), () => BluetoothDevice(),
|
||||
'the constructor should not be callable');
|
||||
}, test_desc_idl);
|
||||
|
||||
const test_desc_attr = 'BluetoothDevice attributes.';
|
||||
let device;
|
||||
bluetooth_test(() => getConnectedHealthThermometerDevice()
|
||||
.then(({device}) => {
|
||||
assert_equals(device.constructor.name, 'BluetoothDevice');
|
||||
var old_device_id = device.id;
|
||||
assert_throws(new TypeError(), () => device.id = 'overwritten',
|
||||
'the device id should not be writable');
|
||||
assert_throws(new TypeError(), () => device.name = 'overwritten',
|
||||
'the device name should not be writable');
|
||||
assert_equals(device.id, old_device_id);
|
||||
assert_equals(device.name, 'Health Thermometer');
|
||||
}), test_desc_attr);
|
||||
bluetooth_test(
|
||||
() => getConnectedHealthThermometerDevice().then(({device}) => {
|
||||
assert_equals(device.constructor.name, 'BluetoothDevice');
|
||||
var old_device_id = device.id;
|
||||
assert_throws(
|
||||
new TypeError(), () => device.id = 'overwritten',
|
||||
'the device id should not be writable');
|
||||
assert_throws(
|
||||
new TypeError(), () => device.name = 'overwritten',
|
||||
'the device name should not be writable');
|
||||
assert_equals(device.id, old_device_id);
|
||||
assert_equals(device.name, 'Health Thermometer');
|
||||
}),
|
||||
test_desc_attr);
|
||||
</script>
|
||||
|
|
|
@ -19,22 +19,25 @@ test(() => {
|
|||
assert_equals(BluetoothUUID.getDescriptor(NaN), base_uuid);
|
||||
}, 'NaN returns basic uuid');
|
||||
|
||||
test(() => {
|
||||
let max_uuid = 'ffffffff-0000-1000-8000-00805f9b34fb';
|
||||
let nine_digits = 0xfffffffff;
|
||||
let thirteen_digits = 0xfffffffffffff;
|
||||
let fourteen_digits = 0xffffffffffffff;
|
||||
assert_equals(BluetoothUUID.getService(nine_digits), max_uuid);
|
||||
assert_equals(BluetoothUUID.getCharacteristic(nine_digits), max_uuid);
|
||||
assert_equals(BluetoothUUID.getDescriptor(nine_digits), max_uuid);
|
||||
assert_equals(BluetoothUUID.getService(thirteen_digits), max_uuid);
|
||||
assert_equals(BluetoothUUID.getCharacteristic(thirteen_digits), max_uuid);
|
||||
assert_equals(BluetoothUUID.getDescriptor(thirteen_digits), max_uuid);
|
||||
assert_equals(BluetoothUUID.getService(fourteen_digits), base_uuid);
|
||||
assert_equals(BluetoothUUID.getCharacteristic(fourteen_digits), base_uuid);
|
||||
assert_equals(BluetoothUUID.getDescriptor(fourteen_digits), base_uuid);
|
||||
}, 'Values between 0xfffffffff (8 digits) and 0xffffffffffffff (14 digits)' +
|
||||
'should return max UUID');
|
||||
test(
|
||||
() => {
|
||||
let max_uuid = 'ffffffff-0000-1000-8000-00805f9b34fb';
|
||||
let nine_digits = 0xfffffffff;
|
||||
let thirteen_digits = 0xfffffffffffff;
|
||||
let fourteen_digits = 0xffffffffffffff;
|
||||
assert_equals(BluetoothUUID.getService(nine_digits), max_uuid);
|
||||
assert_equals(BluetoothUUID.getCharacteristic(nine_digits), max_uuid);
|
||||
assert_equals(BluetoothUUID.getDescriptor(nine_digits), max_uuid);
|
||||
assert_equals(BluetoothUUID.getService(thirteen_digits), max_uuid);
|
||||
assert_equals(BluetoothUUID.getCharacteristic(thirteen_digits), max_uuid);
|
||||
assert_equals(BluetoothUUID.getDescriptor(thirteen_digits), max_uuid);
|
||||
assert_equals(BluetoothUUID.getService(fourteen_digits), base_uuid);
|
||||
assert_equals(
|
||||
BluetoothUUID.getCharacteristic(fourteen_digits), base_uuid);
|
||||
assert_equals(BluetoothUUID.getDescriptor(fourteen_digits), base_uuid);
|
||||
},
|
||||
'Values between 0xfffffffff (8 digits) and 0xffffffffffffff (14 digits)' +
|
||||
'should return max UUID');
|
||||
|
||||
test(() => {
|
||||
assert_equals(BluetoothUUID.getService(Infinity), base_uuid);
|
||||
|
@ -54,7 +57,8 @@ test(() => {
|
|||
let adeadbeef_alias = 0xADEADBEEF;
|
||||
let adeadbeef_uuid = 'deadbeef-0000-1000-8000-00805f9b34fb';
|
||||
assert_equals(BluetoothUUID.getService(adeadbeef_alias), adeadbeef_uuid);
|
||||
assert_equals(BluetoothUUID.getCharacteristic(adeadbeef_alias), adeadbeef_uuid);
|
||||
assert_equals(
|
||||
BluetoothUUID.getCharacteristic(adeadbeef_alias), adeadbeef_uuid);
|
||||
assert_equals(BluetoothUUID.getDescriptor(adeadbeef_alias), adeadbeef_uuid);
|
||||
}, 'Only first 32bits should be used.');
|
||||
|
||||
|
@ -68,31 +72,40 @@ test(() => {
|
|||
test(() => {
|
||||
let all_caps_uuid = '1A2B3C4D-5E6F-7A8B-9C0D-1E2F3A4B5C6D';
|
||||
assert_throws(TypeError(), () => BluetoothUUID.getService(all_caps_uuid));
|
||||
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(all_caps_uuid));
|
||||
assert_throws(
|
||||
TypeError(), () => BluetoothUUID.getCharacteristic(all_caps_uuid));
|
||||
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(all_caps_uuid));
|
||||
}, 'A UUID String with uppercase letters is an invalid UUID.');
|
||||
|
||||
test(() => {
|
||||
let string_alias = 'deadbeef';
|
||||
assert_throws(TypeError(), () => BluetoothUUID.getService(string_alias));
|
||||
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(string_alias));
|
||||
assert_throws(
|
||||
TypeError(), () => BluetoothUUID.getCharacteristic(string_alias));
|
||||
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(string_alias));
|
||||
}, 'A 32bit *String* alias is invalid.');
|
||||
|
||||
test(() => {
|
||||
let invalid_character_uuid = '0000000g-0000-1000-8000-00805f9b34fb';
|
||||
assert_throws(TypeError(), () => BluetoothUUID.getService(invalid_character_uuid));
|
||||
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(invalid_character_uuid));
|
||||
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(invalid_character_uuid));
|
||||
assert_throws(
|
||||
TypeError(), () => BluetoothUUID.getService(invalid_character_uuid));
|
||||
assert_throws(
|
||||
TypeError(),
|
||||
() => BluetoothUUID.getCharacteristic(invalid_character_uuid));
|
||||
assert_throws(
|
||||
TypeError(), () => BluetoothUUID.getDescriptor(invalid_character_uuid));
|
||||
}, 'A UUID with invalid characters is an invalid UUID.');
|
||||
|
||||
test(() => {
|
||||
assert_equals(BluetoothUUID.getService('alert_notification'),
|
||||
'00001811-0000-1000-8000-00805f9b34fb');
|
||||
assert_equals(BluetoothUUID.getCharacteristic('aerobic_heart_rate_lower_limit'),
|
||||
'00002a7e-0000-1000-8000-00805f9b34fb');
|
||||
assert_equals(BluetoothUUID.getDescriptor('gatt.characteristic_extended_properties'),
|
||||
'00002900-0000-1000-8000-00805f9b34fb');
|
||||
assert_equals(
|
||||
BluetoothUUID.getService('alert_notification'),
|
||||
'00001811-0000-1000-8000-00805f9b34fb');
|
||||
assert_equals(
|
||||
BluetoothUUID.getCharacteristic('aerobic_heart_rate_lower_limit'),
|
||||
'00002a7e-0000-1000-8000-00805f9b34fb');
|
||||
assert_equals(
|
||||
BluetoothUUID.getDescriptor('gatt.characteristic_extended_properties'),
|
||||
'00002900-0000-1000-8000-00805f9b34fb');
|
||||
}, 'A valid UUID from a name.');
|
||||
|
||||
test(() => {
|
||||
|
@ -136,7 +149,8 @@ test(() => {
|
|||
assert_throws(new TypeError, () => BluetoothUUID.canonicalUUID(undefined));
|
||||
assert_equals(BluetoothUUID.canonicalUUID(null), base_uuid);
|
||||
assert_equals(BluetoothUUID.canonicalUUID(false), base_uuid);
|
||||
assert_equals(BluetoothUUID.canonicalUUID(true), BluetoothUUID.canonicalUUID(1));
|
||||
assert_equals(
|
||||
BluetoothUUID.canonicalUUID(true), BluetoothUUID.canonicalUUID(1));
|
||||
assert_throws(new TypeError, () => BluetoothUUID.canonicalUUID(NaN));
|
||||
|
||||
// getService
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
const test_desc = '[SameObject] test for navigator.bluetooth';
|
||||
|
||||
test(() => {
|
||||
assert_true('bluetooth' in navigator,
|
||||
'navigator.bluetooth exists.');
|
||||
assert_true('bluetooth' in navigator, 'navigator.bluetooth exists.');
|
||||
}, 'navigator.bluetooth IDL test');
|
||||
|
||||
test(() => {
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
const test_desc = 'Device with empty name and no UUIDs nearby. Should be ' +
|
||||
'found if acceptAllDevices is true.';
|
||||
|
||||
bluetooth_test(() => setUpPreconnectedDevice({name: ''})
|
||||
.then(() => requestDeviceWithTrustedClick({acceptAllDevices: true}))
|
||||
.then(device => assert_equals(device.name, '')),
|
||||
bluetooth_test(
|
||||
() =>
|
||||
setUpPreconnectedDevice({name: ''})
|
||||
.then(() => requestDeviceWithTrustedClick({acceptAllDevices: true}))
|
||||
.then(device => assert_equals(device.name, '')),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -5,12 +5,15 @@
|
|||
<script src="/resources/testdriver-vendor.js"></script>
|
||||
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
|
||||
<script>
|
||||
const test_desc = 'A device with name and no UUIDs nearby. Should be found if ' +
|
||||
'acceptAllDevices is true.';
|
||||
const test_desc =
|
||||
'A device with name and no UUIDs nearby. Should be found if ' +
|
||||
'acceptAllDevices is true.';
|
||||
const name = 'LE Device';
|
||||
|
||||
bluetooth_test(() => setUpPreconnectedDevice({name: name})
|
||||
.then(() => requestDeviceWithTrustedClick({acceptAllDevices: true}))
|
||||
.then(device => assert_equals(device.name, name)),
|
||||
bluetooth_test(
|
||||
() =>
|
||||
setUpPreconnectedDevice({name: name})
|
||||
.then(() => requestDeviceWithTrustedClick({acceptAllDevices: true}))
|
||||
.then(device => assert_equals(device.name, name)),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -10,13 +10,14 @@ const test_desc = 'requestDevice called with acceptAllDevices: true and ' +
|
|||
'with no optionalServices. Should not get access to any services.';
|
||||
const expected = new DOMException(
|
||||
'Origin is not allowed to access any service. ' +
|
||||
'Tip: Add the service UUID to \'optionalServices\' in ' +
|
||||
'requestDevice() options. https://goo.gl/HxfxSQ',
|
||||
'Tip: Add the service UUID to \'optionalServices\' in ' +
|
||||
'requestDevice() options. https://goo.gl/HxfxSQ',
|
||||
'SecurityError');
|
||||
|
||||
bluetooth_test(() => getConnectedHealthThermometerDevice({acceptAllDevices: true})
|
||||
.then(({device}) => assert_promise_rejects_with_message(
|
||||
device.gatt.getPrimaryServices(),
|
||||
expected)),
|
||||
bluetooth_test(
|
||||
() => getConnectedHealthThermometerDevice({acceptAllDevices: true})
|
||||
.then(
|
||||
({device}) => assert_promise_rejects_with_message(
|
||||
device.gatt.getPrimaryServices(), expected)),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -7,20 +7,23 @@
|
|||
<script>
|
||||
'use strict';
|
||||
const test_desc = 'requestDevice called with acceptAllDevices: true and with ' +
|
||||
'optionalServices. Should get access to services.';
|
||||
'optionalServices. Should get access to services.';
|
||||
|
||||
bluetooth_test(() => getTwoHealthThermometerServicesDevice()
|
||||
.then(() => requestDeviceWithTrustedClick({
|
||||
acceptAllDevices: true,
|
||||
optionalServices: ['health_thermometer']
|
||||
}))
|
||||
.then(device => device.gatt.connect())
|
||||
.then(gattServer => gattServer.getPrimaryServices())
|
||||
.then(services => {
|
||||
assert_equals(services.length, 2);
|
||||
services.forEach(service => {
|
||||
assert_equals(service.uuid,
|
||||
BluetoothUUID.getService('health_thermometer'));
|
||||
});
|
||||
}), test_desc);
|
||||
bluetooth_test(
|
||||
() => getTwoHealthThermometerServicesDevice()
|
||||
.then(() => requestDeviceWithTrustedClick({
|
||||
acceptAllDevices: true,
|
||||
optionalServices: ['health_thermometer']
|
||||
}))
|
||||
.then(device => device.gatt.connect())
|
||||
.then(gattServer => gattServer.getPrimaryServices())
|
||||
.then(services => {
|
||||
assert_equals(services.length, 2);
|
||||
services.forEach(service => {
|
||||
assert_equals(
|
||||
service.uuid,
|
||||
BluetoothUUID.getService('health_thermometer'));
|
||||
});
|
||||
}),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -10,16 +10,16 @@ const test_desc = 'Reject with SecurityError if requesting a blocklisted ' +
|
|||
'service.';
|
||||
const expected = new DOMException(
|
||||
'requestDevice() called with a filter containing a blocklisted UUID. ' +
|
||||
'https://goo.gl/4NeimX',
|
||||
'https://goo.gl/4NeimX',
|
||||
'SecurityError');
|
||||
|
||||
bluetooth_test(() => setUpPreconnectedDevice({
|
||||
knownServiceUUIDs: ['human_interface_device']
|
||||
})
|
||||
.then(() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick({
|
||||
filters: [{services: ['human_interface_device']}]
|
||||
}),
|
||||
expected, 'Requesting blocklisted service rejects.')),
|
||||
bluetooth_test(
|
||||
() =>
|
||||
setUpPreconnectedDevice({knownServiceUUIDs: ['human_interface_device']})
|
||||
.then(
|
||||
() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick(
|
||||
{filters: [{services: ['human_interface_device']}]}),
|
||||
expected, 'Requesting blocklisted service rejects.')),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -8,26 +8,30 @@
|
|||
'use strict';
|
||||
const test_desc = 'Blocklisted UUID in optionalServices is removed and ' +
|
||||
'access not granted.';
|
||||
const expected = new DOMException('Origin is not allowed to access the ' +
|
||||
'service. Tip: Add the service UUID to \'optionalServices\' in ' +
|
||||
'requestDevice() options. https://goo.gl/HxfxSQ',
|
||||
const expected = new DOMException(
|
||||
'Origin is not allowed to access the ' +
|
||||
'service. Tip: Add the service UUID to \'optionalServices\' in ' +
|
||||
'requestDevice() options. https://goo.gl/HxfxSQ',
|
||||
'SecurityError');
|
||||
let device, fake_peripheral;
|
||||
|
||||
bluetooth_test(() => getDiscoveredHealthThermometerDevice({
|
||||
filters: [{services: ['health_thermometer']}],
|
||||
optionalServices: ['human_interface_device']
|
||||
})
|
||||
.then(_ => ({device, fake_peripheral} = _))
|
||||
.then(() =>
|
||||
fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS}))
|
||||
.then(() => device.gatt.connect())
|
||||
.then(() => Promise.all([
|
||||
assert_promise_rejects_with_message(
|
||||
device.gatt.getPrimaryService('human_interface_device'),
|
||||
expected, 'Blocklisted service not accessible.'),
|
||||
assert_promise_rejects_with_message(
|
||||
device.gatt.getPrimaryServices('human_interface_device'),
|
||||
expected, 'Blocklisted services not accessible.')])),
|
||||
bluetooth_test(
|
||||
() => getDiscoveredHealthThermometerDevice({
|
||||
filters: [{services: ['health_thermometer']}],
|
||||
optionalServices: ['human_interface_device']
|
||||
})
|
||||
.then(_ => ({device, fake_peripheral} = _))
|
||||
.then(
|
||||
() => fake_peripheral.setNextGATTConnectionResponse(
|
||||
{code: HCI_SUCCESS}))
|
||||
.then(() => device.gatt.connect())
|
||||
.then(() => Promise.all([
|
||||
assert_promise_rejects_with_message(
|
||||
device.gatt.getPrimaryService('human_interface_device'),
|
||||
expected, 'Blocklisted service not accessible.'),
|
||||
assert_promise_rejects_with_message(
|
||||
device.gatt.getPrimaryServices('human_interface_device'),
|
||||
expected, 'Blocklisted services not accessible.')
|
||||
])),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -10,10 +10,11 @@ const test_desc = 'A device name between 29 and 248 bytes is valid.';
|
|||
const DEVICE_NAME = 'a_device_name_that_is_longer_than_29_bytes_but_' +
|
||||
'shorter_than_248_bytes';
|
||||
|
||||
bluetooth_test(() => setUpPreconnectedDevice({name: DEVICE_NAME})
|
||||
.then(() => requestDeviceWithTrustedClick({
|
||||
filters: [{name: DEVICE_NAME}]
|
||||
}))
|
||||
.then(device => assert_equals(device.name, DEVICE_NAME)),
|
||||
bluetooth_test(
|
||||
() => setUpPreconnectedDevice({name: DEVICE_NAME})
|
||||
.then(
|
||||
() => requestDeviceWithTrustedClick(
|
||||
{filters: [{name: DEVICE_NAME}]}))
|
||||
.then(device => assert_equals(device.name, DEVICE_NAME)),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
const test_desc = 'A filter must restrict the devices in some way.';
|
||||
const expected = new TypeError();
|
||||
|
||||
bluetooth_test(() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick({filters: [{}]}),
|
||||
expected),
|
||||
bluetooth_test(
|
||||
() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick({filters: [{}]}), expected),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -7,12 +7,13 @@
|
|||
<script>
|
||||
'use strict';
|
||||
const test_desc = 'An empty |filters| member should result in a TypeError';
|
||||
const expected = new DOMException('Failed to execute \'requestDevice\' on ' +
|
||||
'\'Bluetooth\': \'filters\' member must be non-empty to find any devices.',
|
||||
const expected = new DOMException(
|
||||
'Failed to execute \'requestDevice\' on ' +
|
||||
'\'Bluetooth\': \'filters\' member must be non-empty to find any devices.',
|
||||
new TypeError());
|
||||
|
||||
bluetooth_test(() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick({filters: []}),
|
||||
expected),
|
||||
bluetooth_test(
|
||||
() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick({filters: []}), expected),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -9,36 +9,29 @@
|
|||
const test_desc = 'requestDevice with empty namePrefix. ' +
|
||||
'Should reject with TypeError.';
|
||||
const expected = new TypeError();
|
||||
const test_specs = [{
|
||||
filters: [{ namePrefix: ''}]
|
||||
}, {
|
||||
filters: [{ namePrefix: '', name: 'Name'}]
|
||||
}, {
|
||||
filters: [{ namePrefix: '', services: ['heart_rate']}]
|
||||
}, {
|
||||
filters: [{ namePrefix: '', name: 'Name', services: ['heart_rate']}]
|
||||
}, {
|
||||
filters: [{ namePrefix: ''}],
|
||||
optionalServices: ['heart_rate']
|
||||
}, {
|
||||
filters: [{ namePrefix: '', name: 'Name'}],
|
||||
optionalServices: ['heart_rate']
|
||||
}, {
|
||||
filters: [{ namePrefix: '', services: ['heart_rate']}],
|
||||
optionalServices: ['heart_rate']
|
||||
}, {
|
||||
filters: [{ namePrefix: '', name: 'Name', services: ['heart_rate']}],
|
||||
optionalServices: ['heart_rate']
|
||||
}];
|
||||
const test_specs = [
|
||||
{filters: [{namePrefix: ''}]}, {filters: [{namePrefix: '', name: 'Name'}]},
|
||||
{filters: [{namePrefix: '', services: ['heart_rate']}]},
|
||||
{filters: [{namePrefix: '', name: 'Name', services: ['heart_rate']}]},
|
||||
{filters: [{namePrefix: ''}], optionalServices: ['heart_rate']},
|
||||
{filters: [{namePrefix: '', name: 'Name'}], optionalServices: ['heart_rate']},
|
||||
{
|
||||
filters: [{namePrefix: '', services: ['heart_rate']}],
|
||||
optionalServices: ['heart_rate']
|
||||
},
|
||||
{
|
||||
filters: [{namePrefix: '', name: 'Name', services: ['heart_rate']}],
|
||||
optionalServices: ['heart_rate']
|
||||
}
|
||||
];
|
||||
|
||||
bluetooth_test(() => {
|
||||
let test_promises = Promise.resolve();
|
||||
test_specs.forEach(args => {
|
||||
test_promises = test_promises
|
||||
.then(() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick(args),
|
||||
expected));
|
||||
});
|
||||
return test_promises;
|
||||
}, test_desc);
|
||||
let test_promises = Promise.resolve();
|
||||
test_specs.forEach(args => {
|
||||
test_promises = test_promises.then(
|
||||
() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick(args), expected));
|
||||
});
|
||||
return test_promises;
|
||||
}, test_desc);
|
||||
</script>
|
||||
|
|
|
@ -10,14 +10,12 @@ const test_desc = 'Services member must contain at least one service.';
|
|||
const expected = new TypeError();
|
||||
|
||||
bluetooth_test(() => {
|
||||
let test_promises = Promise.resolve();
|
||||
generateRequestDeviceArgsWithServices([]).forEach(args => {
|
||||
test_promises = test_promises.then(() =>
|
||||
assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick(args),
|
||||
expected,
|
||||
'Services member must contain at least one service'))
|
||||
});
|
||||
return test_promises;
|
||||
}, test_desc);
|
||||
let test_promises = Promise.resolve();
|
||||
generateRequestDeviceArgsWithServices([]).forEach(
|
||||
args => {test_promises = test_promises.then(
|
||||
() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick(args), expected,
|
||||
'Services member must contain at least one service'))});
|
||||
return test_promises;
|
||||
}, test_desc);
|
||||
</script>
|
||||
|
|
|
@ -6,28 +6,24 @@
|
|||
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
const test_desc = "RequestDeviceOptions should have exactly one of " +
|
||||
"'filters' or 'acceptAllDevices:true'. Reject with TypeError if not.";
|
||||
const test_desc = 'RequestDeviceOptions should have exactly one of ' +
|
||||
'\'filters\' or \'acceptAllDevices:true\'. Reject with TypeError if not.';
|
||||
const expected = new DOMException(
|
||||
"Failed to execute 'requestDevice' on 'Bluetooth': " +
|
||||
"Either 'filters' should be present or " +
|
||||
"'acceptAllDevices' should be true, but not both.",
|
||||
'Failed to execute \'requestDevice\' on \'Bluetooth\': ' +
|
||||
'Either \'filters\' should be present or ' +
|
||||
'\'acceptAllDevices\' should be true, but not both.',
|
||||
new TypeError());
|
||||
const test_specs = [
|
||||
{},
|
||||
{optionalServices: ['heart_rate']},
|
||||
{filters: [], acceptAllDevices: true},
|
||||
{}, {optionalServices: ['heart_rate']}, {filters: [], acceptAllDevices: true},
|
||||
{filters: [], acceptAllDevices: true, optionalServices: ['heart_rate']}
|
||||
];
|
||||
|
||||
bluetooth_test(() => {
|
||||
let test_promises = Promise.resolve();
|
||||
test_specs.forEach(args => {
|
||||
test_promises = test_promises
|
||||
.then(() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick(args),
|
||||
expected))
|
||||
});
|
||||
return test_promises;
|
||||
}, test_desc);
|
||||
let test_promises = Promise.resolve();
|
||||
test_specs.forEach(
|
||||
args => {test_promises = test_promises.then(
|
||||
() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick(args), expected))});
|
||||
return test_promises;
|
||||
}, test_desc);
|
||||
</script>
|
||||
|
|
|
@ -9,15 +9,16 @@
|
|||
const test_desc = 'Unicode string with utf8 representation longer than 248 ' +
|
||||
'bytes in \'name\' must throw TypeError.';
|
||||
const expected = new DOMException(
|
||||
"Failed to execute 'requestDevice' on 'Bluetooth': " +
|
||||
"A device name can't be longer than 248 bytes.",
|
||||
'Failed to execute \'requestDevice\' on \'Bluetooth\': ' +
|
||||
'A device name can\'t be longer than 248 bytes.',
|
||||
new TypeError());
|
||||
// \u2764's UTF-8 respresentation is 3 bytes long.
|
||||
// 83 chars * 3 bytes/char = 249 bytes
|
||||
const unicode_name = '\u2764'.repeat(83);
|
||||
|
||||
bluetooth_test(() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick({filters: [{name: unicode_name}]}),
|
||||
expected),
|
||||
bluetooth_test(
|
||||
() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick({filters: [{name: unicode_name}]}),
|
||||
expected),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
'use strict';
|
||||
const test_desc = 'A device name longer than 248 must reject.';
|
||||
const expected = new DOMException(
|
||||
"Failed to execute 'requestDevice' on 'Bluetooth': A device " +
|
||||
"name can't be longer than 248 bytes.",
|
||||
'Failed to execute \'requestDevice\' on \'Bluetooth\': A device ' +
|
||||
'name can\'t be longer than 248 bytes.',
|
||||
new TypeError());
|
||||
const name_too_long = 'a'.repeat(249);
|
||||
|
||||
bluetooth_test(() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick({filters: [{name: name_too_long}]}),
|
||||
expected,
|
||||
'Device name longer than 248'),
|
||||
bluetooth_test(
|
||||
() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick({filters: [{name: name_too_long}]}),
|
||||
expected, 'Device name longer than 248'),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -9,15 +9,16 @@
|
|||
const test_desc = 'Unicode string with utf8 representation longer than 248 ' +
|
||||
'bytes in \'namePrefix\' must throw NotFoundError.';
|
||||
const expected = new DOMException(
|
||||
"Failed to execute 'requestDevice' on 'Bluetooth': " +
|
||||
"A device name can't be longer than 248 bytes.",
|
||||
'Failed to execute \'requestDevice\' on \'Bluetooth\': ' +
|
||||
'A device name can\'t be longer than 248 bytes.',
|
||||
new TypeError());
|
||||
// \u2764's UTF-8 respresentation is 3 bytes long.
|
||||
// 83 chars * 3 bytes/char = 249 bytes
|
||||
const unicode_name = '\u2764'.repeat(83);
|
||||
|
||||
bluetooth_test(() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick({filters: [{namePrefix: unicode_name}]}),
|
||||
expected),
|
||||
bluetooth_test(
|
||||
() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick({filters: [{namePrefix: unicode_name}]}),
|
||||
expected),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
'use strict';
|
||||
const test_desc = 'A device name prefix longer than 248 must reject.';
|
||||
const expected = new DOMException(
|
||||
"Failed to execute 'requestDevice' on 'Bluetooth': A device " +
|
||||
"name can't be longer than 248 bytes.",
|
||||
'Failed to execute \'requestDevice\' on \'Bluetooth\': A device ' +
|
||||
'name can\'t be longer than 248 bytes.',
|
||||
new TypeError());
|
||||
const name_too_long = 'a'.repeat(249);
|
||||
|
||||
bluetooth_test(() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick({filters: [{namePrefix: name_too_long}]}),
|
||||
expected,
|
||||
'Device name longer than 248'),
|
||||
bluetooth_test(
|
||||
() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick({filters: [{namePrefix: name_too_long}]}),
|
||||
expected, 'Device name longer than 248'),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -11,8 +11,11 @@ const test_desc = 'A unicode device name of 248 bytes is valid.';
|
|||
// 124 chars * 2 bytes/char = 248 bytes
|
||||
const DEVICE_NAME = '\u00A1'.repeat(124);
|
||||
|
||||
bluetooth_test(() => setUpPreconnectedDevice({name: DEVICE_NAME})
|
||||
.then(() => requestDeviceWithTrustedClick({ filters: [{name: DEVICE_NAME}]}))
|
||||
.then(device => assert_equals(device.name, DEVICE_NAME)),
|
||||
bluetooth_test(
|
||||
() => setUpPreconnectedDevice({name: DEVICE_NAME})
|
||||
.then(
|
||||
() => requestDeviceWithTrustedClick(
|
||||
{filters: [{name: DEVICE_NAME}]}))
|
||||
.then(device => assert_equals(device.name, DEVICE_NAME)),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -9,8 +9,11 @@
|
|||
const test_desc = 'A device name of 248 bytes is valid.';
|
||||
const DEVICE_NAME = 'a'.repeat(248);
|
||||
|
||||
bluetooth_test(() => setUpPreconnectedDevice({name: DEVICE_NAME})
|
||||
.then(() => requestDeviceWithTrustedClick({ filters: [{name: DEVICE_NAME}]}))
|
||||
.then(device => assert_equals(device.name, DEVICE_NAME)),
|
||||
bluetooth_test(
|
||||
() => setUpPreconnectedDevice({name: DEVICE_NAME})
|
||||
.then(
|
||||
() => requestDeviceWithTrustedClick(
|
||||
{filters: [{name: DEVICE_NAME}]}))
|
||||
.then(device => assert_equals(device.name, DEVICE_NAME)),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -11,10 +11,11 @@ const test_desc = 'A unicode device namePrefix of 248 bytes is valid.';
|
|||
// 124 chars * 2 bytes/char = 248 bytes
|
||||
const DEVICE_NAME = '\u00A1'.repeat(124);
|
||||
|
||||
bluetooth_test(() => setUpPreconnectedDevice({name: DEVICE_NAME})
|
||||
.then(() => requestDeviceWithTrustedClick({
|
||||
filters: [{namePrefix: DEVICE_NAME}]
|
||||
}))
|
||||
.then(device => assert_equals(device.name, DEVICE_NAME)),
|
||||
bluetooth_test(
|
||||
() => setUpPreconnectedDevice({name: DEVICE_NAME})
|
||||
.then(
|
||||
() => requestDeviceWithTrustedClick(
|
||||
{filters: [{namePrefix: DEVICE_NAME}]}))
|
||||
.then(device => assert_equals(device.name, DEVICE_NAME)),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -9,10 +9,11 @@
|
|||
const test_desc = 'A device namePrefix of 248 bytes is valid.';
|
||||
const DEVICE_NAME = 'a'.repeat(248);
|
||||
|
||||
bluetooth_test(() => setUpPreconnectedDevice({name: DEVICE_NAME})
|
||||
.then(() => requestDeviceWithTrustedClick({
|
||||
filters: [{namePrefix: DEVICE_NAME}]
|
||||
}))
|
||||
.then(device => assert_equals(device.name, DEVICE_NAME)),
|
||||
bluetooth_test(
|
||||
() => setUpPreconnectedDevice({name: DEVICE_NAME})
|
||||
.then(
|
||||
() => requestDeviceWithTrustedClick(
|
||||
{filters: [{namePrefix: DEVICE_NAME}]}))
|
||||
.then(device => assert_equals(device.name, DEVICE_NAME)),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
const test_desc = 'requestDevice() requires an argument.';
|
||||
const expected = new TypeError();
|
||||
|
||||
promise_test(() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick(),
|
||||
expected),
|
||||
promise_test(
|
||||
() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick(), expected),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -12,10 +12,11 @@ const test_desc = 'A name containing unicode characters whose utf8 length ' +
|
|||
// 9 chars * 3 bytes/char = 27 bytes
|
||||
const valid_unicode_name = '\u2764'.repeat(9);
|
||||
|
||||
bluetooth_test(() => setUpPreconnectedDevice({name: valid_unicode_name})
|
||||
.then(() => requestDeviceWithTrustedClick({
|
||||
filters: [{name: valid_unicode_name}]
|
||||
}))
|
||||
.then(device => assert_equals(device.name, valid_unicode_name)),
|
||||
bluetooth_test(
|
||||
() => setUpPreconnectedDevice({name: valid_unicode_name})
|
||||
.then(
|
||||
() => requestDeviceWithTrustedClick(
|
||||
{filters: [{name: valid_unicode_name}]}))
|
||||
.then(device => assert_equals(device.name, valid_unicode_name)),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -6,16 +6,17 @@
|
|||
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
const test_desc = 'A namePrefix containing unicode characters whose utf8 ' +
|
||||
const test_desc = 'A namePrefix containing unicode characters whose utf8 ' +
|
||||
'length is less than 30 must not throw an error.';
|
||||
// \u2764's UTF-8 representation is 3 bytes long.
|
||||
// 9 chars * 3 bytes/char = 27 bytes
|
||||
const valid_unicode_name = '\u2764'.repeat(9);
|
||||
|
||||
bluetooth_test(() => setUpPreconnectedDevice({name: valid_unicode_name})
|
||||
.then(() => requestDeviceWithTrustedClick({
|
||||
filters: [{namePrefix: valid_unicode_name}]
|
||||
}))
|
||||
.then(device => assert_equals(device.name, valid_unicode_name)),
|
||||
bluetooth_test(
|
||||
() => setUpPreconnectedDevice({name: valid_unicode_name})
|
||||
.then(
|
||||
() => requestDeviceWithTrustedClick(
|
||||
{filters: [{namePrefix: valid_unicode_name}]}))
|
||||
.then(device => assert_equals(device.name, valid_unicode_name)),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -8,37 +8,34 @@
|
|||
'use strict';
|
||||
const test_desc = 'Invalid optional service must reject the promise.';
|
||||
const expected = new TypeError();
|
||||
const test_specs = [{
|
||||
optionalServices: ['wrong_service'],
|
||||
filters: [{services: ['heart_rate']}]
|
||||
}, {
|
||||
optionalServices: ['wrong_service'],
|
||||
filters: [{ services: ['heart_rate'], name: 'Name'}]
|
||||
}, {
|
||||
optionalServices: ['wrong_service'],
|
||||
filters: [{ services: ['heart_rate'], namePrefix: 'Pre'}]
|
||||
}, {
|
||||
optionalServices: ['wrong_service'],
|
||||
filters: [{ services: ['heart_rate'], name: 'Name', namePrefix: 'Pre'}]
|
||||
}, {
|
||||
optionalServices: ['wrong_service'],
|
||||
filters: [{ name: 'Name'}]
|
||||
}, {
|
||||
optionalServices: ['wrong_service'],
|
||||
filters: [{ name: 'Name', namePrefix: 'Pre'}]
|
||||
}, {
|
||||
optionalServices: ['wrong_service'],
|
||||
filters: [{ namePrefix: 'Pre'}]
|
||||
}];
|
||||
const test_specs = [
|
||||
{optionalServices: ['wrong_service'], filters: [{services: ['heart_rate']}]},
|
||||
{
|
||||
optionalServices: ['wrong_service'],
|
||||
filters: [{services: ['heart_rate'], name: 'Name'}]
|
||||
},
|
||||
{
|
||||
optionalServices: ['wrong_service'],
|
||||
filters: [{services: ['heart_rate'], namePrefix: 'Pre'}]
|
||||
},
|
||||
{
|
||||
optionalServices: ['wrong_service'],
|
||||
filters: [{services: ['heart_rate'], name: 'Name', namePrefix: 'Pre'}]
|
||||
},
|
||||
{optionalServices: ['wrong_service'], filters: [{name: 'Name'}]}, {
|
||||
optionalServices: ['wrong_service'],
|
||||
filters: [{name: 'Name', namePrefix: 'Pre'}]
|
||||
},
|
||||
{optionalServices: ['wrong_service'], filters: [{namePrefix: 'Pre'}]}
|
||||
];
|
||||
|
||||
bluetooth_test(() => {
|
||||
let test_promises = Promise.resolve();
|
||||
test_specs.forEach(args => {
|
||||
test_promises =
|
||||
test_promises.then(() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick(args),
|
||||
expected));
|
||||
});
|
||||
return test_promises;
|
||||
}, test_desc);
|
||||
let test_promises = Promise.resolve();
|
||||
test_specs.forEach(args => {
|
||||
test_promises = test_promises.then(
|
||||
() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick(args), expected));
|
||||
});
|
||||
return test_promises;
|
||||
}, test_desc);
|
||||
</script>
|
||||
|
|
|
@ -10,13 +10,12 @@ const test_desc = 'Invalid service must reject the promise.';
|
|||
const expected = new TypeError();
|
||||
|
||||
bluetooth_test(() => {
|
||||
let test_promises = Promise.resolve();
|
||||
generateRequestDeviceArgsWithServices(['wrong_service']).forEach(args => {
|
||||
test_promises = test_promises.then(() =>
|
||||
assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick(args),
|
||||
expected));
|
||||
});
|
||||
return test_promises;
|
||||
}, test_desc);
|
||||
let test_promises = Promise.resolve();
|
||||
generateRequestDeviceArgsWithServices(['wrong_service']).forEach(args => {
|
||||
test_promises = test_promises.then(
|
||||
() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick(args), expected));
|
||||
});
|
||||
return test_promises;
|
||||
}, test_desc);
|
||||
</script>
|
||||
|
|
|
@ -13,26 +13,29 @@ const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
|
|||
'/bluetooth/resources/health-thermometer-iframe.html'
|
||||
let iframe = document.createElement('iframe');
|
||||
|
||||
bluetooth_test(() => setUpHealthThermometerDevice()
|
||||
// 1. Load the iframe.
|
||||
.then(() => new Promise(resolve => {
|
||||
iframe.src = cross_origin_src;
|
||||
document.body.appendChild(iframe);
|
||||
iframe.addEventListener('load', resolve);
|
||||
}))
|
||||
// 2. Request the device from the iframe.
|
||||
.then(() => new Promise(resolve => {
|
||||
callWithTrustedClick(() => {
|
||||
iframe.contentWindow.postMessage({
|
||||
type: 'RequestDevice'
|
||||
}, '*');
|
||||
});
|
||||
bluetooth_test(
|
||||
() => setUpHealthThermometerDevice()
|
||||
// 1. Load the iframe.
|
||||
.then(() => new Promise(resolve => {
|
||||
iframe.src = cross_origin_src;
|
||||
document.body.appendChild(iframe);
|
||||
iframe.addEventListener('load', resolve);
|
||||
}))
|
||||
// 2. Request the device from the iframe.
|
||||
.then(() => new Promise(resolve => {
|
||||
callWithTrustedClick(() => {
|
||||
iframe.contentWindow.postMessage(
|
||||
{type: 'RequestDevice'}, '*');
|
||||
});
|
||||
|
||||
window.onmessage = messageEvent => {
|
||||
assert_equals(messageEvent.data, 'SecurityError: requestDevice() ' +
|
||||
'called from cross-origin iframe.');
|
||||
resolve();
|
||||
}
|
||||
})), test_desc);
|
||||
window.onmessage = messageEvent => {
|
||||
assert_equals(
|
||||
messageEvent.data,
|
||||
'SecurityError: requestDevice() ' +
|
||||
'called from cross-origin iframe.');
|
||||
resolve();
|
||||
}
|
||||
})),
|
||||
test_desc);
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -8,21 +8,28 @@
|
|||
'use strict';
|
||||
const test_desc = 'Discover a device using alias, name, or UUID.';
|
||||
|
||||
bluetooth_test(() => getConnectedHealthThermometerDevice()
|
||||
// Chrome will always close the previous chooser in the process of handling
|
||||
// a user gesture for the next request, so these need to be done
|
||||
// sequentially.
|
||||
.then(() => requestDeviceWithTrustedClick({
|
||||
filters: [{services: [health_thermometer.alias]}]
|
||||
}))
|
||||
.then(device => assert_equals(device.constructor.name, 'BluetoothDevice'))
|
||||
.then(() => requestDeviceWithTrustedClick({
|
||||
filters: [{services: [health_thermometer.name]}]
|
||||
}))
|
||||
.then(device => assert_equals(device.constructor.name, 'BluetoothDevice'))
|
||||
.then(() => requestDeviceWithTrustedClick({
|
||||
filters: [{services: [health_thermometer.uuid]}]
|
||||
}))
|
||||
.then(device => assert_equals(device.constructor.name, 'BluetoothDevice')),
|
||||
bluetooth_test(
|
||||
() => getConnectedHealthThermometerDevice()
|
||||
// Chrome will always close the previous chooser in the process of
|
||||
// handling a user gesture for the next request, so these need to
|
||||
// be done sequentially.
|
||||
.then(
|
||||
() => requestDeviceWithTrustedClick(
|
||||
{filters: [{services: [health_thermometer.alias]}]}))
|
||||
.then(
|
||||
device =>
|
||||
assert_equals(device.constructor.name, 'BluetoothDevice'))
|
||||
.then(
|
||||
() => requestDeviceWithTrustedClick(
|
||||
{filters: [{services: [health_thermometer.name]}]}))
|
||||
.then(
|
||||
device =>
|
||||
assert_equals(device.constructor.name, 'BluetoothDevice'))
|
||||
.then(
|
||||
() => requestDeviceWithTrustedClick(
|
||||
{filters: [{services: [health_thermometer.uuid]}]}))
|
||||
.then(
|
||||
device => assert_equals(
|
||||
device.constructor.name, 'BluetoothDevice')),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -8,17 +8,21 @@
|
|||
'use strict';
|
||||
const test_desc = 'requestDevice calls do not consume user gestures.';
|
||||
|
||||
bluetooth_test(() => setUpHealthThermometerAndHeartRateDevices()
|
||||
.then(() => callWithTrustedClick(() => {
|
||||
let first = navigator.bluetooth.requestDevice({
|
||||
filters: [{services: ['heart_rate']}]});
|
||||
let second = navigator.bluetooth.requestDevice({
|
||||
filters: [{services: ['heart_rate']}]});
|
||||
return Promise.all([
|
||||
first.then(device => assert_equals(
|
||||
device.constructor.name, 'BluetoothDevice')),
|
||||
second.then(device => assert_equals(
|
||||
device.constructor.name, 'BluetoothDevice')),
|
||||
]);
|
||||
})), test_desc);
|
||||
bluetooth_test(
|
||||
() => setUpHealthThermometerAndHeartRateDevices().then(
|
||||
() => callWithTrustedClick(() => {
|
||||
let first = navigator.bluetooth.requestDevice(
|
||||
{filters: [{services: ['heart_rate']}]});
|
||||
let second = navigator.bluetooth.requestDevice(
|
||||
{filters: [{services: ['heart_rate']}]});
|
||||
return Promise.all([
|
||||
first.then(
|
||||
device =>
|
||||
assert_equals(device.constructor.name, 'BluetoothDevice')),
|
||||
second.then(
|
||||
device =>
|
||||
assert_equals(device.constructor.name, 'BluetoothDevice')),
|
||||
]);
|
||||
})),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -11,57 +11,55 @@ let matching_services = [health_thermometer.uuid];
|
|||
let matching_name = 'Health Thermometer';
|
||||
let matching_namePrefix = 'Health';
|
||||
|
||||
let test_specs = [{
|
||||
filters: [{
|
||||
services: matching_services,
|
||||
}]
|
||||
}, {
|
||||
filters: [{
|
||||
services: matching_services,
|
||||
name: matching_name,
|
||||
}]
|
||||
}, {
|
||||
filters: [{
|
||||
services: matching_services,
|
||||
namePrefix: matching_namePrefix
|
||||
}]
|
||||
}, {
|
||||
filters: [{
|
||||
name: matching_name,
|
||||
}],
|
||||
optionalServices: matching_services
|
||||
}, {
|
||||
filters: [{
|
||||
name: matching_name,
|
||||
namePrefix: matching_namePrefix
|
||||
}],
|
||||
optionalServices: matching_services
|
||||
}, {
|
||||
filters: [{
|
||||
namePrefix: matching_namePrefix
|
||||
}],
|
||||
optionalServices: matching_services
|
||||
}, {
|
||||
filters: [{
|
||||
services: matching_services,
|
||||
name: matching_name,
|
||||
namePrefix: matching_namePrefix
|
||||
}]
|
||||
}];
|
||||
let test_specs = [
|
||||
{
|
||||
filters: [{
|
||||
services: matching_services,
|
||||
}]
|
||||
},
|
||||
{
|
||||
filters: [{
|
||||
services: matching_services,
|
||||
name: matching_name,
|
||||
}]
|
||||
},
|
||||
{filters: [{services: matching_services, namePrefix: matching_namePrefix}]}, {
|
||||
filters: [{
|
||||
name: matching_name,
|
||||
}],
|
||||
optionalServices: matching_services
|
||||
},
|
||||
{
|
||||
filters: [{name: matching_name, namePrefix: matching_namePrefix}],
|
||||
optionalServices: matching_services
|
||||
},
|
||||
{
|
||||
filters: [{namePrefix: matching_namePrefix}],
|
||||
optionalServices: matching_services
|
||||
},
|
||||
{
|
||||
filters: [{
|
||||
services: matching_services,
|
||||
name: matching_name,
|
||||
namePrefix: matching_namePrefix
|
||||
}]
|
||||
}
|
||||
];
|
||||
|
||||
bluetooth_test(() => setUpHealthThermometerDevice()
|
||||
.then(() => {
|
||||
bluetooth_test(
|
||||
() => setUpHealthThermometerDevice().then(() => {
|
||||
let test_promises = Promise.resolve();
|
||||
test_specs.forEach(args => {
|
||||
test_promises = test_promises
|
||||
.then(() => requestDeviceWithTrustedClick(args))
|
||||
.then(device => {
|
||||
// We always have access to the services in matching_services
|
||||
// because we include them in a filter or in optionalServices.
|
||||
assert_equals(device.name, matching_name);
|
||||
assert_true(device.name.startsWith(matching_namePrefix));
|
||||
});
|
||||
test_promises =
|
||||
test_promises.then(() => requestDeviceWithTrustedClick(args))
|
||||
.then(device => {
|
||||
// We always have access to the services in matching_services
|
||||
// because we include them in a filter or in optionalServices.
|
||||
assert_equals(device.name, matching_name);
|
||||
assert_true(device.name.startsWith(matching_namePrefix));
|
||||
});
|
||||
});
|
||||
return test_promises;
|
||||
}), test_desc);
|
||||
}),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -7,12 +7,13 @@
|
|||
<script>
|
||||
'use strict';
|
||||
const test_desc = 'Reject with NotFoundError if Bluetooth is not supported.';
|
||||
const expected = new DOMException('Bluetooth Low Energy not available.',
|
||||
'NotFoundError');
|
||||
const expected =
|
||||
new DOMException('Bluetooth Low Energy not available.', 'NotFoundError');
|
||||
|
||||
bluetooth_test(() => navigator.bluetooth.test.setLESupported(false)
|
||||
.then(() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick({acceptAllDevices: true}),
|
||||
expected, 'Bluetooth Low Energy is not supported.')),
|
||||
bluetooth_test(
|
||||
() => navigator.bluetooth.test.setLESupported(false).then(
|
||||
() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick({acceptAllDevices: true}), expected,
|
||||
'Bluetooth Low Energy is not supported.')),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
'use strict';
|
||||
const test_desc = 'An empty name device can be obtained by empty name filter.'
|
||||
|
||||
bluetooth_test(() => setUpPreconnectedDevice({name: ''})
|
||||
.then(() => requestDeviceWithTrustedClick({filters: [{name: ''}]}))
|
||||
.then(device => assert_equals(device.name, '')),
|
||||
bluetooth_test(
|
||||
() =>
|
||||
setUpPreconnectedDevice({name: ''})
|
||||
.then(() => requestDeviceWithTrustedClick({filters: [{name: ''}]}))
|
||||
.then(device => assert_equals(device.name, '')),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -11,9 +11,11 @@ const expected = new DOMException(
|
|||
'Must be handling a user gesture to show a permission request.',
|
||||
'SecurityError');
|
||||
|
||||
bluetooth_test(() => setUpHealthThermometerAndHeartRateDevices()
|
||||
.then(() => assert_promise_rejects_with_message(
|
||||
navigator.bluetooth.requestDevice({filters:[{services:['heart_rate']}]}),
|
||||
expected, 'User gesture is required')),
|
||||
bluetooth_test(
|
||||
() => setUpHealthThermometerAndHeartRateDevices().then(
|
||||
() => assert_promise_rejects_with_message(
|
||||
navigator.bluetooth.requestDevice(
|
||||
{filters: [{services: ['heart_rate']}]}),
|
||||
expected, 'User gesture is required')),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -7,14 +7,15 @@
|
|||
<script>
|
||||
'use strict';
|
||||
const test_desc = 'Reject with NotFoundError if there is no BT radio present.';
|
||||
const expected = new DOMException('Bluetooth adapter not available.',
|
||||
'NotFoundError');
|
||||
const expected =
|
||||
new DOMException('Bluetooth adapter not available.', 'NotFoundError');
|
||||
|
||||
bluetooth_test(() => navigator.bluetooth.test.simulateCentral({state: 'absent'})
|
||||
.then(() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick({
|
||||
filters: [{services: ['generic_access']}]
|
||||
}),
|
||||
expected, 'Bluetooth adapter is not present.')),
|
||||
bluetooth_test(
|
||||
() => navigator.bluetooth.test.simulateCentral({state: 'absent'})
|
||||
.then(
|
||||
() => assert_promise_rejects_with_message(
|
||||
requestDeviceWithTrustedClick(
|
||||
{filters: [{services: ['generic_access']}]}),
|
||||
expected, 'Bluetooth adapter is not present.')),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -12,32 +12,36 @@ for (let i = 0; i < 5; i++) {
|
|||
iframes.push(document.createElement('iframe'));
|
||||
}
|
||||
|
||||
bluetooth_test(() => setUpHealthThermometerAndHeartRateDevices()
|
||||
// 1. Load the iframes.
|
||||
.then(() => {
|
||||
let promises = [];
|
||||
for (let iframe of iframes) {
|
||||
iframe.src = '/bluetooth/resources/health-thermometer-iframe.html';
|
||||
document.body.appendChild(iframe);
|
||||
promises.push(new Promise(resolve =>
|
||||
iframe.addEventListener('load', resolve)));
|
||||
}
|
||||
return Promise.all(promises);
|
||||
})
|
||||
// 2. Request the device from the iframes.
|
||||
.then(() => new Promise(async (resolve) => {
|
||||
let numMessages = 0;
|
||||
window.onmessage = messageEvent => {
|
||||
assert_equals(messageEvent.data, 'Success');
|
||||
if (++numMessages === iframes.length) {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
bluetooth_test(
|
||||
() => setUpHealthThermometerAndHeartRateDevices()
|
||||
// 1. Load the iframes.
|
||||
.then(() => {
|
||||
let promises = [];
|
||||
for (let iframe of iframes) {
|
||||
iframe.src =
|
||||
'/bluetooth/resources/health-thermometer-iframe.html';
|
||||
document.body.appendChild(iframe);
|
||||
promises.push(new Promise(
|
||||
resolve => iframe.addEventListener('load', resolve)));
|
||||
}
|
||||
return Promise.all(promises);
|
||||
})
|
||||
// 2. Request the device from the iframes.
|
||||
.then(() => new Promise(async (resolve) => {
|
||||
let numMessages = 0;
|
||||
window.onmessage =
|
||||
messageEvent => {
|
||||
assert_equals(messageEvent.data, 'Success');
|
||||
if (++numMessages === iframes.length) {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
for (let iframe of iframes) {
|
||||
await callWithTrustedClick(() => iframe.contentWindow.postMessage({
|
||||
type: 'RequestDevice'
|
||||
}, '*'));
|
||||
}
|
||||
})), test_desc);
|
||||
for (let iframe of iframes) {
|
||||
await callWithTrustedClick(
|
||||
() => iframe.contentWindow.postMessage(
|
||||
{type: 'RequestDevice'}, '*'));
|
||||
}
|
||||
})),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -14,26 +14,28 @@ const expected = 'SecurityError: requestDevice() called from cross-origin ' +
|
|||
|
||||
let iframe = document.createElement('iframe');
|
||||
|
||||
bluetooth_test(() => getConnectedHealthThermometerDevice()
|
||||
// 1. Load the iframe.
|
||||
.then(() => new Promise(resolve => {
|
||||
iframe.sandbox.add('allow-scripts');
|
||||
iframe.src = '/bluetooth/resources/health-thermometer-iframe.html';
|
||||
document.body.appendChild(iframe);
|
||||
iframe.addEventListener('load', resolve);
|
||||
}))
|
||||
// 2. Request the device from the iframe.
|
||||
.then(() => new Promise(resolve => {
|
||||
callWithTrustedClick(() => {
|
||||
iframe.contentWindow.postMessage({
|
||||
type: 'RequestDevice'
|
||||
}, '*');
|
||||
});
|
||||
bluetooth_test(
|
||||
() => getConnectedHealthThermometerDevice()
|
||||
// 1. Load the iframe.
|
||||
.then(() => new Promise(resolve => {
|
||||
iframe.sandbox.add('allow-scripts');
|
||||
iframe.src =
|
||||
'/bluetooth/resources/health-thermometer-iframe.html';
|
||||
document.body.appendChild(iframe);
|
||||
iframe.addEventListener('load', resolve);
|
||||
}))
|
||||
// 2. Request the device from the iframe.
|
||||
.then(() => new Promise(resolve => {
|
||||
callWithTrustedClick(() => {
|
||||
iframe.contentWindow.postMessage(
|
||||
{type: 'RequestDevice'}, '*');
|
||||
});
|
||||
|
||||
window.onmessage = messageEvent => {
|
||||
assert_equals(messageEvent.data, expected);
|
||||
resolve();
|
||||
}
|
||||
})), test_desc);
|
||||
window.onmessage = messageEvent => {
|
||||
assert_equals(messageEvent.data, expected);
|
||||
resolve();
|
||||
}
|
||||
})),
|
||||
test_desc);
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -10,21 +10,23 @@ const test_desc = 'Returned device should always be the same.';
|
|||
let devices = [];
|
||||
let push = device => devices.push(device);
|
||||
|
||||
bluetooth_test(() => setUpHealthThermometerAndHeartRateDevices()
|
||||
.then(() => requestDeviceWithTrustedClick({
|
||||
filters: [{services: [heart_rate.alias]}]
|
||||
}))
|
||||
.then(push)
|
||||
.then(() => requestDeviceWithTrustedClick({
|
||||
filters: [{services: [heart_rate.name]}]
|
||||
}))
|
||||
.then(push)
|
||||
.then(() => requestDeviceWithTrustedClick({
|
||||
filters: [{services: [heart_rate.uuid]}]
|
||||
}))
|
||||
.then(push)
|
||||
.then(() => {
|
||||
assert_equals(devices[0], devices[1]);
|
||||
assert_equals(devices[1], devices[2]);
|
||||
}), test_desc);
|
||||
bluetooth_test(
|
||||
() => setUpHealthThermometerAndHeartRateDevices()
|
||||
.then(
|
||||
() => requestDeviceWithTrustedClick(
|
||||
{filters: [{services: [heart_rate.alias]}]}))
|
||||
.then(push)
|
||||
.then(
|
||||
() => requestDeviceWithTrustedClick(
|
||||
{filters: [{services: [heart_rate.name]}]}))
|
||||
.then(push)
|
||||
.then(
|
||||
() => requestDeviceWithTrustedClick(
|
||||
{filters: [{services: [heart_rate.uuid]}]}))
|
||||
.then(push)
|
||||
.then(() => {
|
||||
assert_equals(devices[0], devices[1]);
|
||||
assert_equals(devices[1], devices[2]);
|
||||
}),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
'use strict';
|
||||
const test_desc = 'Simple filter selects matching device.';
|
||||
|
||||
bluetooth_test(() => setUpHealthThermometerAndHeartRateDevices()
|
||||
.then(() => requestDeviceWithTrustedClick({
|
||||
filters: [{services: ['health_thermometer']}]
|
||||
}))
|
||||
.then(device => assert_equals(device.name, 'Health Thermometer')),
|
||||
bluetooth_test(
|
||||
() => setUpHealthThermometerAndHeartRateDevices()
|
||||
.then(
|
||||
() => requestDeviceWithTrustedClick(
|
||||
{filters: [{services: ['health_thermometer']}]}))
|
||||
.then(device => assert_equals(device.name, 'Health Thermometer')),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -3,24 +3,24 @@
|
|||
let device, gatt;
|
||||
|
||||
function requestDeviceWithOptionsAndConnect(options) {
|
||||
return navigator.bluetooth.requestDevice(options)
|
||||
.then(device => device.gatt.connect());
|
||||
return navigator.bluetooth.requestDevice(options).then(
|
||||
device => device.gatt.connect());
|
||||
}
|
||||
|
||||
window.addEventListener('message', (messageEvent) => {
|
||||
switch (messageEvent.data.type) {
|
||||
case 'RequestDevice':
|
||||
navigator.bluetooth.requestDevice({
|
||||
filters: [{services: ['generic_access']}]
|
||||
})
|
||||
navigator.bluetooth
|
||||
.requestDevice({filters: [{services: ['generic_access']}]})
|
||||
.then(device => {
|
||||
if (device.constructor.name === 'BluetoothDevice') {
|
||||
parent.postMessage('Success', '*');
|
||||
} else {
|
||||
parent.postMessage(
|
||||
`FAIL: requestDevice in iframe returned ${device.name}`, '*');
|
||||
}}).catch(err => parent.postMessage(`${err.name}: ${err.message}`,
|
||||
'*'));
|
||||
}
|
||||
})
|
||||
.catch(err => parent.postMessage(`${err.name}: ${err.message}`, '*'));
|
||||
break;
|
||||
case 'RequestAndConnect':
|
||||
requestDeviceWithOptionsAndConnect(messageEvent.data.options)
|
||||
|
@ -28,7 +28,8 @@ window.addEventListener('message', (messageEvent) => {
|
|||
gatt = _;
|
||||
device = gatt.device;
|
||||
parent.postMessage('Connected', '*');
|
||||
}).catch(err => {
|
||||
})
|
||||
.catch(err => {
|
||||
parent.postMessage(`FAIL: ${err}`, '*');
|
||||
});
|
||||
break;
|
||||
|
@ -50,8 +51,8 @@ window.addEventListener('message', (messageEvent) => {
|
|||
.catch(err => parent.postMessage(`FAIL: ${err}`, '*'));
|
||||
break;
|
||||
default:
|
||||
parent.postMessage(`FAIL: Bad message type: ${messageEvent.data.type}`,
|
||||
'*');
|
||||
parent.postMessage(
|
||||
`FAIL: Bad message type: ${messageEvent.data.type}`, '*');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -9,11 +9,13 @@
|
|||
const test_desc = '[SameObject] test for BluetoothRemoteGATTServer\'s device.';
|
||||
let device, fake_peripheral;
|
||||
|
||||
bluetooth_test(() => getDiscoveredHealthThermometerDevice()
|
||||
.then(_ => ({device, fake_peripheral} = _))
|
||||
.then(() =>
|
||||
fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS}))
|
||||
.then(() => device.gatt.connect())
|
||||
.then(gatt => assert_equals(gatt.device, gatt.device)),
|
||||
bluetooth_test(
|
||||
() => getDiscoveredHealthThermometerDevice()
|
||||
.then(_ => ({device, fake_peripheral} = _))
|
||||
.then(
|
||||
() => fake_peripheral.setNextGATTConnectionResponse(
|
||||
{code: HCI_SUCCESS}))
|
||||
.then(() => device.gatt.connect())
|
||||
.then(gatt => assert_equals(gatt.device, gatt.device)),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -8,11 +8,14 @@
|
|||
'use strict';
|
||||
const test_desc = 'Same parent device returned from multiple services.';
|
||||
|
||||
bluetooth_test(() => getTwoHealthThermometerServicesDevice({
|
||||
filters: [{services: ['health_thermometer']}]
|
||||
})
|
||||
.then(({device}) => device.gatt.getPrimaryServices('health_thermometer'))
|
||||
.then(([service1, service2]) =>
|
||||
assert_equals(service1.device, service2.device)),
|
||||
bluetooth_test(
|
||||
() => getTwoHealthThermometerServicesDevice(
|
||||
{filters: [{services: ['health_thermometer']}]})
|
||||
.then(
|
||||
({device}) =>
|
||||
device.gatt.getPrimaryServices('health_thermometer'))
|
||||
.then(
|
||||
([service1, service2]) =>
|
||||
assert_equals(service1.device, service2.device)),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
'use strict';
|
||||
const test_desc = '[SameObject] test for BluetoothRemoteGATTService device.';
|
||||
|
||||
bluetooth_test(() => getHealthThermometerDevice({
|
||||
filters: [{services: ['health_thermometer']}]
|
||||
})
|
||||
.then(({device}) => device.gatt.getPrimaryService('health_thermometer'))
|
||||
.then(service => assert_equals(service.device, service.device)),
|
||||
bluetooth_test(
|
||||
() => getHealthThermometerDevice(
|
||||
{filters: [{services: ['health_thermometer']}]})
|
||||
.then(
|
||||
({device}) =>
|
||||
device.gatt.getPrimaryService('health_thermometer'))
|
||||
.then(service => assert_equals(service.device, service.device)),
|
||||
test_desc);
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CSS Background Test: Large images with one auto size are correctly sized</title>
|
||||
<link rel="author" title="schenney" href="mailto:schenney@chromium.org">
|
||||
<link rel="help" href="http://www.w3.org/TR/css3-background">
|
||||
<link rel="match" href="reference/background-image-large-with-auto-ref.html">
|
||||
<style>
|
||||
.wide-div {
|
||||
background-image: url(support/green-1000x10.png);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 10000px auto;
|
||||
width: 1000px;
|
||||
height: 100px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
.high-div {
|
||||
background-image: url(support/green-10x1000.png);
|
||||
background-repeat: no-repeat;
|
||||
background-size: auto 10000px;
|
||||
width: 100px;
|
||||
height: 1000px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class='wide-div'></div>
|
||||
<div class='high-div'></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CSS Background Test Reference</title>
|
||||
<link rel="author" title="schenney" href="mailto:schenney@chromium.org">
|
||||
<style>
|
||||
.wide-div {
|
||||
background-image: url(../support/green-1000x10.png);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 10000px 100px;
|
||||
width: 1000px;
|
||||
height: 100px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
.high-div {
|
||||
background-image: url(../support/green-10x1000.png);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100px 10000px;
|
||||
width: 100px;
|
||||
height: 1000px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class='wide-div'></div>
|
||||
<div class='high-div'></div>
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
After Width: | Height: | Size: 128 B |
Binary file not shown.
After Width: | Height: | Size: 161 B |
|
@ -147,6 +147,8 @@
|
|||
{ value: "oblique 20deg", isValid: true, expectedValue: "oblique", description: "'oblique' followed by default 20deg angle" },
|
||||
{ value: "oblique 90deg", isValid: true, description: "'oblique' followed by maxumum 90 degree angle" },
|
||||
{ value: "oblique -90deg", isValid: true, description: "'oblique' followed by minimum -90 degree angle" },
|
||||
{ value: "oblique calc(91deg)", isValid: true, expectedValue: "oblique 90deg", description: "'oblique' followed by calc with out of range value (should be clamped)" },
|
||||
{ value: "oblique calc(-91deg)", isValid: true, expectedValue: "oblique -90deg", description: "'oblique' followed by calc with out of range value (should be clamped)" },
|
||||
{ value: "oblique 0rad", isValid: true, expectedValue: "oblique 0deg", description: "'oblique' followed by angle in radians" },
|
||||
{ value: "oblique 20", isValid: false, description: "'oblique' followed by unit-less number" },
|
||||
{ value: "oblique 20px", isValid: false, description: "'oblique' followed by non-angle" },
|
||||
|
|
|
@ -7,43 +7,54 @@
|
|||
<script src="/resources/testharnessreport.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="test"></div>
|
||||
<script>
|
||||
|
||||
var testFontStyle = [
|
||||
{ style: "italic", expectedResult: true, message: "'italic' is valid" },
|
||||
{ style: "italic 20deg", expectedResult: false, message: "'italic' followed by angle is invalid" },
|
||||
{ style: "italic a", expectedResult: false, message: "'italic' followed by non-number is invalid" },
|
||||
{ style: "oblique", expectedResult: true, message: "'oblique' is valid" },
|
||||
{ style: "oblique 0deg", expectedResult: true, message: "'oblique' followed by zero degrees is valid" },
|
||||
{ style: "oblique 20deg", expectedResult: true, message: "'oblique' followed by positive angle in degrees is valid" },
|
||||
{ style: "oblique 0.5rad", expectedResult: true, message: "'oblique' followed by positive angle in radians is valid" },
|
||||
{ style: "oblique 20grad", expectedResult: true, message: "'oblique' followed by positive angle in gradians is valid" },
|
||||
{ style: "oblique 0.1turn", expectedResult: true, message: "'oblique' followed by positive angle in turns is valid" },
|
||||
{ style: "oblique 20px", expectedResult: false, message: "'oblique' followed by number with invalid unit type is in valid" },
|
||||
{ style: "oblique -20deg", expectedResult: true, message: "'oblique' followed by negative angle is valid" },
|
||||
{ style: "oblique 20.1deg", expectedResult: true, message: "'oblique' followed by fractional angle is valid" },
|
||||
{ style: "oblique 90deg", expectedResult: true, message: "'oblique' followed by maxumum 90 degree angle is valid" },
|
||||
{ style: "oblique -90deg", expectedResult: true, message: "'oblique' followed by minimum -90 degree angle is valid" },
|
||||
{ style: "oblique 90.01deg", expectedResult: false, message: "'oblique' followed by positive out of range angle is in invalid" },
|
||||
{ style: "oblique -90.01deg", expectedResult: false, message: "'oblique' followed by negative out of range angle is in invalid" },
|
||||
{ style: "oblique 10", expectedResult: false, message: "'oblique' followed by unit-less value is invalid" },
|
||||
{ style: "oblique 20deg ", expectedResult: true, message: "'oblique' followed by positive angle is valid" },
|
||||
{ style: "oblique a", expectedResult: false, message: "'oblique' followed by non-number is invalid" },
|
||||
{ style: "oblique 20deg a", expectedResult: false, message: "'oblique' and angle followed by non-number is invalid" },
|
||||
{ style: "oblique -", expectedResult: false, message: "'oblique' followed by isolated minus is invalid" },
|
||||
{ style: "oblique - 20deg", expectedResult: false, message: "'oblique' followed by minus and angle separated by space is invalid" },
|
||||
{ style: "oblique -a", expectedResult: false, message: "'oblique' followed by minus and non-number is invalid" },
|
||||
{ style: "oblique calc(50deg)", expectedResult: true, message: "'oblique' followed by calc is valid" },
|
||||
{ style: "oblique calc(-120deg)", expectedResult: true, message: "'oblique' followed by calc is valid even if it must be clamped (no computation)" },
|
||||
{ style: "oblique calc(6 * 20deg)", expectedResult: true, message: "'oblique' followed by calc is valid even if it must be clamped (with computation)" },
|
||||
{ style: "oblique calc(0.1rad + 1deg)", expectedResult: true, message: "'oblique' followed by calc is valid even if it mixes units (with computation)" }
|
||||
{ style: "italic", expectedResult: true, message: "'italic' is valid" },
|
||||
{ style: "italic 20deg", expectedResult: false, message: "'italic' followed by angle is invalid" },
|
||||
{ style: "italic a", expectedResult: false, message: "'italic' followed by non-number is invalid" },
|
||||
{ style: "oblique", expectedResult: true, message: "'oblique' is valid" },
|
||||
{ style: "oblique 0deg", expectedResult: true, message: "'oblique' followed by zero degrees is valid" },
|
||||
{ style: "oblique 20deg", expectedResult: true, message: "'oblique' followed by positive angle in degrees is valid" },
|
||||
{ style: "oblique 0.5rad", expectedResult: true, message: "'oblique' followed by positive angle in radians is valid", expectedValue: "oblique 28.6479deg" },
|
||||
{ style: "oblique 20grad", expectedResult: true, message: "'oblique' followed by positive angle in gradians is valid", expectedValue: "oblique 18deg" },
|
||||
{ style: "oblique 0.1turn", expectedResult: true, message: "'oblique' followed by positive angle in turns is valid", expectedValue: "oblique 36deg" },
|
||||
{ style: "oblique 20px", expectedResult: false, message: "'oblique' followed by number with invalid unit type is in valid" },
|
||||
{ style: "oblique -20deg", expectedResult: true, message: "'oblique' followed by negative angle is valid" },
|
||||
{ style: "oblique 20.5deg", expectedResult: true, message: "'oblique' followed by fractional angle is valid" },
|
||||
{ style: "oblique 90deg", expectedResult: true, message: "'oblique' followed by maxumum 90 degree angle is valid" },
|
||||
{ style: "oblique -90deg", expectedResult: true, message: "'oblique' followed by minimum -90 degree angle is valid" },
|
||||
{ style: "oblique 90.01deg", expectedResult: false, message: "'oblique' followed by positive out of range angle is in invalid" },
|
||||
{ style: "oblique -90.01deg", expectedResult: false, message: "'oblique' followed by negative out of range angle is in invalid" },
|
||||
{ style: "oblique 10", expectedResult: false, message: "'oblique' followed by unit-less value is invalid" },
|
||||
{ style: "oblique 30deg", expectedResult: true, message: "'oblique' followed by positive angle is valid" },
|
||||
{ style: "oblique a", expectedResult: false, message: "'oblique' followed by non-number is invalid" },
|
||||
{ style: "oblique 20deg a", expectedResult: false, message: "'oblique' and angle followed by non-number is invalid" },
|
||||
{ style: "oblique -", expectedResult: false, message: "'oblique' followed by isolated minus is invalid" },
|
||||
{ style: "oblique - 20deg", expectedResult: false, message: "'oblique' followed by minus and angle separated by space is invalid" },
|
||||
{ style: "oblique -a", expectedResult: false, message: "'oblique' followed by minus and non-number is invalid" },
|
||||
{ style: "oblique calc(50deg)", expectedResult: true, message: "'oblique' followed by calc is valid", expectedValue: "oblique 50deg" },
|
||||
{ style: "oblique calc(-120deg)", expectedResult: true, message: "'oblique' followed by calc is valid even if it must be clamped (no computation)", expectedValue: "oblique -90deg" },
|
||||
{ style: "oblique calc(6 * 20deg)", expectedResult: true, message: "'oblique' followed by calc is valid even if it must be clamped (with computation)", expectedValue: "oblique 90deg" },
|
||||
{ style: "oblique calc(10grad + 5deg)", expectedResult: true, message: "'oblique' followed by calc is valid even if it mixes units (with computation)", expectedValue: "oblique 14deg" }
|
||||
];
|
||||
|
||||
testFontStyle.forEach(function (testCase) {
|
||||
test(() => { assert_equals(window.CSS.supports("font-style", testCase.style), testCase.expectedResult, "Font-style: " + testCase.message); }, "Font-style: " + testCase.message);
|
||||
test(() => {
|
||||
assert_equals(window.CSS.supports("font-style", testCase.style), testCase.expectedResult, "Font-style supports: " + testCase.message);
|
||||
}, "Font-style (supports): " + testCase.message);
|
||||
});
|
||||
|
||||
testFontStyle.forEach(function (testCase) {
|
||||
if (testCase.expectedResult) {
|
||||
test(() => {
|
||||
let element = document.getElementById("test");
|
||||
element.style = "font-style: " + testCase.style;
|
||||
let expectedValue = (testCase.expectedValue) ? testCase.expectedValue : testCase.style;
|
||||
assert_equals(window.getComputedStyle(element).fontStyle, expectedValue, "Font-style computed style: " + testCase.message);
|
||||
}, "Font-style (computed): " + testCase.message);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Multi-column Layout Test Reference: Test column-span:all when the body tag is the multi-column container</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
|
||||
<style>
|
||||
body {
|
||||
column-count: 1;
|
||||
column-rule: 6px solid;
|
||||
width: 400px;
|
||||
outline: 1px solid black;
|
||||
}
|
||||
h3 {
|
||||
/* column-count: 1 makes this behave like a real spanner. */
|
||||
outline: 1px solid blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<div>block1</div>
|
||||
<div>
|
||||
<h3>spanner</h3>
|
||||
</div>
|
||||
<div>block2</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Multi-column Layout Test: Test column-span:all when the body tag is the multi-column container</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span">
|
||||
<link rel="match" href="multicol-span-all-007-ref.html">
|
||||
<meta name="assert" content="This test checks a column-span:all element is working if the body tag is the multi-column container.">
|
||||
|
||||
<style>
|
||||
body {
|
||||
column-count: 3;
|
||||
column-rule: 6px solid;
|
||||
width: 400px;
|
||||
outline: 1px solid black;
|
||||
}
|
||||
h3 {
|
||||
column-span: all;
|
||||
outline: 1px solid blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<div>block1</div>
|
||||
<div>
|
||||
<h3>spanner</h3> <!-- Put spanner in a subtree deliberately -->
|
||||
</div>
|
||||
<div>block2</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Multi-column Layout Test Reference: Append a block containing a spanner kid. The spanner kid should correctly span across all columns.</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
|
||||
<style>
|
||||
#column {
|
||||
column-count: 3;
|
||||
column-rule: 6px solid;
|
||||
width: 400px;
|
||||
outline: 1px solid black;
|
||||
}
|
||||
h3 {
|
||||
column-span: all;
|
||||
outline: 1px solid blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<article id="column">
|
||||
<div>block1</div>
|
||||
<div><h3>spanner</h3>block2</div>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Multi-column Layout Test: Append a block containing a spanner kid. The spanner kid should correctly span across all columns.</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span">
|
||||
<link rel="match" href="multicol-span-all-dynamic-add-010-ref.html">
|
||||
<meta name="assert" content="This test checks appending a block containing 'column-span' element should be rendered correctly.">
|
||||
|
||||
<script>
|
||||
function runTest() {
|
||||
document.body.offsetHeight;
|
||||
|
||||
// Create a subtree like the following, and append it to columns.
|
||||
// <div>
|
||||
// <h3>spanner</h3>
|
||||
// block2
|
||||
// </div>
|
||||
var spanner = document.createElement("h3");
|
||||
var spannerText = document.createTextNode("spanner");
|
||||
spanner.appendChild(spannerText);
|
||||
|
||||
var block2 = document.createElement("div");
|
||||
var block2Text = document.createTextNode("block2");
|
||||
block2.appendChild(spanner);
|
||||
block2.appendChild(block2Text)
|
||||
|
||||
var column = document.getElementById("column");
|
||||
column.appendChild(block2);
|
||||
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#column {
|
||||
column-count: 3;
|
||||
column-rule: 6px solid;
|
||||
width: 400px;
|
||||
outline: 1px solid black;
|
||||
}
|
||||
h3 {
|
||||
column-span: all;
|
||||
outline: 1px solid blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body onload="runTest();">
|
||||
<article id="column">
|
||||
<div>block1</div>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Inheritance of CSS Overflow properties</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-overflow/#property-index">
|
||||
<meta name="assert" content="Properties inherit or not according to the spec.">
|
||||
<meta name="assert" content="Properties have initial values according to the spec.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/inheritance-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="target"></div>
|
||||
</div>
|
||||
<script>
|
||||
assert_inherited('block-ellipsis', 'none', 'auto');
|
||||
assert_not_inherited('continue', 'auto', 'discard');
|
||||
assert_not_inherited('max-lines', 'none', '2');
|
||||
assert_not_inherited('overflow-block', 'visible', 'scroll');
|
||||
assert_not_inherited('overflow-inline', 'visible', 'scroll');
|
||||
assert_not_inherited('overflow-x', 'visible', 'scroll');
|
||||
assert_not_inherited('overflow-y', 'visible', 'scroll');
|
||||
assert_not_inherited('text-overflow', 'clip', 'ellipsis');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Overflow: parsing block-ellipsis with invalid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-block-ellipsis">
|
||||
<meta name="assert" content="block-ellipsis supports only the grammar 'none | auto | <string>'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_invalid_value("block-ellipsis", 'hidden');
|
||||
|
||||
test_invalid_value("block-ellipsis", 'none auto');
|
||||
test_invalid_value("block-ellipsis", 'auto "string"');
|
||||
test_invalid_value("block-ellipsis", '"string" none');
|
||||
test_invalid_value("block-ellipsis", '"first" "second"');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Overflow: parsing block-ellipsis with valid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-block-ellipsis">
|
||||
<meta name="assert" content="block-ellipsis supports the full grammar 'none | auto | <string>'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_valid_value("block-ellipsis", 'none');
|
||||
test_valid_value("block-ellipsis", 'auto');
|
||||
test_valid_value("block-ellipsis", '" etc., etc. "');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Overflow: parsing continue with invalid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-continue">
|
||||
<meta name="assert" content="continue supports only the grammar 'auto | discard'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_invalid_value("continue", 'none');
|
||||
|
||||
test_invalid_value("continue", 'auto discard');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Overflow: parsing continue with valid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-continue">
|
||||
<meta name="assert" content="continue supports the full grammar 'auto | discard'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_valid_value("continue", 'auto');
|
||||
test_valid_value("continue", 'discard');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Overflow: parsing line-clamp with invalid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-line-clamp">
|
||||
<meta name="assert" content="line-clamp supports only the grammar 'none | <integer> <‘block-ellipsis’>?'.">
|
||||
<meta name="assert" content="Zero or negative max-lines integers are invalid.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_invalid_value("line-clamp", 'auto');
|
||||
|
||||
test_invalid_value("line-clamp", '0');
|
||||
test_invalid_value("line-clamp", '-5');
|
||||
|
||||
test_invalid_value("line-clamp", '" etc., etc. "');
|
||||
|
||||
test_invalid_value("line-clamp", 'none 2');
|
||||
test_invalid_value("line-clamp", '3 none');
|
||||
test_invalid_value("line-clamp", 'auto 4');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Overflow: parsing line-clamp with valid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-line-clamp">
|
||||
<meta name="assert" content="line-clamp supports the full grammar 'none | <integer> <‘block-ellipsis’>?'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_valid_value("line-clamp", 'none');
|
||||
|
||||
test_valid_value("line-clamp", '1');
|
||||
test_valid_value("line-clamp", '6');
|
||||
|
||||
test_valid_value("line-clamp", '7 none');
|
||||
test_valid_value("line-clamp", '8 auto', '8');
|
||||
test_valid_value("line-clamp", '9 " etc., etc. "');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Overflow: parsing max-lines with invalid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-max-lines">
|
||||
<meta name="assert" content="max-lines supports only the grammar 'none | <integer>'.">
|
||||
<meta name="assert" content="Zero or negative integers are invalid.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_invalid_value("max-lines", 'auto');
|
||||
test_invalid_value("max-lines", '0');
|
||||
test_invalid_value("max-lines", '-5');
|
||||
|
||||
test_invalid_value("max-lines", 'none none');
|
||||
test_invalid_value("max-lines", '1 none');
|
||||
test_invalid_value("max-lines", 'none 2');
|
||||
test_invalid_value("max-lines", '3 4');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Overflow: parsing max-lines with valid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-max-lines">
|
||||
<meta name="assert" content="max-lines supports the full grammar 'none | <integer>'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_valid_value("max-lines", 'none');
|
||||
test_valid_value("max-lines", '1');
|
||||
test_valid_value("max-lines", '6');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,52 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Overflow: getComputedValue().overflow</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-overflow">
|
||||
<meta name="assert" content="visible/clip compute to auto/hidden (respectively) if one of overflow-x or overflow-y is neither visible nor clip.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/computed-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="target"></div>
|
||||
<script>
|
||||
test_computed_value("overflow", 'visible');
|
||||
test_computed_value("overflow", 'hidden');
|
||||
test_computed_value("overflow", 'clip');
|
||||
test_computed_value("overflow", 'scroll');
|
||||
test_computed_value("overflow", 'auto');
|
||||
|
||||
test_computed_value("overflow", 'auto auto', 'auto');
|
||||
test_computed_value("overflow", 'auto clip', 'auto hidden');
|
||||
test_computed_value("overflow", 'auto visible', 'auto');
|
||||
test_computed_value("overflow", 'clip auto', 'hidden auto');
|
||||
test_computed_value("overflow", 'clip clip', 'clip');
|
||||
test_computed_value("overflow", 'clip hidden', 'hidden');
|
||||
test_computed_value("overflow", 'clip scroll', 'hidden scroll')
|
||||
test_computed_value("overflow", 'hidden clip', 'hidden');
|
||||
test_computed_value("overflow", 'hidden visible', 'hidden auto');
|
||||
test_computed_value("overflow", 'scroll auto');
|
||||
test_computed_value("overflow", 'scroll clip', 'scroll hidden');
|
||||
test_computed_value("overflow", 'scroll visible', 'scroll auto');
|
||||
test_computed_value("overflow", 'visible auto', 'auto');
|
||||
test_computed_value("overflow", 'visible hidden', 'auto hidden');
|
||||
test_computed_value("overflow", 'visible scroll', 'auto scroll');
|
||||
test_computed_value("overflow", 'visible visible', 'visible');
|
||||
|
||||
|
||||
test_computed_value("overflow-x", 'scroll');
|
||||
test_computed_value("overflow-x", 'hidden');
|
||||
test_computed_value("overflow-x", 'visible');
|
||||
test_computed_value("overflow-y", 'clip');
|
||||
test_computed_value("overflow-y", 'auto');
|
||||
test_computed_value("overflow-y", 'visible');
|
||||
test_computed_value("overflow-block", 'hidden');
|
||||
test_computed_value("overflow-block", 'clip');
|
||||
test_computed_value("overflow-block", 'visible');
|
||||
test_computed_value("overflow-inline", 'scroll');
|
||||
test_computed_value("overflow-inline", 'visible');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Overflow: parsing overflow with invalid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-overflow">
|
||||
<meta name="assert" content="overflow supports only the grammar '[ visible | hidden | clip | scroll | auto ]{1,2}'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_invalid_value("overflow", 'none');
|
||||
test_invalid_value("overflow", 'visible clip auto');
|
||||
|
||||
|
||||
test_invalid_value("overflow-x", 'visible clip');
|
||||
test_invalid_value("overflow-y", 'clip hidden');
|
||||
test_invalid_value("overflow-block", 'hidden scroll');
|
||||
test_invalid_value("overflow-inline", 'scroll auto');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Overflow: parsing overflow with valid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-overflow">
|
||||
<meta name="assert" content="overflow supports the full grammar '[ visible | hidden | clip | scroll | auto ]{1,2}'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_valid_value("overflow", 'visible');
|
||||
test_valid_value("overflow", 'hidden');
|
||||
test_valid_value("overflow", 'clip');
|
||||
test_valid_value("overflow", 'scroll');
|
||||
test_valid_value("overflow", 'auto');
|
||||
|
||||
test_valid_value("overflow", 'visible visible', 'visible');
|
||||
test_valid_value("overflow", 'hidden visible');
|
||||
test_valid_value("overflow", 'clip clip', 'clip');
|
||||
test_valid_value("overflow", 'scroll auto');
|
||||
test_valid_value("overflow", 'auto auto', 'auto');
|
||||
|
||||
|
||||
test_valid_value("overflow-x", 'visible');
|
||||
test_valid_value("overflow-x", 'scroll');
|
||||
test_valid_value("overflow-y", 'clip');
|
||||
test_valid_value("overflow-y", 'auto');
|
||||
test_valid_value("overflow-block", 'hidden');
|
||||
test_valid_value("overflow-block", 'clip');
|
||||
test_valid_value("overflow-inline", 'scroll');
|
||||
test_valid_value("overflow-inline", 'visible');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Overflow: getComputedValue().textOverflow</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-text-overflow">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/computed-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="target"></div>
|
||||
<script>
|
||||
test_computed_value("text-overflow", 'clip');
|
||||
test_computed_value("text-overflow", 'ellipsis');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Overflow: parsing text-overflow with invalid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-text-overflow">
|
||||
<meta name="assert" content="text-overflow supports only the grammar 'clip | ellipsis'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_invalid_value("text-overflow", 'auto');
|
||||
|
||||
test_invalid_value("text-overflow", 'clip ellipsis clip');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Overflow: parsing text-overflow with valid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-text-overflow">
|
||||
<meta name="assert" content="text-overflow supports the full grammar 'clip | ellipsis'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_valid_value("text-overflow", 'clip');
|
||||
test_valid_value("text-overflow", 'ellipsis');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-scroll-anchoring-1/">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<style>
|
||||
|
||||
#scroller {
|
||||
overflow: scroll;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
}
|
||||
#before { height: 50px; }
|
||||
#content { margin-top: 100px; margin-bottom: 600px; }
|
||||
.no { overflow-anchor: none; }
|
||||
|
||||
</style>
|
||||
<div id="scroller">
|
||||
<div id="before"></div>
|
||||
<div id="content">content</div>
|
||||
</div>
|
||||
<script>
|
||||
|
||||
// Tests that dynamic styling 'overflow-anchor' on a scrolling element has the
|
||||
// same effect as initial styling
|
||||
|
||||
test(() => {
|
||||
let scroller = document.querySelector("#scroller");
|
||||
let before = document.querySelector("#before");
|
||||
|
||||
// Scroll down so that #content is the first element in the viewport
|
||||
scroller.scrollTop = 100;
|
||||
|
||||
// Change the height of #before to trigger a scroll adjustment. This ensures
|
||||
// that #content was selected as a scroll anchor
|
||||
before.style.height = "100px";
|
||||
assert_equals(scroller.scrollTop, 150);
|
||||
|
||||
// Now set 'overflow-anchor: none' on #scroller. This should invalidate the
|
||||
// scroll anchor, and #scroller shouldn't be able to select an anchor anymore
|
||||
scroller.className = 'no';
|
||||
|
||||
// Change the height of #before and make sure we don't adjust. This ensures
|
||||
// that #content is not a scroll anchor
|
||||
before.style.height = "150px";
|
||||
assert_equals(scroller.scrollTop, 150);
|
||||
}, "Dynamically styling 'overflow-anchor: none' on the scroller element should prevent scroll anchoring");
|
||||
|
||||
</script>
|
|
@ -0,0 +1,51 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-scroll-anchoring-1/">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<style>
|
||||
|
||||
#scroller {
|
||||
overflow: scroll;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
}
|
||||
#before { height: 50px; }
|
||||
#content { margin-top: 100px; margin-bottom: 600px; }
|
||||
.no { overflow-anchor: none; }
|
||||
|
||||
</style>
|
||||
<div id="scroller">
|
||||
<div id="before"></div>
|
||||
<div id="content">content</div>
|
||||
</div>
|
||||
<script>
|
||||
|
||||
// Tests that dynamic styling 'overflow-anchor' on an anchor node has the
|
||||
// same effect as initial styling
|
||||
|
||||
test(() => {
|
||||
let scroller = document.querySelector("#scroller");
|
||||
let before = document.querySelector("#before");
|
||||
let content = document.querySelector("#content");
|
||||
|
||||
// Scroll down so that #content is the first element in the viewport
|
||||
scroller.scrollTop = 100;
|
||||
|
||||
// Change the height of #before to trigger a scroll adjustment. This ensures
|
||||
// that #content was selected as a scroll anchor
|
||||
before.style.height = "100px";
|
||||
assert_equals(scroller.scrollTop, 150);
|
||||
|
||||
// Now set 'overflow-anchor: none' on #content. This should invalidate the
|
||||
// scroll anchor, and #scroller should recalculate its anchor. There are no
|
||||
// other valid anchors in the viewport, so there should be no anchor.
|
||||
content.className = 'no';
|
||||
|
||||
// Change the height of #before and make sure we don't adjust. This ensures
|
||||
// that #content was not selected as a scroll anchor
|
||||
before.style.height = "150px";
|
||||
assert_equals(scroller.scrollTop, 150);
|
||||
}, "Dynamically styling 'overflow-anchor: none' on the anchor node should prevent scroll anchoring");
|
||||
|
||||
</script>
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CSS Shadow Parts - Interaction with placeholder</title>
|
||||
<meta href="mailto:fergal@chromium.org" rel="author" title="Fergal Daly">
|
||||
<link href="http://www.google.com/" rel="author" title="Google">
|
||||
<link href="https://drafts.csswg.org/css-shadow-parts/" rel="help">
|
||||
</head>
|
||||
<body>
|
||||
<style>
|
||||
#placeholder-i::placeholder { color: green; }
|
||||
</style>
|
||||
<div>
|
||||
The following text should be green:
|
||||
<input id="placeholder-i" part="placeholder-p" placeholder="this text"></input>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CSS Shadow Parts - Interaction with placeholder</title>
|
||||
<!-- This reftest exists because getComputedStyle for
|
||||
::placeholder is not implemented everywhere --!>
|
||||
<meta href="mailto:fergal@chromium.org" rel="author" title="Fergal Daly">
|
||||
<link href="http://www.google.com/" rel="author" title="Google">
|
||||
<link href="https://drafts.csswg.org/css-shadow-parts/" rel="help">
|
||||
<link href="interaction-with-placeholder-ref.html" rel="match">
|
||||
<script src="support/shadow-helper.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<style>
|
||||
#c-e::part(placeholder-p)::placeholder { color: green; }
|
||||
</style>
|
||||
<script>installCustomElement("custom-element", "custom-element-template");</script>
|
||||
<template id="custom-element-template">
|
||||
<style>
|
||||
#placeholder-i::placeholder { color: red; }
|
||||
</style>
|
||||
<div>
|
||||
The following text should be green:
|
||||
<input id="placeholder-i" part="placeholder-p" placeholder="this text"></input>
|
||||
</div>
|
||||
</template>
|
||||
<custom-element id="c-e"></custom-element>
|
||||
</body>
|
||||
</html>
|
|
@ -501,15 +501,18 @@ test(() => {
|
|||
span.shadowRoot.adoptedStyleSheets = [sheet];
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)");
|
||||
|
||||
document.adoptNode(span);
|
||||
assert_equals(span.shadowRoot.adoptedStyleSheets.length, 1);
|
||||
assert_equals(span.shadowRoot.adoptedStyleSheets[0], sheet);
|
||||
|
||||
const iframe = document.createElement("iframe");
|
||||
document.body.appendChild(iframe);
|
||||
iframe.contentDocument.adoptNode(span);
|
||||
iframe.contentDocument.body.appendChild(span);
|
||||
assert_not_equals(span.shadowRoot, null);
|
||||
assert_equals(span.shadowRoot.adoptedStyleSheets.length, 1);
|
||||
assert_equals(span.shadowRoot.adoptedStyleSheets[0], sheet);
|
||||
assert_equals(span.shadowRoot.adoptedStyleSheets.length, 0);
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
|
||||
}, 'Adopting a shadow host will move adoptedStyleSheets but it is not applied');
|
||||
}, 'Adopting a shadow host will empty adoptedStyleSheets if adopting to a different document');
|
||||
|
||||
</script>
|
||||
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
<td>x</td>
|
||||
<td style="width: 100px">y</td>
|
||||
</table>
|
||||
<table border>
|
||||
<tr>
|
||||
<td style="width: 50%">x</td>
|
||||
<td style="width: 100px">y</td>
|
||||
</table>
|
||||
<table border>
|
||||
<tr>
|
||||
<td>x</td>
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
<td style="width: calc(500px)">x</td>
|
||||
<td style="width: 100px">y</td>
|
||||
</table>
|
||||
<table border>
|
||||
<tr>
|
||||
<td style="width: calc(50% + 1px)">x</td>
|
||||
<td style="width: 100px">y</td>
|
||||
</table>
|
||||
<table border>
|
||||
<tr>
|
||||
<td style="width: calc(50%)">x</td>
|
||||
|
|
|
@ -19,6 +19,11 @@ table { table-layout: fixed; width: 500px; border-spacing: 0 }
|
|||
<td>x</td>
|
||||
<td style="width: 100px">y</td>
|
||||
</table>
|
||||
<table border>
|
||||
<tr>
|
||||
<td style="width: 50%">x</td>
|
||||
<td style="width: 100px">y</td>
|
||||
</table>
|
||||
<table border>
|
||||
<tr>
|
||||
<td>x</td>
|
||||
|
|
|
@ -16,6 +16,11 @@ table { table-layout: fixed; width: 500px; border-spacing: 0 }
|
|||
<td style="width: calc(500px)">x</td>
|
||||
<td style="width: 100px">y</td>
|
||||
</table>
|
||||
<table border>
|
||||
<tr>
|
||||
<td style="width: calc(50% + 1px)">x</td>
|
||||
<td style="width: 100px">y</td>
|
||||
</table>
|
||||
<table border>
|
||||
<tr>
|
||||
<td style="width: calc(50%)">x</td>
|
||||
|
|
|
@ -8,7 +8,7 @@ The tests make a number of assumptions of the user agent, and new
|
|||
tests can freely rely on these assumptions being true:
|
||||
|
||||
* The device is a full-color device.
|
||||
* The device has a viewport width of at least 800px.
|
||||
* The device has a viewport width of at least 600px.
|
||||
* The UA imposes no minimum font size.
|
||||
* The `medium` `font-size` computes to 16px.
|
||||
* The canvas background is `white`.
|
||||
|
|
|
@ -90,7 +90,7 @@ headers.
|
|||
### Be Short
|
||||
|
||||
Tests should be as short as possible. For reftests in particular
|
||||
scrollbars at 800×600px window size must be avoided unless scrolling
|
||||
scrollbars at 600×600px window size must be avoided unless scrolling
|
||||
behavior is specifically being tested. For all tests extraneous
|
||||
elements on the page should be avoided so it is clear what is part of
|
||||
the test (for a typical testharness test, the only content on the page
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="author" title="Dom Farolino" href="mailto:dom@chromium.org">
|
||||
<link rel="help" href="https://html.spec.whatwg.org/multipage/links.html#link-type-stylesheet">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
var saw_link_onerror = false;
|
||||
var t = async_test("Check if the stylesheet's error event is fired before the " +
|
||||
"pending parsing-blocking script is unblocked");
|
||||
</script>
|
||||
<link href="nonexistent.css" rel="stylesheet" id="style_test"
|
||||
onload="t.unreached_func('Sheet should fail to load')"
|
||||
onerror="t.step(function() { saw_link_onerror = true; })">
|
||||
<script>
|
||||
t.step(function() {
|
||||
assert_true(saw_link_onerror, "The pending parsing-blocking script should " +
|
||||
"only run after the last element that " +
|
||||
"contributes a script-blocking style " +
|
||||
"sheet's error event is fired if the sheet " +
|
||||
"fails to load.");
|
||||
});
|
||||
t.done();
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
|
@ -11,7 +11,7 @@ window.addEventListener('load', t.step_func_done(function() {
|
|||
}));
|
||||
</script>
|
||||
<link href="style.css?pipe=trickle(d3)" rel="stylesheet" id="style_test"
|
||||
onload="t.step(function() { saw_link_onload = true; });"
|
||||
onerror="t.step(function() { assert_unreached('Sheet should load OK'); });"></link>
|
||||
onload="t.step(function() { saw_link_onload = true; })"
|
||||
onerror="t.unreached_func('Sheet should load OK')">
|
||||
</head>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="author" title="Dom Farolino" href="mailto:dom@chromium.org">
|
||||
<link rel="help" href="https://html.spec.whatwg.org/multipage/links.html#link-type-stylesheet">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
var saw_link_onload = false;
|
||||
var t = async_test("Check if the stylesheet's load event is fired before the " +
|
||||
"pending parsing-blocking script is unblocked");
|
||||
</script>
|
||||
<link href="style.css?pipe=trickle(d3)" rel="stylesheet" id="style_test"
|
||||
onload="t.step(function() { saw_link_onload = true; })"
|
||||
onerror="t.unreached_func('Sheet should load OK')">
|
||||
<script>
|
||||
t.step(function() {
|
||||
assert_true(saw_link_onload, "The pending parsing-blocking script should " +
|
||||
"only run after the last element that " +
|
||||
"contributes a script-blocking style " +
|
||||
"sheet's load event is fired.");
|
||||
});
|
||||
t.done();
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
|
@ -0,0 +1,3 @@
|
|||
body {
|
||||
background-color: gray;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="author" title="Dom Farolino" href="mailto:dom@chromium.org">
|
||||
<link rel="help" href="https://html.spec.whatwg.org/multipage/links.html#link-type-stylesheet">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<link href="style.css?pipe=trickle(d3)" rel="stylesheet" id="style_test">
|
||||
<script>
|
||||
test(function() {
|
||||
assert_true(document.styleSheets.length === 1 &&
|
||||
document.styleSheets[0].href.includes("style.css"),
|
||||
"The style sheet 'style.css' must be available to scripts");
|
||||
|
||||
style_test.href = "resources/neutral.css?pipe=trickle(d3)";
|
||||
|
||||
assert_true(document.styleSheets.length === 1 &&
|
||||
document.styleSheets[0].href.includes("style.css"),
|
||||
"The style sheet 'style.css' must remain accessible to " +
|
||||
"scripts until its replacement has finished loading");
|
||||
}, "Check that a style sheet loaded by a <link> is available until its successor is loaded");
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
|
@ -0,0 +1,2 @@
|
|||
<!doctype html>
|
||||
<p>innerWidth x innerHeight: <span>600x600</span></p>
|
|
@ -0,0 +1,6 @@
|
|||
<!doctype html>
|
||||
<link rel=match href=size-ref.html>
|
||||
<p>innerWidth x innerHeight: <span id=size></span></p>
|
||||
<script>
|
||||
document.querySelector("#size").textContent = window.innerWidth + "x" + window.innerHeight;
|
||||
</script>
|
|
@ -262,7 +262,7 @@ interface SVGSVGElement : SVGGraphicsElement {
|
|||
DOMMatrix createSVGMatrix();
|
||||
DOMRect createSVGRect();
|
||||
SVGTransform createSVGTransform();
|
||||
SVGTransform createSVGTransformFromMatrix(DOMMatrixReadOnly matrix);
|
||||
SVGTransform createSVGTransformFromMatrix(optional DOMMatrix2DInit matrix);
|
||||
|
||||
Element getElementById(DOMString elementId);
|
||||
|
||||
|
@ -367,7 +367,7 @@ interface SVGTransform {
|
|||
[SameObject] readonly attribute DOMMatrix matrix;
|
||||
readonly attribute float angle;
|
||||
|
||||
void setMatrix(DOMMatrixReadOnly matrix);
|
||||
void setMatrix(optional DOMMatrix2DInit matrix);
|
||||
void setTranslate(float tx, float ty);
|
||||
void setScale(float sx, float sy);
|
||||
void setRotate(float angle, float cx, float cy);
|
||||
|
@ -391,7 +391,7 @@ interface SVGTransformList {
|
|||
setter void (unsigned long index, SVGTransform newItem);
|
||||
|
||||
// Additional methods not common to other list interfaces.
|
||||
SVGTransform createSVGTransformFromMatrix(DOMMatrixReadOnly matrix);
|
||||
SVGTransform createSVGTransformFromMatrix(optional DOMMatrix2DInit matrix);
|
||||
SVGTransform? consolidate();
|
||||
};
|
||||
|
||||
|
|
|
@ -164,16 +164,18 @@ function userIsShownErrorsFields(button) {
|
|||
function abortTheUpdate(button) {
|
||||
button.disabled = true;
|
||||
promise_test(async t => {
|
||||
const { response, request } = await getPaymentRequestResponse({ requestShipping: true });
|
||||
// causes "abort the update" to run
|
||||
const shippingChangedPromise = new Promise(resolve => {
|
||||
request.onshippingoptionchange = () => {
|
||||
event.updateWith({ total: { amount: { currency: "USD", value: "INVALID" } }});
|
||||
const { response, request } = await getPaymentRequestResponse({
|
||||
requestShipping: true,
|
||||
});
|
||||
const shipOptionChangePromise = new Promise(resolve => {
|
||||
request.onshippingoptionchange = event => {
|
||||
// causes "abort the update" to run
|
||||
event.updateWith({ total: "error!" });
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
const retryPromise = response.retry();
|
||||
await shippingChangedPromise;
|
||||
await shipOptionChangePromise;
|
||||
await promise_rejects(
|
||||
t,
|
||||
new TypeError(),
|
||||
|
@ -265,7 +267,9 @@ function callingRetryReturnsUniquePromise(button){
|
|||
</li>
|
||||
<li>
|
||||
<p>
|
||||
When shown the payment sheet, hit pay once. Then retry once.
|
||||
When shown the payment sheet, hit pay once.
|
||||
Then, change the shipping option.
|
||||
Select to pay again.
|
||||
</p>
|
||||
<button onclick="abortTheUpdate(this);">
|
||||
When "abort the update" occurs because of an update error,
|
||||
|
|
|
@ -2,16 +2,21 @@
|
|||
<meta charset="utf-8">
|
||||
<title>iframe for xhr tests</title>
|
||||
<script>
|
||||
async function xhr(url) {
|
||||
async function xhr(url, options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
const opts = options ? options : {};
|
||||
xhr.onload = () => {
|
||||
resolve(xhr);
|
||||
};
|
||||
xhr.onerror = () => {
|
||||
reject('xhr failed');
|
||||
};
|
||||
|
||||
xhr.open('GET', url);
|
||||
if (opts.responseType) {
|
||||
xhr.responseType = opts.responseType;
|
||||
}
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue