diff options
Diffstat (limited to 'testing/web-platform/tests/bluetooth/requestDevice')
49 files changed, 1221 insertions, 0 deletions
diff --git a/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.https.window.js new file mode 100644 index 0000000000..15bde6a933 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.https.window.js @@ -0,0 +1,19 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'Device with empty name and no UUIDs nearby. Should be ' + + 'found if acceptAllDevices is true.'; + +bluetooth_test(async () => { + let { device } = await setUpPreconnectedFakeDevice({ + fakeDeviceOptions: { + name: '' + }, + requestDeviceOptions: { + acceptAllDevices: true + } + }); + assert_equals(device.name, ''); +}, test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/device-with-name.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/device-with-name.https.window.js new file mode 100644 index 0000000000..f3373a6bb6 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/device-with-name.https.window.js @@ -0,0 +1,20 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +const test_desc = + 'A device with name and no UUIDs nearby. Should be found if ' + + 'acceptAllDevices is true.'; +const name = 'LE Device'; + +bluetooth_test(async () => { + let { device } = await setUpPreconnectedFakeDevice({ + fakeDeviceOptions: { + name: name + }, + requestDeviceOptions: { + acceptAllDevices: true + } + }); + assert_equals(device.name, name); +}, test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/optional-services-missing.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/optional-services-missing.https.window.js new file mode 100644 index 0000000000..5226a645a8 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/optional-services-missing.https.window.js @@ -0,0 +1,21 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +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', + 'SecurityError'); + +bluetooth_test( + async () => { + let { device } = await getConnectedHealthThermometerDevice( + { acceptAllDevices: true }); + assert_promise_rejects_with_message( + device.gatt.getPrimaryServices(), expected); + }, + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/optional-services-present.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/optional-services-present.https.window.js new file mode 100644 index 0000000000..7c200d03f1 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/optional-services-present.https.window.js @@ -0,0 +1,25 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'requestDevice called with acceptAllDevices: true and with ' + + 'optionalServices. Should get access to services.'; + +bluetooth_test( + async () => { + await getTwoHealthThermometerServicesDevice() + let device = await requestDeviceWithTrustedClick({ + acceptAllDevices: true, + optionalServices: ['health_thermometer'] + }); + let gattServer = await device.gatt.connect(); + let services = await gattServer.getPrimaryServices(); + assert_equals(services.length, 2); + services.forEach(service => { + assert_equals( + service.uuid, + BluetoothUUID.getService('health_thermometer')); + }); + }, + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/blocklisted-manufacturer-data-in-filter.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/blocklisted-manufacturer-data-in-filter.https.window.js new file mode 100644 index 0000000000..2dae7f4cc6 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/blocklisted-manufacturer-data-in-filter.https.window.js @@ -0,0 +1,29 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'Reject with SecurityError if requesting a blocklisted ' + + 'manufacturer data.'; + +const expected = new DOMException( + 'requestDevice() called with a filter containing a blocklisted UUID ' + + 'or manufacturer data. https://goo.gl/4NeimX', + 'SecurityError'); + +bluetooth_test(async () => { + await assert_promise_rejects_with_message( + setUpPreconnectedFakeDevice({ + fakeDeviceOptions: {knownServiceUUIDs: ['heart_rate']}, + requestDeviceOptions: { + filters: [{ + services: ['heart_rate'], + manufacturerData: [{ + companyIdentifier: blocklistedManufacturerId, + dataPrefix: blocklistedManufacturerData, + }], + }] + } + }), + expected, 'Requesting blocklisted service rejects.'); +}, test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/blocklisted-service-in-filter.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/blocklisted-service-in-filter.https.window.js new file mode 100644 index 0000000000..80eaf14447 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/blocklisted-service-in-filter.https.window.js @@ -0,0 +1,21 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'Reject with SecurityError if requesting a blocklisted ' + + 'service.'; +const expected = new DOMException( + 'requestDevice() called with a filter containing a blocklisted UUID ' + + 'or manufacturer data. https://goo.gl/4NeimX', + 'SecurityError'); + +bluetooth_test(async () => { + await assert_promise_rejects_with_message( + setUpPreconnectedFakeDevice({ + fakeDeviceOptions: {knownServiceUUIDs: ['human_interface_device']}, + requestDeviceOptions: + {filters: [{services: ['human_interface_device']}]} + }), + expected, 'Requesting blocklisted service rejects.'); +}, test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/blocklisted-service-in-optionalServices.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/blocklisted-service-in-optionalServices.https.window.js new file mode 100644 index 0000000000..4c01974e55 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/blocklisted-service-in-optionalServices.https.window.js @@ -0,0 +1,29 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'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', + 'SecurityError'); + +bluetooth_test(async () => { + let {device, fake_peripheral} = await getDiscoveredHealthThermometerDevice({ + filters: [{services: ['health_thermometer']}], + optionalServices: ['human_interface_device'] + }); + await fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS}); + await device.gatt.connect(); + 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); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/data-prefix-and-mask-size.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/data-prefix-and-mask-size.https.window.js new file mode 100644 index 0000000000..fa2645093a --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/data-prefix-and-mask-size.https.window.js @@ -0,0 +1,22 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = + 'Manufacturer data mask size must be equal to dataPrefix size.'; + +bluetooth_test(async (t) => { + const companyIdentifier = 0x0001; + const dataPrefix = new Uint8Array([0x01, 0x02, 0x03, 0x04]); + const mask = new Uint8Array([0xff]); + + await promise_rejects_js( + t, TypeError, + requestDeviceWithTrustedClick( + {filters: [{manufacturerData: [{companyIdentifier, mask}]}]})); + await promise_rejects_js( + t, TypeError, requestDeviceWithTrustedClick({ + filters: [{manufacturerData: [{companyIdentifier, dataPrefix, mask}]}] + })); +}, test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/dataPrefix-buffer-is-detached.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/dataPrefix-buffer-is-detached.https.window.js new file mode 100644 index 0000000000..936ca4735c --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/dataPrefix-buffer-is-detached.https.window.js @@ -0,0 +1,33 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'dataPrefix value buffer must not be detached'; + +function detachBuffer(buffer) { + window.postMessage('', '*', [buffer]); +} + +bluetooth_test(async (t) => { + const companyIdentifier = 0x0001; + + const typed_array = Uint8Array.of(1, 2); + detachBuffer(typed_array.buffer); + + await promise_rejects_dom( + t, 'InvalidStateError', requestDeviceWithTrustedClick({ + filters: + [{manufacturerData: [{companyIdentifier, dataPrefix: typed_array}]}] + })); + + const array_buffer = Uint8Array.of(3, 4).buffer; + detachBuffer(array_buffer); + + await promise_rejects_dom( + t, 'InvalidStateError', requestDeviceWithTrustedClick({ + filters: [ + {manufacturerData: [{companyIdentifier, dataPrefix: array_buffer}]} + ] + })); +}, test_desc);
\ No newline at end of file diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/device-name-longer-than-29-bytes.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/device-name-longer-than-29-bytes.https.window.js new file mode 100644 index 0000000000..20ed383d39 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/device-name-longer-than-29-bytes.https.window.js @@ -0,0 +1,16 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +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(async () => { + let {device} = await setUpPreconnectedFakeDevice({ + fakeDeviceOptions: {name: DEVICE_NAME}, + requestDeviceOptions: {filters: [{name: DEVICE_NAME}]} + }); + assert_equals(device.name, DEVICE_NAME) +}, test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-dataPrefix.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-dataPrefix.https.window.js new file mode 100644 index 0000000000..75e12219cc --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-dataPrefix.https.window.js @@ -0,0 +1,16 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'dataPrefix when present must be non-empty'; + +bluetooth_test(async (t) => { + await promise_rejects_js( + t, TypeError, requestDeviceWithTrustedClick({ + filters: [{ + manufacturerData: + [{companyIdentifier: 1, dataPrefix: new Uint8Array()}] + }] + })); +}, test_desc);
\ No newline at end of file diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-filter.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-filter.https.window.js new file mode 100644 index 0000000000..bfe94f2721 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-filter.https.window.js @@ -0,0 +1,12 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +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), + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-filters-member.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-filters-member.https.window.js new file mode 100644 index 0000000000..3265e54fd8 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-filters-member.https.window.js @@ -0,0 +1,16 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'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.', + new TypeError()); + +bluetooth_test( + () => assert_promise_rejects_with_message( + requestDeviceWithTrustedClick({filters: []}), expected), + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-manufacturerData-member.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-manufacturerData-member.https.window.js new file mode 100644 index 0000000000..0996137f51 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-manufacturerData-member.https.window.js @@ -0,0 +1,35 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'requestDevice with empty manufacturerData. ' + + 'Should reject with TypeError.'; +const test_specs = [ + {filters: [{manufacturerData: []}]}, + {filters: [{manufacturerData: [], name: 'Name'}]}, + {filters: [{manufacturerData: [], services: ['heart_rate']}]}, + {filters: [{manufacturerData: [], name: 'Name', services: ['heart_rate']}]}, + {filters: [{manufacturerData: []}], optionalServices: ['heart_rate']}, { + filters: [{manufacturerData: [], name: 'Name'}], + optionalServices: ['heart_rate'] + }, + { + filters: [{manufacturerData: [], services: ['heart_rate']}], + optionalServices: ['heart_rate'] + }, + { + filters: [{manufacturerData: [], name: 'Name', services: ['heart_rate']}], + optionalServices: ['heart_rate'] + } +]; + +bluetooth_test((t) => { + let test_promises = Promise.resolve(); + test_specs.forEach(args => { + test_promises = test_promises.then( + () => promise_rejects_js( + t, TypeError, requestDeviceWithTrustedClick(args))); + }); + return test_promises; +}, test_desc);
\ No newline at end of file diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-namePrefix.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-namePrefix.https.window.js new file mode 100644 index 0000000000..8ce2e64967 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-namePrefix.https.window.js @@ -0,0 +1,33 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +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'] + } +]; + +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); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-services-member.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-services-member.https.window.js new file mode 100644 index 0000000000..a24611631d --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-services-member.https.window.js @@ -0,0 +1,18 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +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); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/filters-xor-acceptAllDevices.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/filters-xor-acceptAllDevices.https.window.js new file mode 100644 index 0000000000..a6c48f2962 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/filters-xor-acceptAllDevices.https.window.js @@ -0,0 +1,26 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +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.', + new TypeError()); +const test_specs = [ + {}, {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); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/invalid-companyIdentifier.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/invalid-companyIdentifier.https.window.js new file mode 100644 index 0000000000..18cdbb4b4a --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/invalid-companyIdentifier.https.window.js @@ -0,0 +1,17 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'companyIdentifier must be in the [0, 65535] range'; + +bluetooth_test(async (t) => { + await promise_rejects_js( + t, TypeError, + requestDeviceWithTrustedClick( + {filters: [{manufacturerData: [{companyIdentifier: -1}]}]})); + await promise_rejects_js( + t, TypeError, + requestDeviceWithTrustedClick( + {filters: [{manufacturerData: [{companyIdentifier: 65536}]}]})); +}, test_desc);
\ No newline at end of file diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/mask-buffer-is-detached.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/mask-buffer-is-detached.https.window.js new file mode 100644 index 0000000000..502e2e4057 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/mask-buffer-is-detached.https.window.js @@ -0,0 +1,36 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'mask value buffer must not be detached'; + +function detachBuffer(buffer) { + window.postMessage('', '*', [buffer]); +} + +bluetooth_test(async (t) => { + const companyIdentifier = 0x0001; + const dataPrefix = Uint8Array.of(1, 2); + + const typed_array = Uint8Array.of(1, 2); + detachBuffer(typed_array.buffer); + + await promise_rejects_dom( + t, 'InvalidStateError', requestDeviceWithTrustedClick({ + filters: [{ + manufacturerData: [{companyIdentifier, dataPrefix, mask: typed_array}] + }] + })); + + const array_buffer = Uint8Array.of(3, 4).buffer; + detachBuffer(array_buffer); + + await promise_rejects_dom( + t, 'InvalidStateError', requestDeviceWithTrustedClick({ + filters: [{ + manufacturerData: + [{companyIdentifier, dataPrefix, mask: array_buffer}] + }] + })); +}, test_desc);
\ No newline at end of file diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-name-unicode.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-name-unicode.https.window.js new file mode 100644 index 0000000000..23de63d293 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-name-unicode.https.window.js @@ -0,0 +1,20 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +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.', + 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), + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-name.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-name.https.window.js new file mode 100644 index 0000000000..f14f78fe7d --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-name.https.window.js @@ -0,0 +1,17 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'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.', + 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'), + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-namePrefix-unicode.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-namePrefix-unicode.https.window.js new file mode 100644 index 0000000000..aa832b2e76 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-namePrefix-unicode.https.window.js @@ -0,0 +1,20 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +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.', + 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), + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-namePrefix.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-namePrefix.https.window.js new file mode 100644 index 0000000000..5d27629eaa --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-namePrefix.https.window.js @@ -0,0 +1,17 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'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.', + 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'), + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-name-unicode.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-name-unicode.https.window.js new file mode 100644 index 0000000000..1232a030e9 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-name-unicode.https.window.js @@ -0,0 +1,17 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'A unicode device name of 248 bytes is valid.'; +// \u00A1's UTF-8 respresentation is 2 bytes long. +// 124 chars * 2 bytes/char = 248 bytes +const DEVICE_NAME = '\u00A1'.repeat(124); + +bluetooth_test(async () => { + let {device} = await setUpPreconnectedFakeDevice({ + fakeDeviceOptions: {name: DEVICE_NAME}, + requestDeviceOptions: {filters: [{name: DEVICE_NAME}]} + }); + device => assert_equals(device.name, DEVICE_NAME) +}, test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-name.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-name.https.window.js new file mode 100644 index 0000000000..7ede93ce72 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-name.https.window.js @@ -0,0 +1,15 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'A device name of 248 bytes is valid.'; +const DEVICE_NAME = 'a'.repeat(248); + +bluetooth_test(async () => { + let {device} = await setUpPreconnectedFakeDevice({ + fakeDeviceOptions: {name: DEVICE_NAME}, + requestDeviceOptions: {filters: [{name: DEVICE_NAME}]} + }); + device => assert_equals(device.name, DEVICE_NAME) +}, test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-namePrefix-unicode.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-namePrefix-unicode.https.window.js new file mode 100644 index 0000000000..2932dc1cde --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-namePrefix-unicode.https.window.js @@ -0,0 +1,17 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'A unicode device namePrefix of 248 bytes is valid.'; +// \u00A1's UTF-8 respresentation is 2 bytes long. +// 124 chars * 2 bytes/char = 248 bytes +const DEVICE_NAME = '\u00A1'.repeat(124); + +bluetooth_test(async () => { + let {device} = await setUpPreconnectedFakeDevice({ + fakeDeviceOptions: {name: DEVICE_NAME}, + requestDeviceOptions: {filters: [{namePrefix: DEVICE_NAME}]} + }); + device => assert_equals(device.name, DEVICE_NAME) +}, test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-namePrefix.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-namePrefix.https.window.js new file mode 100644 index 0000000000..f922bb2f0d --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-namePrefix.https.window.js @@ -0,0 +1,15 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'A device namePrefix of 248 bytes is valid.'; +const DEVICE_NAME = 'a'.repeat(248); + +bluetooth_test(async () => { + let {device} = await setUpPreconnectedFakeDevice({ + fakeDeviceOptions: {name: DEVICE_NAME}, + requestDeviceOptions: {filters: [{namePrefix: DEVICE_NAME}]} + }); + device => assert_equals(device.name, DEVICE_NAME) +}, test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/no-arguments.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/no-arguments.https.window.js new file mode 100644 index 0000000000..075a97f1a9 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/no-arguments.https.window.js @@ -0,0 +1,12 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'requestDevice() requires an argument.'; +const expected = new TypeError(); + +promise_test( + () => assert_promise_rejects_with_message( + requestDeviceWithTrustedClick(), expected), + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/same-company-identifier.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/same-company-identifier.https.window.js new file mode 100644 index 0000000000..41f851adc5 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/same-company-identifier.https.window.js @@ -0,0 +1,23 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'Manufacturer data company identifier must be unique.'; +const expected = new TypeError(); + +let filters = [{ + manufacturerData: [ + { + companyIdentifier: 0x0001, + }, + { + companyIdentifier: 0x0001, + } + ] +}]; + +bluetooth_test( + (t) => promise_rejects_js( + t, TypeError, requestDeviceWithTrustedClick({filters})), + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-name.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-name.https.window.js new file mode 100644 index 0000000000..cd10288ddb --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-name.https.window.js @@ -0,0 +1,18 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'A name 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(async () => { + let {device} = await setUpPreconnectedFakeDevice({ + fakeDeviceOptions: {name: valid_unicode_name}, + requestDeviceOptions: {filters: [{name: valid_unicode_name}]} + }); + device => assert_equals(device.name, valid_unicode_name) +}, test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-namePrefix.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-namePrefix.https.window.js new file mode 100644 index 0000000000..494f324ee2 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-namePrefix.https.window.js @@ -0,0 +1,18 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +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(async () => { + let {device} = await setUpPreconnectedFakeDevice({ + fakeDeviceOptions: {name: valid_unicode_name}, + requestDeviceOptions: {filters: [{namePrefix: valid_unicode_name}]} + }); + device => assert_equals(device.name, valid_unicode_name) +}, test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-optionalServices-member.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-optionalServices-member.https.window.js new file mode 100644 index 0000000000..bfba220f47 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-optionalServices-member.https.window.js @@ -0,0 +1,37 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'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'}]} +]; + +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); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-services-member.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-services-member.https.window.js new file mode 100644 index 0000000000..352437d0e5 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-services-member.https.window.js @@ -0,0 +1,17 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +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); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/cross-origin-iframe.sub.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/cross-origin-iframe.sub.https.window.js new file mode 100644 index 0000000000..d802a86279 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/cross-origin-iframe.sub.https.window.js @@ -0,0 +1,28 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'Request device from a unique origin. ' + + 'Should reject with SecurityError.'; +const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' + + '/bluetooth/resources/health-thermometer-iframe.html' +let iframe = document.createElement('iframe'); + +bluetooth_test(async (t) => { + await setUpHealthThermometerDevice(); + + // 1. Load the iframe. + const iframeWatcher = new EventWatcher(t, iframe, ['load']); + iframe.src = cross_origin_src; + document.body.appendChild(iframe); + await iframeWatcher.wait_for('load'); + + // 2. Request the device from the iframe. + const windowWatcher = new EventWatcher(t, window, ['message']); + iframe.contentWindow.postMessage({type: 'RequestDevice'}, '*'); + const messageEvent = await windowWatcher.wait_for('message'); + assert_equals( + messageEvent.data, + 'FAIL: SecurityError: Failed to execute \'requestDevice\' on \'Bluetooth\': Access to the feature "bluetooth" is disallowed by permissions policy.'); +}, test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/discovery-succeeds.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/discovery-succeeds.https.window.js new file mode 100644 index 0000000000..4941d185ca --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/discovery-succeeds.https.window.js @@ -0,0 +1,31 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'Discover a device using alias, name, or UUID.'; + +const test_specs = [ + { + filters: [{services: [health_thermometer.alias]}], + }, + { + filters: [{services: [health_thermometer.name]}], + }, + { + filters: [{services: [health_thermometer.uuid]}], + }, +]; + +bluetooth_test( + () => setUpHealthThermometerDevice().then(() => { + let test_promises = Promise.resolve(); + test_specs.forEach(args => { + test_promises = test_promises.then(async () => { + const device = await requestDeviceWithTrustedClick(args); + assert_equals(device.constructor.name, 'BluetoothDevice'); + }); + }); + return test_promises; + }), + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/doesnt-consume-user-gesture.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/doesnt-consume-user-gesture.https.window.js new file mode 100644 index 0000000000..9c742733e1 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/doesnt-consume-user-gesture.https.window.js @@ -0,0 +1,24 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'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); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/filter-matches.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/filter-matches.https.window.js new file mode 100644 index 0000000000..1a0f52ac30 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/filter-matches.https.window.js @@ -0,0 +1,76 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'Matches a filter if all present members match.'; +let matching_services = [health_thermometer.uuid]; +let matching_name = 'Health Thermometer'; +let matching_namePrefix = 'Health'; +let matching_manufacturerData = [{companyIdentifier: 0x0001}]; + +let test_specs = [ + { + filters: [{ + services: matching_services, + }] + }, + { + filters: [{ + services: matching_services, + name: matching_name, + }] + }, + {filters: [{services: matching_services, namePrefix: matching_namePrefix}]}, { + filters: [ + {services: matching_services, manufacturerData: matching_manufacturerData} + ] + }, + { + filters: [{ + name: matching_name, + }], + optionalServices: matching_services + }, + { + filters: [{namePrefix: matching_namePrefix}], + optionalServices: matching_services + }, + { + filters: [{manufacturerData: matching_manufacturerData}], + optionalServices: matching_services + }, + { + filters: [{ + name: matching_name, + namePrefix: matching_namePrefix, + manufacturerData: matching_manufacturerData + }], + optionalServices: matching_services + }, + { + filters: [{ + services: matching_services, + name: matching_name, + namePrefix: matching_namePrefix, + manufacturerData: matching_manufacturerData + }] + } +]; + +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)); + }); + }); + return test_promises; + }), + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/le-not-supported.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/le-not-supported.https.window.js new file mode 100644 index 0000000000..c961ab4492 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/le-not-supported.https.window.js @@ -0,0 +1,15 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'Reject with NotFoundError if Bluetooth is not supported.'; +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.')), + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/manufacturer-data-filter-matches.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/manufacturer-data-filter-matches.https.window.js new file mode 100644 index 0000000000..c4c0e80532 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/manufacturer-data-filter-matches.https.window.js @@ -0,0 +1,139 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'Matches a filter when manufacturer data match.'; + +let test_specs = [ + { + filters: [{ + manufacturerData: [{ + companyIdentifier: 0x0001, + }], + }], + }, + { + filters: [{ + manufacturerData: [{ + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01]), + }], + }], + }, + { + filters: [{ + manufacturerData: [{ + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01]), + mask: new Uint8Array([0xff]), + }], + }], + }, + { + filters: [{ + manufacturerData: [{ + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01, 0x02]), + }], + }], + }, + { + filters: [{ + manufacturerData: [{ + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01, 0x02]), + mask: new Uint8Array([0xff, 0x01]), + }], + }], + }, + { + filters: [{ + manufacturerData: [ + { + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01, 0x02]), + mask: new Uint8Array([0xff, 0x01]), + }, + { + companyIdentifier: 0x0002, + } + ], + }], + }, + { + filters: [{ + manufacturerData: [ + { + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01, 0x02]), + mask: new Uint8Array([0xff, 0x01]), + }, + { + companyIdentifier: 0x0002, + dataPrefix: new Uint8Array([0x03]), + } + ], + }], + }, + { + filters: [{ + manufacturerData: [ + { + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01, 0x02]), + mask: new Uint8Array([0xff, 0x01]), + }, + { + companyIdentifier: 0x0002, + dataPrefix: new Uint8Array([0x03]), + mask: new Uint8Array([0xff]), + } + ], + }], + }, + { + filters: [{ + manufacturerData: [ + { + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01, 0x02]), + mask: new Uint8Array([0xff, 0x01]), + }, + { + companyIdentifier: 0x0002, + dataPrefix: new Uint8Array([0x03, 0x04]), + } + ], + }], + }, + { + filters: [{ + manufacturerData: [ + { + companyIdentifier: 0x0001, + dataPrefix: new Uint8Array([0x01, 0x02]), + mask: new Uint8Array([0xff, 0x01]), + }, + { + companyIdentifier: 0x0002, + dataPrefix: new Uint8Array([0x03, 0x04]), + mask: new Uint8Array([0xff, 0xff]) + } + ], + }], + }, +]; + +bluetooth_test( + () => setUpHealthThermometerDevice().then(() => { + let test_promises = Promise.resolve(); + test_specs.forEach(args => { + test_promises = test_promises.then(async () => { + const device = await requestDeviceWithTrustedClick(args); + assert_equals(device.name, 'Health Thermometer'); + }); + }); + return test_promises; + }), + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/name-empty-device-from-name-empty-filter.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/name-empty-device-from-name-empty-filter.https.window.js new file mode 100644 index 0000000000..2ff22cb702 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/name-empty-device-from-name-empty-filter.https.window.js @@ -0,0 +1,14 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'An empty name device can be obtained by empty name filter.' + +bluetooth_test(async () => { + let {device} = await setUpPreconnectedFakeDevice({ + fakeDeviceOptions: {name: ''}, + requestDeviceOptions: {filters: [{name: ''}]} + }); + assert_equals(device.name, ''); +}, test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/not-processing-user-gesture.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/not-processing-user-gesture.https.window.js new file mode 100644 index 0000000000..a063b61163 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/not-processing-user-gesture.https.window.js @@ -0,0 +1,18 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'Requires a user gesture.'; +const expected = new DOMException( + 'Failed to execute \'requestDevice\' on \'Bluetooth\': ' + + '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')), + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/radio-not-present.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/radio-not-present.https.window.js new file mode 100644 index 0000000000..b55d63c6ff --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/radio-not-present.https.window.js @@ -0,0 +1,17 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'Reject with NotFoundError if there is no BT radio present.'; +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.')), + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/reject_opaque_origin.https.html b/testing/web-platform/tests/bluetooth/requestDevice/reject_opaque_origin.https.html new file mode 100644 index 0000000000..df348dd39e --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/reject_opaque_origin.https.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + 'use strict'; + + promise_test(async (t) => { + await promise_rejects_dom( + t, 'SecurityError', navigator.bluetooth.requestDevice(), + 'requestDevice() should throw a SecurityError DOMException when called from a context where the top-level document has an opaque origin.'); + }, 'Calls to Bluetooth APIs from an origin with opaque top origin get blocked.'); +</script>
\ No newline at end of file diff --git a/testing/web-platform/tests/bluetooth/requestDevice/reject_opaque_origin.https.html.headers b/testing/web-platform/tests/bluetooth/requestDevice/reject_opaque_origin.https.html.headers new file mode 100644 index 0000000000..c7e4e7cc5b --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/reject_opaque_origin.https.html.headers @@ -0,0 +1 @@ +Content-Security-Policy: sandbox allow-scripts
\ No newline at end of file diff --git a/testing/web-platform/tests/bluetooth/requestDevice/request-from-iframe.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/request-from-iframe.https.window.js new file mode 100644 index 0000000000..d3f3cf897f --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/request-from-iframe.https.window.js @@ -0,0 +1,43 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'Concurrent requestDevice calls in iframes work.'; +const iframes = []; +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(); + } + } + + for (let iframe of iframes) { + await callWithTrustedClick( + () => iframe.contentWindow.postMessage( + {type: 'RequestDevice'}, '*')); + } + })), + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/request-from-sandboxed-iframe.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/request-from-sandboxed-iframe.https.window.js new file mode 100644 index 0000000000..2101cf0d6b --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/request-from-sandboxed-iframe.https.window.js @@ -0,0 +1,35 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'Request device from a unique origin. ' + + 'Should reject with SecurityError.'; +const expected = + 'FAIL: SecurityError: Failed to execute \'requestDevice\' on ' + + '\'Bluetooth\': Access to the feature "bluetooth" is disallowed by ' + + 'permissions policy.'; + +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 => { + iframe.contentWindow.postMessage( + {type: 'RequestDevice'}, '*'); + + window.onmessage = messageEvent => { + assert_equals(messageEvent.data, expected); + resolve(); + } + })), + test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/same-device.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/same-device.https.window.js new file mode 100644 index 0000000000..41a42cf4c8 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/same-device.https.window.js @@ -0,0 +1,19 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'use strict'; +const test_desc = 'Returned device should always be the same.'; +let devices = []; + +bluetooth_test(async () => { + await setUpHealthThermometerAndHeartRateDevices(); + devices.push(await requestDeviceWithTrustedClick( + {filters: [{services: [heart_rate.alias]}]})); + devices.push(await requestDeviceWithTrustedClick( + {filters: [{services: [heart_rate.name]}]})); + devices.push(await requestDeviceWithTrustedClick( + {filters: [{services: [heart_rate.uuid]}]})); + assert_equals(devices[0], devices[1]); + assert_equals(devices[1], devices[2]); +}, test_desc); diff --git a/testing/web-platform/tests/bluetooth/requestDevice/sandboxed_iframe.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/sandboxed_iframe.https.window.js new file mode 100644 index 0000000000..e9192a9305 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/sandboxed_iframe.https.window.js @@ -0,0 +1,27 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js + +'use strict'; + +let iframe = document.createElement('iframe'); + +bluetooth_test(async () => { + await getConnectedHealthThermometerDevice(); + await new Promise(resolve => { + iframe.src = '/bluetooth/resources/health-thermometer-iframe.html'; + iframe.sandbox.add('allow-scripts'); + iframe.allow = 'bluetooth'; + document.body.appendChild(iframe); + iframe.addEventListener('load', resolve); + }); + await new Promise(resolve => { + iframe.contentWindow.postMessage({type: 'RequestDevice'}, '*'); + + window.addEventListener('message', (messageEvent) => { + assert_false(/^FAIL: .*/.test(messageEvent.data)); + resolve(); + }); + }); +}, 'Calls to Bluetooth APIs from a sandboxed iframe are valid.');
\ No newline at end of file diff --git a/testing/web-platform/tests/bluetooth/requestDevice/single-filter-single-service.https.window.js b/testing/web-platform/tests/bluetooth/requestDevice/single-filter-single-service.https.window.js new file mode 100644 index 0000000000..67afad0b93 --- /dev/null +++ b/testing/web-platform/tests/bluetooth/requestDevice/single-filter-single-service.https.window.js @@ -0,0 +1,14 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/bluetooth/resources/bluetooth-test.js +// META: script=/bluetooth/resources/bluetooth-fake-devices.js +'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')), + test_desc); |