Update web-platform-tests to revision 74bae78af4b95a2f0ca3a81df9c7fe3143f24bbc

This commit is contained in:
WPT Sync Bot 2019-01-17 20:37:38 -05:00
parent fb95f9df9c
commit 02c1eed999
150 changed files with 2395 additions and 829 deletions

View file

@ -1,4 +1,5 @@
[url-in-tags-revoke.window.html] [url-in-tags-revoke.window.html]
expected: TIMEOUT
[Fetching a blob URL immediately before revoking it works in an iframe.] [Fetching a blob URL immediately before revoking it works in an iframe.]
expected: FAIL expected: FAIL
@ -14,3 +15,6 @@
[Opening a blob URL in a new window by clicking an <a> tag works immediately before revoking the URL.] [Opening a blob URL in a new window by clicking an <a> tag works immediately before revoking the URL.]
expected: FAIL expected: FAIL
[Fetching a blob URL immediately before revoking it works in <script> tags.]
expected: TIMEOUT

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,2 @@
[insert-inline-in-blocks-n-inlines-begin-001.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[insert-inline-in-blocks-n-inlines-begin-003.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[insert-inline-in-blocks-n-inlines-end-001.xht]
expected: FAIL

View file

@ -1,3 +0,0 @@
[insert-inline-in-blocks-n-inlines-end-003.xht]
type: reftest
expected: FAIL

View file

@ -0,0 +1,2 @@
[insert-inline-in-blocks-n-inlines-middle-001.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[insert-inline-in-blocks-n-inlines-middle-003.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[c5525-fltmult-000.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[border-padding-bleed-001.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[border-padding-bleed-002.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[border-padding-bleed-003.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[background-size-028.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[background-size-030.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[flexbox_order-box.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[ttwf-reftest-flex-direction-row-reverse.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[ttwf-reftest-flex-order.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[font-variant-alternates-18.html]
expected: FAIL

View file

@ -257,3 +257,9 @@
[font-weight(valid): Out-of-range simple calc value (should be clamped): calc(1001)] [font-weight(valid): Out-of-range simple calc value (should be clamped): calc(1001)]
expected: FAIL expected: FAIL
[font-style(valid): 'oblique' followed by calc with out of range value (should be clamped): oblique calc(-91deg)]
expected: FAIL
[font-style(valid): 'oblique' followed by calc with out of range value (should be clamped): oblique calc(91deg)]
expected: FAIL

View file

@ -0,0 +1,49 @@
[font-style-parsing.html]
[Font-style (computed): 'oblique' followed by calc is valid even if it must be clamped (with computation)]
expected: FAIL
[Font-style (computed): 'oblique' followed by calc is valid even if it must be clamped (no computation)]
expected: FAIL
[Font-style (computed): 'oblique' followed by minimum -90 degree angle is valid]
expected: FAIL
[Font-style (computed): 'italic' is valid]
expected: FAIL
[Font-style (computed): 'oblique' followed by positive angle in turns is valid]
expected: FAIL
[Font-style (computed): 'oblique' followed by fractional angle is valid]
expected: FAIL
[Font-style (computed): 'oblique' followed by positive angle in degrees is valid]
expected: FAIL
[Font-style (computed): 'oblique' followed by positive angle in gradians is valid]
expected: FAIL
[Font-style (computed): 'oblique' followed by positive angle in radians is valid]
expected: FAIL
[Font-style (computed): 'oblique' followed by zero degrees is valid]
expected: FAIL
[Font-style (computed): 'oblique' followed by calc is valid]
expected: FAIL
[Font-style (computed): 'oblique' followed by calc is valid even if it mixes units (with computation)]
expected: FAIL
[Font-style (computed): 'oblique' followed by positive angle is valid]
expected: FAIL
[Font-style (computed): 'oblique' is valid]
expected: FAIL
[Font-style (computed): 'oblique' followed by maxumum 90 degree angle is valid]
expected: FAIL
[Font-style (computed): 'oblique' followed by negative angle is valid]
expected: FAIL

View file

@ -32,7 +32,7 @@
[single-byte-decoder.html?XMLHttpRequest] [single-byte-decoder.html?XMLHttpRequest]
expected: TIMEOUT expected: CRASH
[ISO-8859-2: iso_8859-2:1987 (XMLHttpRequest)] [ISO-8859-2: iso_8859-2:1987 (XMLHttpRequest)]
expected: FAIL expected: FAIL

View file

@ -312,15 +312,3 @@
[<iframe>: separate response Content-Type: text/plain */*;charset=gbk] [<iframe>: separate response Content-Type: text/plain */*;charset=gbk]
expected: FAIL expected: FAIL
[<iframe>: combined response Content-Type: text/html;" text/plain]
expected: FAIL
[<iframe>: combined response Content-Type: text/html */*]
expected: FAIL
[<iframe>: combined response Content-Type: text/html */*;charset=gbk]
expected: FAIL
[<iframe>: combined response Content-Type: text/html;" \\" text/plain]
expected: FAIL

View file

@ -11,3 +11,6 @@
[X-Content-Type-Options%3A%20nosniff%0C] [X-Content-Type-Options%3A%20nosniff%0C]
expected: FAIL expected: FAIL
[Content-Type-Options%3A%20nosniff]
expected: FAIL

View file

@ -1,4 +1,4 @@
[traverse_the_history_4.html] [traverse_the_history_5.html]
[Multiple history traversals, last would be aborted] [Multiple history traversals, last would be aborted]
expected: FAIL expected: FAIL

View file

@ -0,0 +1,4 @@
[link-error-fired-before-scripting-unblocked.html]
[Check if the stylesheet's error event is fired before the pending parsing-blocking script is unblocked]
expected: FAIL

View file

@ -0,0 +1,4 @@
[link-load-fired-before-scripting-unblocked.html]
[Check if the stylesheet's load event is fired before the pending parsing-blocking script is unblocked]
expected: FAIL

View file

@ -0,0 +1,4 @@
[stylesheet-not-removed-until-next-stylesheet-loads.html]
[Check that a style sheet loaded by a <link> is available until its successor is loaded]
expected: FAIL

View file

@ -1,4 +1,5 @@
[autoplay-hidden.optional.html] [autoplay-hidden.optional.html]
expected: TIMEOUT
[Allow delaying autoplay until video elements become visible] [Allow delaying autoplay until video elements become visible]
expected: FAIL expected: TIMEOUT

View file

@ -0,0 +1,10 @@
[non-active-document.html]
[DOMParser]
expected: FAIL
[createHTMLDocument]
expected: FAIL
[<template>]
expected: FAIL

View file

@ -12,3 +12,6 @@
[Verifies the resolution of entry.startTime is at least 5 microseconds.] [Verifies the resolution of entry.startTime is at least 5 microseconds.]
expected: TIMEOUT expected: TIMEOUT
[Verifies the resolution of performance.now() is at least 5 microseconds.]
expected: FAIL

View file

@ -1,5 +1,4 @@
[realtimeanalyser-fft-scaling.html] [realtimeanalyser-fft-scaling.html]
expected: TIMEOUT
[X 2048-point FFT peak position is not equal to 64. Got 0.] [X 2048-point FFT peak position is not equal to 64. Got 0.]
expected: FAIL expected: FAIL

View file

@ -1,5 +1,4 @@
[import-in-moduleworker.html] [import-in-moduleworker.html]
expected: ERROR
[Base URL in module dedicated workers: import] [Base URL in module dedicated workers: import]
expected: FAIL expected: FAIL

View file

@ -1,5 +1,4 @@
[sharedworker-in-worker.html] [sharedworker-in-worker.html]
expected: ERROR
[Base URL in workers: new SharedWorker()] [Base URL in workers: new SharedWorker()]
expected: FAIL expected: FAIL

View file

@ -0,0 +1,2 @@
[block_formatting_context_with_margin_a.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[inline_block_baseline_a.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[overconstrained_block.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[stacked_layers.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[transform_skew_a.html]
expected: FAIL

View file

@ -3,6 +3,7 @@
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/"> <link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
<script src="/resources/testharness.js"></script> <script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script> <script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<script src="common.js"></script> <script src="common.js"></script>
<style> <style>
@ -47,7 +48,7 @@ async_test(t => {
animation.play(); animation.play();
assert_equals(data, '0.4'); assert_equals(data, '0.4');
waitTwoAnimationFrames(t.step_func_done(() => { waitForAsyncAnimationFrames(1).then(t.step_func_done(() => {
assert_equals(getComputedStyle(target).opacity, '0.5'); assert_equals(getComputedStyle(target).opacity, '0.5');
})); }));
}); });

View file

@ -8,26 +8,25 @@ function registerPassthroughAnimator() {
`); `);
} }
function registerConstantLocalTimeAnimator(localTime) {
return runInAnimationWorklet(`
registerAnimator('constant_time', class {
animate(currentTime, effect) { effect.localTime = ${localTime}; }
});
`);
}
function runInAnimationWorklet(code) { function runInAnimationWorklet(code) {
return CSS.animationWorklet.addModule( return CSS.animationWorklet.addModule(
URL.createObjectURL(new Blob([code], {type: 'text/javascript'})) URL.createObjectURL(new Blob([code], {type: 'text/javascript'}))
); );
} }
function waitForAnimationFrames(count, callback) { function waitForAsyncAnimationFrames(count) {
function rafCallback() { // In Chrome, waiting for N+1 main thread frames guarantees that compositor has produced
if (count <= 0) { // at least N frames.
callback(); // TODO(majidvp): re-evaluate this choice once other browsers have implemented
} else { // AnimationWorklet.
count -= 1; return waitForAnimationFrames(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);
};

View file

@ -6,6 +6,7 @@
background-color: #00ff00; background-color: #00ff00;
} }
</style> </style>
<script src="/web-animations/testcommon.js"></script>
<script src="../common.js"></script> <script src="../common.js"></script>
<script id="iframe_worklet" type="text/worklet"> <script id="iframe_worklet" type="text/worklet">
@ -32,7 +33,7 @@ runInAnimationWorklet(
const effect = new KeyframeEffect(target, [{ opacity: 0 }], { duration: 1000 }); const effect = new KeyframeEffect(target, [{ opacity: 0 }], { duration: 1000 });
const animation = new WorkletAnimation('iframe_animator', effect); const animation = new WorkletAnimation('iframe_animator', effect);
animation.play(); animation.play();
waitTwoAnimationFrames( _ => { waitForAnimationFrames(2).then(_ => {
window.parent.postMessage(getComputedStyle(target).opacity, '*'); window.parent.postMessage(getComputedStyle(target).opacity, '*');
}); });
}); });

View file

@ -3,15 +3,9 @@
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/"> <link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
<script src="/resources/testharness.js"></script> <script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script> <script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<script src="common.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> <script>
// Creates a DOM structure like: // Creates a DOM structure like:
@ -63,15 +57,14 @@ function createAndPlayTestAnimation(elements, timeline_orientation) {
timeRange: 1000, timeRange: 1000,
orientation: timeline_orientation orientation: timeline_orientation
}); });
const animation = new WorkletAnimation('test_animator', effect, timeline); const animation = new WorkletAnimation('passthrough', effect, timeline);
animation.play(); animation.play();
} }
setup(setupAndRegisterTests, {explicit_done: true}); setup(setupAndRegisterTests, {explicit_done: true});
function setupAndRegisterTests() { function setupAndRegisterTests() {
const worklet_code = document.getElementById('worklet_code').textContent; registerPassthroughAnimator().then(() => {
runInAnimationWorklet(worklet_code).then(() => {
// Note that block horizontal-tb is tested implicitly in the basic // Note that block horizontal-tb is tested implicitly in the basic
// ScrollTimeline tests (as it is the default). // ScrollTimeline tests (as it is the default).
async_test( async_test(
@ -104,7 +97,7 @@ function block_vertical_lr(t) {
elements.scroller.scrollWidth - elements.scroller.clientWidth; elements.scroller.scrollWidth - elements.scroller.clientWidth;
elements.scroller.scrollLeft = 0.25 * maxScroll; elements.scroller.scrollLeft = 0.25 * maxScroll;
waitForAnimationFrames(3, t.step_func_done(() => { waitForAsyncAnimationFrames(2).then(t.step_func_done(() => {
assert_equals( assert_equals(
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)'); 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.scrollWidth - elements.scroller.clientWidth;
elements.scroller.scrollLeft = 0.75 * maxScroll; elements.scroller.scrollLeft = 0.75 * maxScroll;
waitForAnimationFrames(3, t.step_func_done(() => { waitForAsyncAnimationFrames(2).then(t.step_func_done(() => {
assert_equals( assert_equals(
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)'); 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.scrollWidth - elements.scroller.clientWidth;
elements.scroller.scrollLeft = 0.75 * maxScroll; elements.scroller.scrollLeft = 0.75 * maxScroll;
waitForAnimationFrames(3, t.step_func_done(() => { waitForAsyncAnimationFrames(2).then(t.step_func_done(() => {
assert_equals( assert_equals(
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)'); 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.scrollHeight - elements.scroller.clientHeight;
elements.scroller.scrollTop = 0.25 * maxScroll; elements.scroller.scrollTop = 0.25 * maxScroll;
waitForAnimationFrames(3, t.step_func_done(() => { waitForAsyncAnimationFrames(2).then(t.step_func_done(() => {
assert_equals( assert_equals(
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)'); 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.scrollHeight - elements.scroller.clientHeight;
elements.scroller.scrollTop = 0.75 * maxScroll; elements.scroller.scrollTop = 0.75 * maxScroll;
waitForAnimationFrames(3, t.step_func_done(() => { waitForAsyncAnimationFrames(2).then(t.step_func_done(() => {
assert_equals( assert_equals(
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)'); getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)');
})); }));

View file

@ -3,6 +3,7 @@
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/"> <link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
<script src="/resources/testharness.js"></script> <script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script> <script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<script src="common.js"></script> <script src="common.js"></script>
<style> <style>
@ -15,33 +16,21 @@
<script> <script>
function CreateTest(target, effect, verify, test_name) { function CreateTest(target, effect, verify, test_name) {
async_test(t => { promise_test(async function() {
runInAnimationWorklet( await registerConstantLocalTimeAnimator(2000);
document.getElementById('simple_animate').textContent const animation = new WorkletAnimation('constant_time', effect);
).then(_ => {
const animation = new WorkletAnimation('test_animator', effect);
animation.play(); animation.play();
waitTwoAnimationFrames(() => { await waitForAsyncAnimationFrames(1);
// waitTwoAnimationFrames guarantees a compositor frame that could update // waitTwoAnimationFrames guarantees a compositor frame that could update
// the opacity value in the worklet. Meanwhile, getComputedStyle needs an // the opacity value in the worklet. Meanwhile, getComputedStyle needs an
// extra frame to fetch the updated value. // extra frame to fetch the updated value.
window.requestAnimationFrame(t.step_func_done(() => { await waitForNextFrame();
verify(); verify();
animation.cancel(); animation.cancel();
}));
});
});
}, test_name); }, test_name);
} }
</script> </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="target1" class='target'></div>
<div id="target2" class='target'></div> <div id="target2" class='target'></div>

View file

@ -3,6 +3,7 @@
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/"> <link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
<script src="/resources/testharness.js"></script> <script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script> <script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<script src="common.js"></script> <script src="common.js"></script>
<style> <style>
@ -17,8 +18,8 @@
<script> <script>
'use strict'; 'use strict';
test(function() { promise_test(async function() {
registerPassthroughAnimator(); await registerPassthroughAnimator();
let playFunc = function() { let playFunc = function() {
let effect = new KeyframeEffect( let effect = new KeyframeEffect(
document.getElementById('target'), document.getElementById('target'),

View file

@ -8,19 +8,22 @@
'use strict'; 'use strict';
const test_desc = 'HeartRate device properties'; const test_desc = 'HeartRate device properties';
bluetooth_test(() => getHealthThermometerService() bluetooth_test(
() => getHealthThermometerService()
.then(({service}) => Promise.all([ .then(({service}) => Promise.all([
service.getCharacteristic('temperature_measurement'), service.getCharacteristic('temperature_measurement'),
service.getCharacteristic('measurement_interval')])) service.getCharacteristic('measurement_interval')
]))
.then(([temperature_measurement, measurement_interval]) => { .then(([temperature_measurement, measurement_interval]) => {
let tm_expected_properties = let tm_expected_properties =
new TestCharacteristicProperties(['indicate']); new TestCharacteristicProperties(['indicate']);
assert_properties_equal(temperature_measurement.properties, assert_properties_equal(
tm_expected_properties); temperature_measurement.properties, tm_expected_properties);
let mi_expected_properties = let mi_expected_properties = new TestCharacteristicProperties(
new TestCharacteristicProperties(['read', 'write', 'indicate']); ['read', 'write', 'indicate']);
assert_properties_equal(measurement_interval.properties, assert_properties_equal(
mi_expected_properties); measurement_interval.properties, mi_expected_properties);
}), test_desc); }),
test_desc);
</script> </script>

View file

@ -8,12 +8,14 @@
'use strict'; 'use strict';
const test_desc = 'Same parent service returned from multiple characteristics.'; const test_desc = 'Same parent service returned from multiple characteristics.';
bluetooth_test(() => getHealthThermometerService() bluetooth_test(
() => getHealthThermometerService()
.then(({service}) => Promise.all([ .then(({service}) => Promise.all([
service.getCharacteristic('measurement_interval'), service.getCharacteristic('measurement_interval'),
service.getCharacteristic('temperature_measurement') service.getCharacteristic('temperature_measurement')
])) ]))
.then(characteristics => .then(
assert_equals(characteristics[0].service, characteristics[1].service)), characteristics => assert_equals(
characteristics[0].service, characteristics[1].service)),
test_desc); test_desc);
</script> </script>

View file

@ -9,8 +9,9 @@
const test_desc = '[SameObject] test for BluetoothRemoteGATTCharacteristic ' + const test_desc = '[SameObject] test for BluetoothRemoteGATTCharacteristic ' +
'service.'; 'service.';
bluetooth_test(() => getMeasurementIntervalCharacteristic() bluetooth_test(
.then(({characteristic}) => () => getMeasurementIntervalCharacteristic().then(
({characteristic}) =>
assert_equals(characteristic.service, characteristic.service)), assert_equals(characteristic.service, characteristic.service)),
test_desc); test_desc);
</script> </script>

View file

@ -7,9 +7,11 @@
const test_desc = 'Bluetooth IDL test'; const test_desc = 'Bluetooth IDL test';
test(() => { test(() => {
assert_throws(new TypeError(), () => new Bluetooth(), assert_throws(
new TypeError(), () => new Bluetooth(),
'the constructor should not be callable with "new"'); 'the constructor should not be callable with "new"');
assert_throws(new TypeError(), () => Bluetooth(), assert_throws(
new TypeError(), () => Bluetooth(),
'the constructor should not be callable'); 'the constructor should not be callable');
// Bluetooth implements BluetoothDiscovery; // Bluetooth implements BluetoothDiscovery;

View file

@ -9,23 +9,28 @@
const test_desc_idl = 'BluetoothDevice IDL test.'; const test_desc_idl = 'BluetoothDevice IDL test.';
test(() => { test(() => {
assert_throws(new TypeError(), () => new BluetoothDevice(), assert_throws(
new TypeError(), () => new BluetoothDevice(),
'the constructor should not be callable with "new"'); 'the constructor should not be callable with "new"');
assert_throws(new TypeError(), () => BluetoothDevice(), assert_throws(
new TypeError(), () => BluetoothDevice(),
'the constructor should not be callable'); 'the constructor should not be callable');
}, test_desc_idl); }, test_desc_idl);
const test_desc_attr = 'BluetoothDevice attributes.'; const test_desc_attr = 'BluetoothDevice attributes.';
let device; let device;
bluetooth_test(() => getConnectedHealthThermometerDevice() bluetooth_test(
.then(({device}) => { () => getConnectedHealthThermometerDevice().then(({device}) => {
assert_equals(device.constructor.name, 'BluetoothDevice'); assert_equals(device.constructor.name, 'BluetoothDevice');
var old_device_id = device.id; var old_device_id = device.id;
assert_throws(new TypeError(), () => device.id = 'overwritten', assert_throws(
new TypeError(), () => device.id = 'overwritten',
'the device id should not be writable'); 'the device id should not be writable');
assert_throws(new TypeError(), () => device.name = 'overwritten', assert_throws(
new TypeError(), () => device.name = 'overwritten',
'the device name should not be writable'); 'the device name should not be writable');
assert_equals(device.id, old_device_id); assert_equals(device.id, old_device_id);
assert_equals(device.name, 'Health Thermometer'); assert_equals(device.name, 'Health Thermometer');
}), test_desc_attr); }),
test_desc_attr);
</script> </script>

View file

@ -19,7 +19,8 @@ test(() => {
assert_equals(BluetoothUUID.getDescriptor(NaN), base_uuid); assert_equals(BluetoothUUID.getDescriptor(NaN), base_uuid);
}, 'NaN returns basic uuid'); }, 'NaN returns basic uuid');
test(() => { test(
() => {
let max_uuid = 'ffffffff-0000-1000-8000-00805f9b34fb'; let max_uuid = 'ffffffff-0000-1000-8000-00805f9b34fb';
let nine_digits = 0xfffffffff; let nine_digits = 0xfffffffff;
let thirteen_digits = 0xfffffffffffff; let thirteen_digits = 0xfffffffffffff;
@ -31,9 +32,11 @@ test(() => {
assert_equals(BluetoothUUID.getCharacteristic(thirteen_digits), max_uuid); assert_equals(BluetoothUUID.getCharacteristic(thirteen_digits), max_uuid);
assert_equals(BluetoothUUID.getDescriptor(thirteen_digits), max_uuid); assert_equals(BluetoothUUID.getDescriptor(thirteen_digits), max_uuid);
assert_equals(BluetoothUUID.getService(fourteen_digits), base_uuid); assert_equals(BluetoothUUID.getService(fourteen_digits), base_uuid);
assert_equals(BluetoothUUID.getCharacteristic(fourteen_digits), base_uuid); assert_equals(
BluetoothUUID.getCharacteristic(fourteen_digits), base_uuid);
assert_equals(BluetoothUUID.getDescriptor(fourteen_digits), base_uuid); assert_equals(BluetoothUUID.getDescriptor(fourteen_digits), base_uuid);
}, 'Values between 0xfffffffff (8 digits) and 0xffffffffffffff (14 digits)' + },
'Values between 0xfffffffff (8 digits) and 0xffffffffffffff (14 digits)' +
'should return max UUID'); 'should return max UUID');
test(() => { test(() => {
@ -54,7 +57,8 @@ test(() => {
let adeadbeef_alias = 0xADEADBEEF; let adeadbeef_alias = 0xADEADBEEF;
let adeadbeef_uuid = 'deadbeef-0000-1000-8000-00805f9b34fb'; let adeadbeef_uuid = 'deadbeef-0000-1000-8000-00805f9b34fb';
assert_equals(BluetoothUUID.getService(adeadbeef_alias), adeadbeef_uuid); 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); assert_equals(BluetoothUUID.getDescriptor(adeadbeef_alias), adeadbeef_uuid);
}, 'Only first 32bits should be used.'); }, 'Only first 32bits should be used.');
@ -68,30 +72,39 @@ test(() => {
test(() => { test(() => {
let all_caps_uuid = '1A2B3C4D-5E6F-7A8B-9C0D-1E2F3A4B5C6D'; let all_caps_uuid = '1A2B3C4D-5E6F-7A8B-9C0D-1E2F3A4B5C6D';
assert_throws(TypeError(), () => BluetoothUUID.getService(all_caps_uuid)); 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)); assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(all_caps_uuid));
}, 'A UUID String with uppercase letters is an invalid UUID.'); }, 'A UUID String with uppercase letters is an invalid UUID.');
test(() => { test(() => {
let string_alias = 'deadbeef'; let string_alias = 'deadbeef';
assert_throws(TypeError(), () => BluetoothUUID.getService(string_alias)); 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)); assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(string_alias));
}, 'A 32bit *String* alias is invalid.'); }, 'A 32bit *String* alias is invalid.');
test(() => { test(() => {
let invalid_character_uuid = '0000000g-0000-1000-8000-00805f9b34fb'; let invalid_character_uuid = '0000000g-0000-1000-8000-00805f9b34fb';
assert_throws(TypeError(), () => BluetoothUUID.getService(invalid_character_uuid)); assert_throws(
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(invalid_character_uuid)); TypeError(), () => BluetoothUUID.getService(invalid_character_uuid));
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(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.'); }, 'A UUID with invalid characters is an invalid UUID.');
test(() => { test(() => {
assert_equals(BluetoothUUID.getService('alert_notification'), assert_equals(
BluetoothUUID.getService('alert_notification'),
'00001811-0000-1000-8000-00805f9b34fb'); '00001811-0000-1000-8000-00805f9b34fb');
assert_equals(BluetoothUUID.getCharacteristic('aerobic_heart_rate_lower_limit'), assert_equals(
BluetoothUUID.getCharacteristic('aerobic_heart_rate_lower_limit'),
'00002a7e-0000-1000-8000-00805f9b34fb'); '00002a7e-0000-1000-8000-00805f9b34fb');
assert_equals(BluetoothUUID.getDescriptor('gatt.characteristic_extended_properties'), assert_equals(
BluetoothUUID.getDescriptor('gatt.characteristic_extended_properties'),
'00002900-0000-1000-8000-00805f9b34fb'); '00002900-0000-1000-8000-00805f9b34fb');
}, 'A valid UUID from a name.'); }, 'A valid UUID from a name.');
@ -136,7 +149,8 @@ test(() => {
assert_throws(new TypeError, () => BluetoothUUID.canonicalUUID(undefined)); assert_throws(new TypeError, () => BluetoothUUID.canonicalUUID(undefined));
assert_equals(BluetoothUUID.canonicalUUID(null), base_uuid); assert_equals(BluetoothUUID.canonicalUUID(null), base_uuid);
assert_equals(BluetoothUUID.canonicalUUID(false), 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)); assert_throws(new TypeError, () => BluetoothUUID.canonicalUUID(NaN));
// getService // getService

View file

@ -6,8 +6,7 @@
const test_desc = '[SameObject] test for navigator.bluetooth'; const test_desc = '[SameObject] test for navigator.bluetooth';
test(() => { test(() => {
assert_true('bluetooth' in navigator, assert_true('bluetooth' in navigator, 'navigator.bluetooth exists.');
'navigator.bluetooth exists.');
}, 'navigator.bluetooth IDL test'); }, 'navigator.bluetooth IDL test');
test(() => { test(() => {

View file

@ -9,7 +9,9 @@
const test_desc = 'Device with empty name and no UUIDs nearby. Should be ' + const test_desc = 'Device with empty name and no UUIDs nearby. Should be ' +
'found if acceptAllDevices is true.'; 'found if acceptAllDevices is true.';
bluetooth_test(() => setUpPreconnectedDevice({name: ''}) bluetooth_test(
() =>
setUpPreconnectedDevice({name: ''})
.then(() => requestDeviceWithTrustedClick({acceptAllDevices: true})) .then(() => requestDeviceWithTrustedClick({acceptAllDevices: true}))
.then(device => assert_equals(device.name, '')), .then(device => assert_equals(device.name, '')),
test_desc); test_desc);

View file

@ -5,11 +5,14 @@
<script src="/resources/testdriver-vendor.js"></script> <script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script> <script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script> <script>
const test_desc = 'A device with name and no UUIDs nearby. Should be found if ' + const test_desc =
'A device with name and no UUIDs nearby. Should be found if ' +
'acceptAllDevices is true.'; 'acceptAllDevices is true.';
const name = 'LE Device'; const name = 'LE Device';
bluetooth_test(() => setUpPreconnectedDevice({name: name}) bluetooth_test(
() =>
setUpPreconnectedDevice({name: name})
.then(() => requestDeviceWithTrustedClick({acceptAllDevices: true})) .then(() => requestDeviceWithTrustedClick({acceptAllDevices: true}))
.then(device => assert_equals(device.name, name)), .then(device => assert_equals(device.name, name)),
test_desc); test_desc);

View file

@ -14,9 +14,10 @@ const expected = new DOMException(
'requestDevice() options. https://goo.gl/HxfxSQ', 'requestDevice() options. https://goo.gl/HxfxSQ',
'SecurityError'); 'SecurityError');
bluetooth_test(() => getConnectedHealthThermometerDevice({acceptAllDevices: true}) bluetooth_test(
.then(({device}) => assert_promise_rejects_with_message( () => getConnectedHealthThermometerDevice({acceptAllDevices: true})
device.gatt.getPrimaryServices(), .then(
expected)), ({device}) => assert_promise_rejects_with_message(
device.gatt.getPrimaryServices(), expected)),
test_desc); test_desc);
</script> </script>

View file

@ -9,7 +9,8 @@
const test_desc = 'requestDevice called with acceptAllDevices: true and with ' + 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() bluetooth_test(
() => getTwoHealthThermometerServicesDevice()
.then(() => requestDeviceWithTrustedClick({ .then(() => requestDeviceWithTrustedClick({
acceptAllDevices: true, acceptAllDevices: true,
optionalServices: ['health_thermometer'] optionalServices: ['health_thermometer']
@ -19,8 +20,10 @@ bluetooth_test(() => getTwoHealthThermometerServicesDevice()
.then(services => { .then(services => {
assert_equals(services.length, 2); assert_equals(services.length, 2);
services.forEach(service => { services.forEach(service => {
assert_equals(service.uuid, assert_equals(
service.uuid,
BluetoothUUID.getService('health_thermometer')); BluetoothUUID.getService('health_thermometer'));
}); });
}), test_desc); }),
test_desc);
</script> </script>

View file

@ -13,13 +13,13 @@ const expected = new DOMException(
'https://goo.gl/4NeimX', 'https://goo.gl/4NeimX',
'SecurityError'); 'SecurityError');
bluetooth_test(() => setUpPreconnectedDevice({ bluetooth_test(
knownServiceUUIDs: ['human_interface_device'] () =>
}) setUpPreconnectedDevice({knownServiceUUIDs: ['human_interface_device']})
.then(() => assert_promise_rejects_with_message( .then(
requestDeviceWithTrustedClick({ () => assert_promise_rejects_with_message(
filters: [{services: ['human_interface_device']}] requestDeviceWithTrustedClick(
}), {filters: [{services: ['human_interface_device']}]}),
expected, 'Requesting blocklisted service rejects.')), expected, 'Requesting blocklisted service rejects.')),
test_desc); test_desc);
</script> </script>

View file

@ -8,19 +8,22 @@
'use strict'; 'use strict';
const test_desc = 'Blocklisted UUID in optionalServices is removed and ' + const test_desc = 'Blocklisted UUID in optionalServices is removed and ' +
'access not granted.'; 'access not granted.';
const expected = new DOMException('Origin is not allowed to access the ' + const expected = new DOMException(
'Origin is not allowed to access the ' +
'service. Tip: Add the service UUID to \'optionalServices\' in ' + 'service. Tip: Add the service UUID to \'optionalServices\' in ' +
'requestDevice() options. https://goo.gl/HxfxSQ', 'requestDevice() options. https://goo.gl/HxfxSQ',
'SecurityError'); 'SecurityError');
let device, fake_peripheral; let device, fake_peripheral;
bluetooth_test(() => getDiscoveredHealthThermometerDevice({ bluetooth_test(
() => getDiscoveredHealthThermometerDevice({
filters: [{services: ['health_thermometer']}], filters: [{services: ['health_thermometer']}],
optionalServices: ['human_interface_device'] optionalServices: ['human_interface_device']
}) })
.then(_ => ({device, fake_peripheral} = _)) .then(_ => ({device, fake_peripheral} = _))
.then(() => .then(
fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS})) () => fake_peripheral.setNextGATTConnectionResponse(
{code: HCI_SUCCESS}))
.then(() => device.gatt.connect()) .then(() => device.gatt.connect())
.then(() => Promise.all([ .then(() => Promise.all([
assert_promise_rejects_with_message( assert_promise_rejects_with_message(
@ -28,6 +31,7 @@ bluetooth_test(() => getDiscoveredHealthThermometerDevice({
expected, 'Blocklisted service not accessible.'), expected, 'Blocklisted service not accessible.'),
assert_promise_rejects_with_message( assert_promise_rejects_with_message(
device.gatt.getPrimaryServices('human_interface_device'), device.gatt.getPrimaryServices('human_interface_device'),
expected, 'Blocklisted services not accessible.')])), expected, 'Blocklisted services not accessible.')
])),
test_desc); test_desc);
</script> </script>

View file

@ -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_' + const DEVICE_NAME = 'a_device_name_that_is_longer_than_29_bytes_but_' +
'shorter_than_248_bytes'; 'shorter_than_248_bytes';
bluetooth_test(() => setUpPreconnectedDevice({name: DEVICE_NAME}) bluetooth_test(
.then(() => requestDeviceWithTrustedClick({ () => setUpPreconnectedDevice({name: DEVICE_NAME})
filters: [{name: DEVICE_NAME}] .then(
})) () => requestDeviceWithTrustedClick(
{filters: [{name: DEVICE_NAME}]}))
.then(device => assert_equals(device.name, DEVICE_NAME)), .then(device => assert_equals(device.name, DEVICE_NAME)),
test_desc); test_desc);
</script> </script>

View file

@ -9,8 +9,8 @@
const test_desc = 'A filter must restrict the devices in some way.'; const test_desc = 'A filter must restrict the devices in some way.';
const expected = new TypeError(); const expected = new TypeError();
bluetooth_test(() => assert_promise_rejects_with_message( bluetooth_test(
requestDeviceWithTrustedClick({filters: [{}]}), () => assert_promise_rejects_with_message(
expected), requestDeviceWithTrustedClick({filters: [{}]}), expected),
test_desc); test_desc);
</script> </script>

View file

@ -7,12 +7,13 @@
<script> <script>
'use strict'; 'use strict';
const test_desc = 'An empty |filters| member should result in a TypeError'; const test_desc = 'An empty |filters| member should result in a TypeError';
const expected = new DOMException('Failed to execute \'requestDevice\' on ' + const expected = new DOMException(
'Failed to execute \'requestDevice\' on ' +
'\'Bluetooth\': \'filters\' member must be non-empty to find any devices.', '\'Bluetooth\': \'filters\' member must be non-empty to find any devices.',
new TypeError()); new TypeError());
bluetooth_test(() => assert_promise_rejects_with_message( bluetooth_test(
requestDeviceWithTrustedClick({filters: []}), () => assert_promise_rejects_with_message(
expected), requestDeviceWithTrustedClick({filters: []}), expected),
test_desc); test_desc);
</script> </script>

View file

@ -9,36 +9,29 @@
const test_desc = 'requestDevice with empty namePrefix. ' + const test_desc = 'requestDevice with empty namePrefix. ' +
'Should reject with TypeError.'; 'Should reject with TypeError.';
const expected = new TypeError(); const expected = new TypeError();
const test_specs = [{ const test_specs = [
filters: [{ namePrefix: ''}] {filters: [{namePrefix: ''}]}, {filters: [{namePrefix: '', name: 'Name'}]},
}, { {filters: [{namePrefix: '', services: ['heart_rate']}]},
filters: [{ namePrefix: '', name: 'Name'}] {filters: [{namePrefix: '', name: 'Name', services: ['heart_rate']}]},
}, { {filters: [{namePrefix: ''}], optionalServices: ['heart_rate']},
filters: [{ namePrefix: '', services: ['heart_rate']}] {filters: [{namePrefix: '', name: 'Name'}], optionalServices: ['heart_rate']},
}, { {
filters: [{ namePrefix: '', name: 'Name', services: ['heart_rate']}] filters: [{namePrefix: '', services: ['heart_rate']}],
}, {
filters: [{ namePrefix: ''}],
optionalServices: ['heart_rate'] optionalServices: ['heart_rate']
}, { },
filters: [{ namePrefix: '', name: 'Name'}], {
filters: [{namePrefix: '', name: 'Name', services: ['heart_rate']}],
optionalServices: ['heart_rate'] optionalServices: ['heart_rate']
}, { }
filters: [{ namePrefix: '', services: ['heart_rate']}], ];
optionalServices: ['heart_rate']
}, {
filters: [{ namePrefix: '', name: 'Name', services: ['heart_rate']}],
optionalServices: ['heart_rate']
}];
bluetooth_test(() => { bluetooth_test(() => {
let test_promises = Promise.resolve(); let test_promises = Promise.resolve();
test_specs.forEach(args => { test_specs.forEach(args => {
test_promises = test_promises test_promises = test_promises.then(
.then(() => assert_promise_rejects_with_message( () => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(args), requestDeviceWithTrustedClick(args), expected));
expected));
}); });
return test_promises; return test_promises;
}, test_desc); }, test_desc);
</script> </script>

View file

@ -11,13 +11,11 @@ const expected = new TypeError();
bluetooth_test(() => { bluetooth_test(() => {
let test_promises = Promise.resolve(); let test_promises = Promise.resolve();
generateRequestDeviceArgsWithServices([]).forEach(args => { generateRequestDeviceArgsWithServices([]).forEach(
test_promises = test_promises.then(() => args => {test_promises = test_promises.then(
assert_promise_rejects_with_message( () => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(args), requestDeviceWithTrustedClick(args), expected,
expected, 'Services member must contain at least one service'))});
'Services member must contain at least one service'))
});
return test_promises; return test_promises;
}, test_desc); }, test_desc);
</script> </script>

View file

@ -6,28 +6,24 @@
<script src="/bluetooth/resources/bluetooth-helpers.js"></script> <script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script> <script>
'use strict'; 'use strict';
const test_desc = "RequestDeviceOptions should have exactly one of " + const test_desc = 'RequestDeviceOptions should have exactly one of ' +
"'filters' or 'acceptAllDevices:true'. Reject with TypeError if not."; '\'filters\' or \'acceptAllDevices:true\'. Reject with TypeError if not.';
const expected = new DOMException( const expected = new DOMException(
"Failed to execute 'requestDevice' on 'Bluetooth': " + 'Failed to execute \'requestDevice\' on \'Bluetooth\': ' +
"Either 'filters' should be present or " + 'Either \'filters\' should be present or ' +
"'acceptAllDevices' should be true, but not both.", '\'acceptAllDevices\' should be true, but not both.',
new TypeError()); new TypeError());
const test_specs = [ const test_specs = [
{}, {}, {optionalServices: ['heart_rate']}, {filters: [], acceptAllDevices: true},
{optionalServices: ['heart_rate']},
{filters: [], acceptAllDevices: true},
{filters: [], acceptAllDevices: true, optionalServices: ['heart_rate']} {filters: [], acceptAllDevices: true, optionalServices: ['heart_rate']}
]; ];
bluetooth_test(() => { bluetooth_test(() => {
let test_promises = Promise.resolve(); let test_promises = Promise.resolve();
test_specs.forEach(args => { test_specs.forEach(
test_promises = test_promises args => {test_promises = test_promises.then(
.then(() => assert_promise_rejects_with_message( () => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(args), requestDeviceWithTrustedClick(args), expected))});
expected))
});
return test_promises; return test_promises;
}, test_desc); }, test_desc);
</script> </script>

View file

@ -9,14 +9,15 @@
const test_desc = 'Unicode string with utf8 representation longer than 248 ' + const test_desc = 'Unicode string with utf8 representation longer than 248 ' +
'bytes in \'name\' must throw TypeError.'; 'bytes in \'name\' must throw TypeError.';
const expected = new DOMException( const expected = new DOMException(
"Failed to execute 'requestDevice' on 'Bluetooth': " + 'Failed to execute \'requestDevice\' on \'Bluetooth\': ' +
"A device name can't be longer than 248 bytes.", 'A device name can\'t be longer than 248 bytes.',
new TypeError()); new TypeError());
// \u2764's UTF-8 respresentation is 3 bytes long. // \u2764's UTF-8 respresentation is 3 bytes long.
// 83 chars * 3 bytes/char = 249 bytes // 83 chars * 3 bytes/char = 249 bytes
const unicode_name = '\u2764'.repeat(83); const unicode_name = '\u2764'.repeat(83);
bluetooth_test(() => assert_promise_rejects_with_message( bluetooth_test(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({filters: [{name: unicode_name}]}), requestDeviceWithTrustedClick({filters: [{name: unicode_name}]}),
expected), expected),
test_desc); test_desc);

View file

@ -8,14 +8,14 @@
'use strict'; 'use strict';
const test_desc = 'A device name longer than 248 must reject.'; const test_desc = 'A device name longer than 248 must reject.';
const expected = new DOMException( const expected = new DOMException(
"Failed to execute 'requestDevice' on 'Bluetooth': A device " + 'Failed to execute \'requestDevice\' on \'Bluetooth\': A device ' +
"name can't be longer than 248 bytes.", 'name can\'t be longer than 248 bytes.',
new TypeError()); new TypeError());
const name_too_long = 'a'.repeat(249); const name_too_long = 'a'.repeat(249);
bluetooth_test(() => assert_promise_rejects_with_message( bluetooth_test(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({filters: [{name: name_too_long}]}), requestDeviceWithTrustedClick({filters: [{name: name_too_long}]}),
expected, expected, 'Device name longer than 248'),
'Device name longer than 248'),
test_desc); test_desc);
</script> </script>

View file

@ -9,14 +9,15 @@
const test_desc = 'Unicode string with utf8 representation longer than 248 ' + const test_desc = 'Unicode string with utf8 representation longer than 248 ' +
'bytes in \'namePrefix\' must throw NotFoundError.'; 'bytes in \'namePrefix\' must throw NotFoundError.';
const expected = new DOMException( const expected = new DOMException(
"Failed to execute 'requestDevice' on 'Bluetooth': " + 'Failed to execute \'requestDevice\' on \'Bluetooth\': ' +
"A device name can't be longer than 248 bytes.", 'A device name can\'t be longer than 248 bytes.',
new TypeError()); new TypeError());
// \u2764's UTF-8 respresentation is 3 bytes long. // \u2764's UTF-8 respresentation is 3 bytes long.
// 83 chars * 3 bytes/char = 249 bytes // 83 chars * 3 bytes/char = 249 bytes
const unicode_name = '\u2764'.repeat(83); const unicode_name = '\u2764'.repeat(83);
bluetooth_test(() => assert_promise_rejects_with_message( bluetooth_test(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({filters: [{namePrefix: unicode_name}]}), requestDeviceWithTrustedClick({filters: [{namePrefix: unicode_name}]}),
expected), expected),
test_desc); test_desc);

View file

@ -8,14 +8,14 @@
'use strict'; 'use strict';
const test_desc = 'A device name prefix longer than 248 must reject.'; const test_desc = 'A device name prefix longer than 248 must reject.';
const expected = new DOMException( const expected = new DOMException(
"Failed to execute 'requestDevice' on 'Bluetooth': A device " + 'Failed to execute \'requestDevice\' on \'Bluetooth\': A device ' +
"name can't be longer than 248 bytes.", 'name can\'t be longer than 248 bytes.',
new TypeError()); new TypeError());
const name_too_long = 'a'.repeat(249); const name_too_long = 'a'.repeat(249);
bluetooth_test(() => assert_promise_rejects_with_message( bluetooth_test(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({filters: [{namePrefix: name_too_long}]}), requestDeviceWithTrustedClick({filters: [{namePrefix: name_too_long}]}),
expected, expected, 'Device name longer than 248'),
'Device name longer than 248'),
test_desc); test_desc);
</script> </script>

View file

@ -11,8 +11,11 @@ const test_desc = 'A unicode device name of 248 bytes is valid.';
// 124 chars * 2 bytes/char = 248 bytes // 124 chars * 2 bytes/char = 248 bytes
const DEVICE_NAME = '\u00A1'.repeat(124); const DEVICE_NAME = '\u00A1'.repeat(124);
bluetooth_test(() => setUpPreconnectedDevice({name: DEVICE_NAME}) bluetooth_test(
.then(() => requestDeviceWithTrustedClick({ filters: [{name: DEVICE_NAME}]})) () => setUpPreconnectedDevice({name: DEVICE_NAME})
.then(
() => requestDeviceWithTrustedClick(
{filters: [{name: DEVICE_NAME}]}))
.then(device => assert_equals(device.name, DEVICE_NAME)), .then(device => assert_equals(device.name, DEVICE_NAME)),
test_desc); test_desc);
</script> </script>

View file

@ -9,8 +9,11 @@
const test_desc = 'A device name of 248 bytes is valid.'; const test_desc = 'A device name of 248 bytes is valid.';
const DEVICE_NAME = 'a'.repeat(248); const DEVICE_NAME = 'a'.repeat(248);
bluetooth_test(() => setUpPreconnectedDevice({name: DEVICE_NAME}) bluetooth_test(
.then(() => requestDeviceWithTrustedClick({ filters: [{name: DEVICE_NAME}]})) () => setUpPreconnectedDevice({name: DEVICE_NAME})
.then(
() => requestDeviceWithTrustedClick(
{filters: [{name: DEVICE_NAME}]}))
.then(device => assert_equals(device.name, DEVICE_NAME)), .then(device => assert_equals(device.name, DEVICE_NAME)),
test_desc); test_desc);
</script> </script>

View file

@ -11,10 +11,11 @@ const test_desc = 'A unicode device namePrefix of 248 bytes is valid.';
// 124 chars * 2 bytes/char = 248 bytes // 124 chars * 2 bytes/char = 248 bytes
const DEVICE_NAME = '\u00A1'.repeat(124); const DEVICE_NAME = '\u00A1'.repeat(124);
bluetooth_test(() => setUpPreconnectedDevice({name: DEVICE_NAME}) bluetooth_test(
.then(() => requestDeviceWithTrustedClick({ () => setUpPreconnectedDevice({name: DEVICE_NAME})
filters: [{namePrefix: DEVICE_NAME}] .then(
})) () => requestDeviceWithTrustedClick(
{filters: [{namePrefix: DEVICE_NAME}]}))
.then(device => assert_equals(device.name, DEVICE_NAME)), .then(device => assert_equals(device.name, DEVICE_NAME)),
test_desc); test_desc);
</script> </script>

View file

@ -9,10 +9,11 @@
const test_desc = 'A device namePrefix of 248 bytes is valid.'; const test_desc = 'A device namePrefix of 248 bytes is valid.';
const DEVICE_NAME = 'a'.repeat(248); const DEVICE_NAME = 'a'.repeat(248);
bluetooth_test(() => setUpPreconnectedDevice({name: DEVICE_NAME}) bluetooth_test(
.then(() => requestDeviceWithTrustedClick({ () => setUpPreconnectedDevice({name: DEVICE_NAME})
filters: [{namePrefix: DEVICE_NAME}] .then(
})) () => requestDeviceWithTrustedClick(
{filters: [{namePrefix: DEVICE_NAME}]}))
.then(device => assert_equals(device.name, DEVICE_NAME)), .then(device => assert_equals(device.name, DEVICE_NAME)),
test_desc); test_desc);
</script> </script>

View file

@ -10,8 +10,8 @@
const test_desc = 'requestDevice() requires an argument.'; const test_desc = 'requestDevice() requires an argument.';
const expected = new TypeError(); const expected = new TypeError();
promise_test(() => assert_promise_rejects_with_message( promise_test(
requestDeviceWithTrustedClick(), () => assert_promise_rejects_with_message(
expected), requestDeviceWithTrustedClick(), expected),
test_desc); test_desc);
</script> </script>

View file

@ -12,10 +12,11 @@ const test_desc = 'A name containing unicode characters whose utf8 length ' +
// 9 chars * 3 bytes/char = 27 bytes // 9 chars * 3 bytes/char = 27 bytes
const valid_unicode_name = '\u2764'.repeat(9); const valid_unicode_name = '\u2764'.repeat(9);
bluetooth_test(() => setUpPreconnectedDevice({name: valid_unicode_name}) bluetooth_test(
.then(() => requestDeviceWithTrustedClick({ () => setUpPreconnectedDevice({name: valid_unicode_name})
filters: [{name: valid_unicode_name}] .then(
})) () => requestDeviceWithTrustedClick(
{filters: [{name: valid_unicode_name}]}))
.then(device => assert_equals(device.name, valid_unicode_name)), .then(device => assert_equals(device.name, valid_unicode_name)),
test_desc); test_desc);
</script> </script>

View file

@ -12,10 +12,11 @@ const test_desc = 'A namePrefix containing unicode characters whose utf8 ' +
// 9 chars * 3 bytes/char = 27 bytes // 9 chars * 3 bytes/char = 27 bytes
const valid_unicode_name = '\u2764'.repeat(9); const valid_unicode_name = '\u2764'.repeat(9);
bluetooth_test(() => setUpPreconnectedDevice({name: valid_unicode_name}) bluetooth_test(
.then(() => requestDeviceWithTrustedClick({ () => setUpPreconnectedDevice({name: valid_unicode_name})
filters: [{namePrefix: valid_unicode_name}] .then(
})) () => requestDeviceWithTrustedClick(
{filters: [{namePrefix: valid_unicode_name}]}))
.then(device => assert_equals(device.name, valid_unicode_name)), .then(device => assert_equals(device.name, valid_unicode_name)),
test_desc); test_desc);
</script> </script>

View file

@ -8,37 +8,34 @@
'use strict'; 'use strict';
const test_desc = 'Invalid optional service must reject the promise.'; const test_desc = 'Invalid optional service must reject the promise.';
const expected = new TypeError(); const expected = new TypeError();
const test_specs = [{ const test_specs = [
{optionalServices: ['wrong_service'], filters: [{services: ['heart_rate']}]},
{
optionalServices: ['wrong_service'], optionalServices: ['wrong_service'],
filters: [{services: ['heart_rate']}] filters: [{services: ['heart_rate'], name: 'Name'}]
}, { },
{
optionalServices: ['wrong_service'], optionalServices: ['wrong_service'],
filters: [{ services: ['heart_rate'], name: 'Name'}] filters: [{services: ['heart_rate'], namePrefix: 'Pre'}]
}, { },
{
optionalServices: ['wrong_service'], optionalServices: ['wrong_service'],
filters: [{ services: ['heart_rate'], namePrefix: 'Pre'}] filters: [{services: ['heart_rate'], name: 'Name', namePrefix: 'Pre'}]
}, { },
{optionalServices: ['wrong_service'], filters: [{name: 'Name'}]}, {
optionalServices: ['wrong_service'], optionalServices: ['wrong_service'],
filters: [{ services: ['heart_rate'], name: 'Name', namePrefix: 'Pre'}] filters: [{name: 'Name', namePrefix: 'Pre'}]
}, { },
optionalServices: ['wrong_service'], {optionalServices: ['wrong_service'], filters: [{namePrefix: 'Pre'}]}
filters: [{ name: 'Name'}] ];
}, {
optionalServices: ['wrong_service'],
filters: [{ name: 'Name', namePrefix: 'Pre'}]
}, {
optionalServices: ['wrong_service'],
filters: [{ namePrefix: 'Pre'}]
}];
bluetooth_test(() => { bluetooth_test(() => {
let test_promises = Promise.resolve(); let test_promises = Promise.resolve();
test_specs.forEach(args => { test_specs.forEach(args => {
test_promises = test_promises = test_promises.then(
test_promises.then(() => assert_promise_rejects_with_message( () => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(args), requestDeviceWithTrustedClick(args), expected));
expected));
}); });
return test_promises; return test_promises;
}, test_desc); }, test_desc);
</script> </script>

View file

@ -12,11 +12,10 @@ const expected = new TypeError();
bluetooth_test(() => { bluetooth_test(() => {
let test_promises = Promise.resolve(); let test_promises = Promise.resolve();
generateRequestDeviceArgsWithServices(['wrong_service']).forEach(args => { generateRequestDeviceArgsWithServices(['wrong_service']).forEach(args => {
test_promises = test_promises.then(() => test_promises = test_promises.then(
assert_promise_rejects_with_message( () => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(args), requestDeviceWithTrustedClick(args), expected));
expected));
}); });
return test_promises; return test_promises;
}, test_desc); }, test_desc);
</script> </script>

View file

@ -13,7 +13,8 @@ const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
'/bluetooth/resources/health-thermometer-iframe.html' '/bluetooth/resources/health-thermometer-iframe.html'
let iframe = document.createElement('iframe'); let iframe = document.createElement('iframe');
bluetooth_test(() => setUpHealthThermometerDevice() bluetooth_test(
() => setUpHealthThermometerDevice()
// 1. Load the iframe. // 1. Load the iframe.
.then(() => new Promise(resolve => { .then(() => new Promise(resolve => {
iframe.src = cross_origin_src; iframe.src = cross_origin_src;
@ -23,16 +24,18 @@ bluetooth_test(() => setUpHealthThermometerDevice()
// 2. Request the device from the iframe. // 2. Request the device from the iframe.
.then(() => new Promise(resolve => { .then(() => new Promise(resolve => {
callWithTrustedClick(() => { callWithTrustedClick(() => {
iframe.contentWindow.postMessage({ iframe.contentWindow.postMessage(
type: 'RequestDevice' {type: 'RequestDevice'}, '*');
}, '*');
}); });
window.onmessage = messageEvent => { window.onmessage = messageEvent => {
assert_equals(messageEvent.data, 'SecurityError: requestDevice() ' + assert_equals(
messageEvent.data,
'SecurityError: requestDevice() ' +
'called from cross-origin iframe.'); 'called from cross-origin iframe.');
resolve(); resolve();
} }
})), test_desc); })),
test_desc);
</script> </script>
</body> </body>

View file

@ -8,21 +8,28 @@
'use strict'; 'use strict';
const test_desc = 'Discover a device using alias, name, or UUID.'; const test_desc = 'Discover a device using alias, name, or UUID.';
bluetooth_test(() => getConnectedHealthThermometerDevice() bluetooth_test(
// Chrome will always close the previous chooser in the process of handling () => getConnectedHealthThermometerDevice()
// a user gesture for the next request, so these need to be done // Chrome will always close the previous chooser in the process of
// sequentially. // handling a user gesture for the next request, so these need to
.then(() => requestDeviceWithTrustedClick({ // be done sequentially.
filters: [{services: [health_thermometer.alias]}] .then(
})) () => requestDeviceWithTrustedClick(
.then(device => assert_equals(device.constructor.name, 'BluetoothDevice')) {filters: [{services: [health_thermometer.alias]}]}))
.then(() => requestDeviceWithTrustedClick({ .then(
filters: [{services: [health_thermometer.name]}] device =>
})) assert_equals(device.constructor.name, 'BluetoothDevice'))
.then(device => assert_equals(device.constructor.name, 'BluetoothDevice')) .then(
.then(() => requestDeviceWithTrustedClick({ () => requestDeviceWithTrustedClick(
filters: [{services: [health_thermometer.uuid]}] {filters: [{services: [health_thermometer.name]}]}))
})) .then(
.then(device => assert_equals(device.constructor.name, 'BluetoothDevice')), device =>
assert_equals(device.constructor.name, 'BluetoothDevice'))
.then(
() => requestDeviceWithTrustedClick(
{filters: [{services: [health_thermometer.uuid]}]}))
.then(
device => assert_equals(
device.constructor.name, 'BluetoothDevice')),
test_desc); test_desc);
</script> </script>

View file

@ -8,17 +8,21 @@
'use strict'; 'use strict';
const test_desc = 'requestDevice calls do not consume user gestures.'; const test_desc = 'requestDevice calls do not consume user gestures.';
bluetooth_test(() => setUpHealthThermometerAndHeartRateDevices() bluetooth_test(
.then(() => callWithTrustedClick(() => { () => setUpHealthThermometerAndHeartRateDevices().then(
let first = navigator.bluetooth.requestDevice({ () => callWithTrustedClick(() => {
filters: [{services: ['heart_rate']}]}); let first = navigator.bluetooth.requestDevice(
let second = navigator.bluetooth.requestDevice({ {filters: [{services: ['heart_rate']}]});
filters: [{services: ['heart_rate']}]}); let second = navigator.bluetooth.requestDevice(
{filters: [{services: ['heart_rate']}]});
return Promise.all([ return Promise.all([
first.then(device => assert_equals( first.then(
device.constructor.name, 'BluetoothDevice')), device =>
second.then(device => assert_equals( assert_equals(device.constructor.name, 'BluetoothDevice')),
device.constructor.name, 'BluetoothDevice')), second.then(
device =>
assert_equals(device.constructor.name, 'BluetoothDevice')),
]); ]);
})), test_desc); })),
test_desc);
</script> </script>

View file

@ -11,50 +11,47 @@ let matching_services = [health_thermometer.uuid];
let matching_name = 'Health Thermometer'; let matching_name = 'Health Thermometer';
let matching_namePrefix = 'Health'; let matching_namePrefix = 'Health';
let test_specs = [{ let test_specs = [
{
filters: [{ filters: [{
services: matching_services, services: matching_services,
}] }]
}, { },
{
filters: [{ filters: [{
services: matching_services, services: matching_services,
name: matching_name, name: matching_name,
}] }]
}, { },
filters: [{ {filters: [{services: matching_services, namePrefix: matching_namePrefix}]}, {
services: matching_services,
namePrefix: matching_namePrefix
}]
}, {
filters: [{ filters: [{
name: matching_name, name: matching_name,
}], }],
optionalServices: matching_services optionalServices: matching_services
}, { },
filters: [{ {
name: matching_name, filters: [{name: matching_name, namePrefix: matching_namePrefix}],
namePrefix: matching_namePrefix
}],
optionalServices: matching_services optionalServices: matching_services
}, { },
filters: [{ {
namePrefix: matching_namePrefix filters: [{namePrefix: matching_namePrefix}],
}],
optionalServices: matching_services optionalServices: matching_services
}, { },
{
filters: [{ filters: [{
services: matching_services, services: matching_services,
name: matching_name, name: matching_name,
namePrefix: matching_namePrefix namePrefix: matching_namePrefix
}] }]
}]; }
];
bluetooth_test(() => setUpHealthThermometerDevice() bluetooth_test(
.then(() => { () => setUpHealthThermometerDevice().then(() => {
let test_promises = Promise.resolve(); let test_promises = Promise.resolve();
test_specs.forEach(args => { test_specs.forEach(args => {
test_promises = test_promises test_promises =
.then(() => requestDeviceWithTrustedClick(args)) test_promises.then(() => requestDeviceWithTrustedClick(args))
.then(device => { .then(device => {
// We always have access to the services in matching_services // We always have access to the services in matching_services
// because we include them in a filter or in optionalServices. // because we include them in a filter or in optionalServices.
@ -63,5 +60,6 @@ bluetooth_test(() => setUpHealthThermometerDevice()
}); });
}); });
return test_promises; return test_promises;
}), test_desc); }),
test_desc);
</script> </script>

View file

@ -7,12 +7,13 @@
<script> <script>
'use strict'; 'use strict';
const test_desc = 'Reject with NotFoundError if Bluetooth is not supported.'; const test_desc = 'Reject with NotFoundError if Bluetooth is not supported.';
const expected = new DOMException('Bluetooth Low Energy not available.', const expected =
'NotFoundError'); new DOMException('Bluetooth Low Energy not available.', 'NotFoundError');
bluetooth_test(() => navigator.bluetooth.test.setLESupported(false) bluetooth_test(
.then(() => assert_promise_rejects_with_message( () => navigator.bluetooth.test.setLESupported(false).then(
requestDeviceWithTrustedClick({acceptAllDevices: true}), () => assert_promise_rejects_with_message(
expected, 'Bluetooth Low Energy is not supported.')), requestDeviceWithTrustedClick({acceptAllDevices: true}), expected,
'Bluetooth Low Energy is not supported.')),
test_desc); test_desc);
</script> </script>

View file

@ -8,7 +8,9 @@
'use strict'; 'use strict';
const test_desc = 'An empty name device can be obtained by empty name filter.' const test_desc = 'An empty name device can be obtained by empty name filter.'
bluetooth_test(() => setUpPreconnectedDevice({name: ''}) bluetooth_test(
() =>
setUpPreconnectedDevice({name: ''})
.then(() => requestDeviceWithTrustedClick({filters: [{name: ''}]})) .then(() => requestDeviceWithTrustedClick({filters: [{name: ''}]}))
.then(device => assert_equals(device.name, '')), .then(device => assert_equals(device.name, '')),
test_desc); test_desc);

View file

@ -11,9 +11,11 @@ const expected = new DOMException(
'Must be handling a user gesture to show a permission request.', 'Must be handling a user gesture to show a permission request.',
'SecurityError'); 'SecurityError');
bluetooth_test(() => setUpHealthThermometerAndHeartRateDevices() bluetooth_test(
.then(() => assert_promise_rejects_with_message( () => setUpHealthThermometerAndHeartRateDevices().then(
navigator.bluetooth.requestDevice({filters:[{services:['heart_rate']}]}), () => assert_promise_rejects_with_message(
navigator.bluetooth.requestDevice(
{filters: [{services: ['heart_rate']}]}),
expected, 'User gesture is required')), expected, 'User gesture is required')),
test_desc); test_desc);
</script> </script>

View file

@ -7,14 +7,15 @@
<script> <script>
'use strict'; 'use strict';
const test_desc = 'Reject with NotFoundError if there is no BT radio present.'; const test_desc = 'Reject with NotFoundError if there is no BT radio present.';
const expected = new DOMException('Bluetooth adapter not available.', const expected =
'NotFoundError'); new DOMException('Bluetooth adapter not available.', 'NotFoundError');
bluetooth_test(() => navigator.bluetooth.test.simulateCentral({state: 'absent'}) bluetooth_test(
.then(() => assert_promise_rejects_with_message( () => navigator.bluetooth.test.simulateCentral({state: 'absent'})
requestDeviceWithTrustedClick({ .then(
filters: [{services: ['generic_access']}] () => assert_promise_rejects_with_message(
}), requestDeviceWithTrustedClick(
{filters: [{services: ['generic_access']}]}),
expected, 'Bluetooth adapter is not present.')), expected, 'Bluetooth adapter is not present.')),
test_desc); test_desc);
</script> </script>

View file

@ -12,22 +12,25 @@ for (let i = 0; i < 5; i++) {
iframes.push(document.createElement('iframe')); iframes.push(document.createElement('iframe'));
} }
bluetooth_test(() => setUpHealthThermometerAndHeartRateDevices() bluetooth_test(
() => setUpHealthThermometerAndHeartRateDevices()
// 1. Load the iframes. // 1. Load the iframes.
.then(() => { .then(() => {
let promises = []; let promises = [];
for (let iframe of iframes) { for (let iframe of iframes) {
iframe.src = '/bluetooth/resources/health-thermometer-iframe.html'; iframe.src =
'/bluetooth/resources/health-thermometer-iframe.html';
document.body.appendChild(iframe); document.body.appendChild(iframe);
promises.push(new Promise(resolve => promises.push(new Promise(
iframe.addEventListener('load', resolve))); resolve => iframe.addEventListener('load', resolve)));
} }
return Promise.all(promises); return Promise.all(promises);
}) })
// 2. Request the device from the iframes. // 2. Request the device from the iframes.
.then(() => new Promise(async (resolve) => { .then(() => new Promise(async (resolve) => {
let numMessages = 0; let numMessages = 0;
window.onmessage = messageEvent => { window.onmessage =
messageEvent => {
assert_equals(messageEvent.data, 'Success'); assert_equals(messageEvent.data, 'Success');
if (++numMessages === iframes.length) { if (++numMessages === iframes.length) {
resolve(); resolve();
@ -35,9 +38,10 @@ bluetooth_test(() => setUpHealthThermometerAndHeartRateDevices()
} }
for (let iframe of iframes) { for (let iframe of iframes) {
await callWithTrustedClick(() => iframe.contentWindow.postMessage({ await callWithTrustedClick(
type: 'RequestDevice' () => iframe.contentWindow.postMessage(
}, '*')); {type: 'RequestDevice'}, '*'));
} }
})), test_desc); })),
test_desc);
</script> </script>

View file

@ -14,26 +14,28 @@ const expected = 'SecurityError: requestDevice() called from cross-origin ' +
let iframe = document.createElement('iframe'); let iframe = document.createElement('iframe');
bluetooth_test(() => getConnectedHealthThermometerDevice() bluetooth_test(
() => getConnectedHealthThermometerDevice()
// 1. Load the iframe. // 1. Load the iframe.
.then(() => new Promise(resolve => { .then(() => new Promise(resolve => {
iframe.sandbox.add('allow-scripts'); iframe.sandbox.add('allow-scripts');
iframe.src = '/bluetooth/resources/health-thermometer-iframe.html'; iframe.src =
'/bluetooth/resources/health-thermometer-iframe.html';
document.body.appendChild(iframe); document.body.appendChild(iframe);
iframe.addEventListener('load', resolve); iframe.addEventListener('load', resolve);
})) }))
// 2. Request the device from the iframe. // 2. Request the device from the iframe.
.then(() => new Promise(resolve => { .then(() => new Promise(resolve => {
callWithTrustedClick(() => { callWithTrustedClick(() => {
iframe.contentWindow.postMessage({ iframe.contentWindow.postMessage(
type: 'RequestDevice' {type: 'RequestDevice'}, '*');
}, '*');
}); });
window.onmessage = messageEvent => { window.onmessage = messageEvent => {
assert_equals(messageEvent.data, expected); assert_equals(messageEvent.data, expected);
resolve(); resolve();
} }
})), test_desc); })),
test_desc);
</script> </script>
</body> </body>

View file

@ -10,21 +10,23 @@ const test_desc = 'Returned device should always be the same.';
let devices = []; let devices = [];
let push = device => devices.push(device); let push = device => devices.push(device);
bluetooth_test(() => setUpHealthThermometerAndHeartRateDevices() bluetooth_test(
.then(() => requestDeviceWithTrustedClick({ () => setUpHealthThermometerAndHeartRateDevices()
filters: [{services: [heart_rate.alias]}] .then(
})) () => requestDeviceWithTrustedClick(
{filters: [{services: [heart_rate.alias]}]}))
.then(push) .then(push)
.then(() => requestDeviceWithTrustedClick({ .then(
filters: [{services: [heart_rate.name]}] () => requestDeviceWithTrustedClick(
})) {filters: [{services: [heart_rate.name]}]}))
.then(push) .then(push)
.then(() => requestDeviceWithTrustedClick({ .then(
filters: [{services: [heart_rate.uuid]}] () => requestDeviceWithTrustedClick(
})) {filters: [{services: [heart_rate.uuid]}]}))
.then(push) .then(push)
.then(() => { .then(() => {
assert_equals(devices[0], devices[1]); assert_equals(devices[0], devices[1]);
assert_equals(devices[1], devices[2]); assert_equals(devices[1], devices[2]);
}), test_desc); }),
test_desc);
</script> </script>

View file

@ -8,10 +8,11 @@
'use strict'; 'use strict';
const test_desc = 'Simple filter selects matching device.'; const test_desc = 'Simple filter selects matching device.';
bluetooth_test(() => setUpHealthThermometerAndHeartRateDevices() bluetooth_test(
.then(() => requestDeviceWithTrustedClick({ () => setUpHealthThermometerAndHeartRateDevices()
filters: [{services: ['health_thermometer']}] .then(
})) () => requestDeviceWithTrustedClick(
{filters: [{services: ['health_thermometer']}]}))
.then(device => assert_equals(device.name, 'Health Thermometer')), .then(device => assert_equals(device.name, 'Health Thermometer')),
test_desc); test_desc);
</script> </script>

View file

@ -3,24 +3,24 @@
let device, gatt; let device, gatt;
function requestDeviceWithOptionsAndConnect(options) { function requestDeviceWithOptionsAndConnect(options) {
return navigator.bluetooth.requestDevice(options) return navigator.bluetooth.requestDevice(options).then(
.then(device => device.gatt.connect()); device => device.gatt.connect());
} }
window.addEventListener('message', (messageEvent) => { window.addEventListener('message', (messageEvent) => {
switch (messageEvent.data.type) { switch (messageEvent.data.type) {
case 'RequestDevice': case 'RequestDevice':
navigator.bluetooth.requestDevice({ navigator.bluetooth
filters: [{services: ['generic_access']}] .requestDevice({filters: [{services: ['generic_access']}]})
})
.then(device => { .then(device => {
if (device.constructor.name === 'BluetoothDevice') { if (device.constructor.name === 'BluetoothDevice') {
parent.postMessage('Success', '*'); parent.postMessage('Success', '*');
} else { } else {
parent.postMessage( parent.postMessage(
`FAIL: requestDevice in iframe returned ${device.name}`, '*'); `FAIL: requestDevice in iframe returned ${device.name}`, '*');
}}).catch(err => parent.postMessage(`${err.name}: ${err.message}`, }
'*')); })
.catch(err => parent.postMessage(`${err.name}: ${err.message}`, '*'));
break; break;
case 'RequestAndConnect': case 'RequestAndConnect':
requestDeviceWithOptionsAndConnect(messageEvent.data.options) requestDeviceWithOptionsAndConnect(messageEvent.data.options)
@ -28,7 +28,8 @@ window.addEventListener('message', (messageEvent) => {
gatt = _; gatt = _;
device = gatt.device; device = gatt.device;
parent.postMessage('Connected', '*'); parent.postMessage('Connected', '*');
}).catch(err => { })
.catch(err => {
parent.postMessage(`FAIL: ${err}`, '*'); parent.postMessage(`FAIL: ${err}`, '*');
}); });
break; break;
@ -50,8 +51,8 @@ window.addEventListener('message', (messageEvent) => {
.catch(err => parent.postMessage(`FAIL: ${err}`, '*')); .catch(err => parent.postMessage(`FAIL: ${err}`, '*'));
break; break;
default: default:
parent.postMessage(`FAIL: Bad message type: ${messageEvent.data.type}`, parent.postMessage(
'*'); `FAIL: Bad message type: ${messageEvent.data.type}`, '*');
} }
}); });
</script> </script>

View file

@ -9,10 +9,12 @@
const test_desc = '[SameObject] test for BluetoothRemoteGATTServer\'s device.'; const test_desc = '[SameObject] test for BluetoothRemoteGATTServer\'s device.';
let device, fake_peripheral; let device, fake_peripheral;
bluetooth_test(() => getDiscoveredHealthThermometerDevice() bluetooth_test(
() => getDiscoveredHealthThermometerDevice()
.then(_ => ({device, fake_peripheral} = _)) .then(_ => ({device, fake_peripheral} = _))
.then(() => .then(
fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS})) () => fake_peripheral.setNextGATTConnectionResponse(
{code: HCI_SUCCESS}))
.then(() => device.gatt.connect()) .then(() => device.gatt.connect())
.then(gatt => assert_equals(gatt.device, gatt.device)), .then(gatt => assert_equals(gatt.device, gatt.device)),
test_desc); test_desc);

View file

@ -8,11 +8,14 @@
'use strict'; 'use strict';
const test_desc = 'Same parent device returned from multiple services.'; const test_desc = 'Same parent device returned from multiple services.';
bluetooth_test(() => getTwoHealthThermometerServicesDevice({ bluetooth_test(
filters: [{services: ['health_thermometer']}] () => getTwoHealthThermometerServicesDevice(
}) {filters: [{services: ['health_thermometer']}]})
.then(({device}) => device.gatt.getPrimaryServices('health_thermometer')) .then(
.then(([service1, service2]) => ({device}) =>
device.gatt.getPrimaryServices('health_thermometer'))
.then(
([service1, service2]) =>
assert_equals(service1.device, service2.device)), assert_equals(service1.device, service2.device)),
test_desc); test_desc);
</script> </script>

View file

@ -8,10 +8,12 @@
'use strict'; 'use strict';
const test_desc = '[SameObject] test for BluetoothRemoteGATTService device.'; const test_desc = '[SameObject] test for BluetoothRemoteGATTService device.';
bluetooth_test(() => getHealthThermometerDevice({ bluetooth_test(
filters: [{services: ['health_thermometer']}] () => getHealthThermometerDevice(
}) {filters: [{services: ['health_thermometer']}]})
.then(({device}) => device.gatt.getPrimaryService('health_thermometer')) .then(
({device}) =>
device.gatt.getPrimaryService('health_thermometer'))
.then(service => assert_equals(service.device, service.device)), .then(service => assert_equals(service.device, service.device)),
test_desc); test_desc);
</script> </script>

View file

@ -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>

View file

@ -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

View file

@ -147,6 +147,8 @@
{ value: "oblique 20deg", isValid: true, expectedValue: "oblique", description: "'oblique' followed by default 20deg angle" }, { 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 maxumum 90 degree angle" },
{ value: "oblique -90deg", isValid: true, description: "'oblique' followed by minimum -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 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 20", isValid: false, description: "'oblique' followed by unit-less number" },
{ value: "oblique 20px", isValid: false, description: "'oblique' followed by non-angle" }, { value: "oblique 20px", isValid: false, description: "'oblique' followed by non-angle" },

View file

@ -7,9 +7,8 @@
<script src="/resources/testharnessreport.js"></script> <script src="/resources/testharnessreport.js"></script>
</head> </head>
<body> <body>
<div id="test"></div>
<script> <script>
var testFontStyle = [ var testFontStyle = [
{ style: "italic", expectedResult: true, message: "'italic' is valid" }, { style: "italic", expectedResult: true, message: "'italic' is valid" },
{ style: "italic 20deg", expectedResult: false, message: "'italic' followed by angle is invalid" }, { style: "italic 20deg", expectedResult: false, message: "'italic' followed by angle is invalid" },
@ -17,33 +16,45 @@
{ style: "oblique", expectedResult: true, message: "'oblique' is valid" }, { style: "oblique", expectedResult: true, message: "'oblique' is valid" },
{ style: "oblique 0deg", expectedResult: true, message: "'oblique' followed by zero degrees 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 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 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" }, { 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" }, { 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 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 -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 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 maxumum 90 degree angle is valid" },
{ style: "oblique -90deg", expectedResult: true, message: "'oblique' followed by minimum -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 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 -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 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 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 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 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 -", 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 - 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 -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(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)" }, { 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)" }, { 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(0.1rad + 1deg)", expectedResult: true, message: "'oblique' followed by calc is valid even if it mixes units (with computation)" } { 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) { 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> </script>
</body> </body>
</html> </html>

View file

@ -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>

View file

@ -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>

Some files were not shown because too many files have changed in this diff Show more