summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/bluetooth/device
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/bluetooth/device')
-rw-r--r--testing/web-platform/tests/bluetooth/device/forget/connect-after-forget.https.window.js11
-rw-r--r--testing/web-platform/tests/bluetooth/device/forget/detachedIframe.https.window.js27
-rw-r--r--testing/web-platform/tests/bluetooth/device/forget/getDevices.https.window.js18
-rw-r--r--testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/disconnected.https.window.js16
-rw-r--r--testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/disconnected_gc.https.window.js23
-rw-r--r--testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/one-event-per-disconnection.https.window.js30
-rw-r--r--testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/reconnect-during-disconnected-event.https.window.js31
-rw-r--r--testing/web-platform/tests/bluetooth/device/watchAdvertisements/abort-before-watchAdvertisements.https.window.js17
-rw-r--r--testing/web-platform/tests/bluetooth/device/watchAdvertisements/abort-pending-operation.https.window.js22
-rw-r--r--testing/web-platform/tests/bluetooth/device/watchAdvertisements/abort-signal-stops-events.https.window.js27
-rw-r--r--testing/web-platform/tests/bluetooth/device/watchAdvertisements/abort-subsequent-watchAdvertisements-call-stops-events.https.window.js26
-rw-r--r--testing/web-platform/tests/bluetooth/device/watchAdvertisements/advertisementreceived-event-fired.https.window.js25
-rw-r--r--testing/web-platform/tests/bluetooth/device/watchAdvertisements/blocklisted-manufacturer-data-filtered-from-event.https.window.js50
-rw-r--r--testing/web-platform/tests/bluetooth/device/watchAdvertisements/concurrent-watchAdvertisements-calls.https.window.js29
-rw-r--r--testing/web-platform/tests/bluetooth/device/watchAdvertisements/detachedIframe.https.window.js27
-rw-r--r--testing/web-platform/tests/bluetooth/device/watchAdvertisements/service-and-manufacturer-data-filtered-from-event.https.window.js41
-rw-r--r--testing/web-platform/tests/bluetooth/device/watchAdvertisements/subsequent-watchAdvertisements-call.https.window.js25
-rw-r--r--testing/web-platform/tests/bluetooth/device/watchAdvertisements/watching-two-devices-abort-one-watchAdvertisements.https.window.js47
-rw-r--r--testing/web-platform/tests/bluetooth/device/watchAdvertisements/watching-two-devices.https.window.js41
19 files changed, 533 insertions, 0 deletions
diff --git a/testing/web-platform/tests/bluetooth/device/forget/connect-after-forget.https.window.js b/testing/web-platform/tests/bluetooth/device/forget/connect-after-forget.https.window.js
new file mode 100644
index 0000000000..0b15b4d060
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/forget/connect-after-forget.https.window.js
@@ -0,0 +1,11 @@
+// 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
+
+bluetooth_test(async (t) => {
+ const { device } = await getConnectedHealthThermometerDevice();
+ await device.forget();
+
+ await promise_rejects_dom(t, 'SecurityError', device.gatt.connect());
+}, 'gatt.connect() rejects after forget().');
diff --git a/testing/web-platform/tests/bluetooth/device/forget/detachedIframe.https.window.js b/testing/web-platform/tests/bluetooth/device/forget/detachedIframe.https.window.js
new file mode 100644
index 0000000000..f4803542fb
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/forget/detachedIframe.https.window.js
@@ -0,0 +1,27 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+
+bluetooth_test(async () => {
+ let iframe = document.createElement('iframe');
+ let error;
+
+ const {device} = await getHealthThermometerDeviceFromIframe(iframe);
+
+ iframe.remove();
+ // Set iframe to null to ensure that the GC cleans up as much as possible.
+ iframe = null;
+ await garbageCollect();
+
+ try {
+ await device.forget();
+ } catch (e) {
+ // Cannot use promise_rejects_dom() because |e| is thrown from a different
+ // global.
+ error = e;
+ }
+ assert_not_equals(error, undefined);
+ assert_equals(error.name, 'TypeError');
+}, 'forget() rejects in a detached context');
diff --git a/testing/web-platform/tests/bluetooth/device/forget/getDevices.https.window.js b/testing/web-platform/tests/bluetooth/device/forget/getDevices.https.window.js
new file mode 100644
index 0000000000..e9ce656319
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/forget/getDevices.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
+
+bluetooth_test(async () => {
+ await getConnectedHealthThermometerDevice();
+ const devicesBeforeForget = await navigator.bluetooth.getDevices();
+ assert_equals(
+ devicesBeforeForget.length, 1, 'getDevices() should return the granted device.');
+
+ const device = devicesBeforeForget[0];
+ await device.forget();
+ const devicesAfterForget = await navigator.bluetooth.getDevices();
+ assert_equals(
+ devicesAfterForget.length, 0,
+ 'getDevices() is empty after device.forget().');
+}, 'forget() removes devices from getDevices().');
diff --git a/testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/disconnected.https.window.js b/testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/disconnected.https.window.js
new file mode 100644
index 0000000000..43a11a88cb
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/disconnected.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 disconnecting while connected should fire the ' +
+ 'gattserverdisconnected event.';
+
+bluetooth_test(async () => {
+ const {device, fake_peripheral} = await getConnectedHealthThermometerDevice();
+ const disconnectPromise = eventPromise(device, 'gattserverdisconnected');
+
+ await fake_peripheral.simulateGATTDisconnection();
+ let disconnectEvent = await disconnectPromise;
+ assert_true(disconnectEvent.bubbles);
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/disconnected_gc.https.window.js b/testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/disconnected_gc.https.window.js
new file mode 100644
index 0000000000..0cf4973e21
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/disconnected_gc.https.window.js
@@ -0,0 +1,23 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+'use strict';
+const test_desc = 'A device disconnecting after the BluetoothDevice object ' +
+ 'has been GC\'ed should not access freed memory.';
+
+bluetooth_test(async () => {
+ let {fake_peripheral} = await getConnectedHealthThermometerDevice();
+
+ // 1. Disconnect.
+ await fake_peripheral.simulateGATTDisconnection();
+
+ // 2. Run garbage collection.
+ fake_peripheral = undefined;
+ await garbageCollect();
+
+ // 3. Wait 50ms after the GC runs for the disconnection event to come back.
+ // There's nothing to assert other than that only valid memory is used.
+ await new Promise(resolve => step_timeout(resolve, 50));
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/one-event-per-disconnection.https.window.js b/testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/one-event-per-disconnection.https.window.js
new file mode 100644
index 0000000000..ab273adbc8
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/one-event-per-disconnection.https.window.js
@@ -0,0 +1,30 @@
+// 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 = 'If a site disconnects from a device while the platform is ' +
+ 'disconnecting that device, only one gattserverdisconnected event should ' +
+ 'fire.';
+
+bluetooth_test(async () => {
+ const {device, fake_peripheral} = await getConnectedHealthThermometerDevice();
+ let num_events = 0;
+
+ // 1. Listen for disconnections.
+ device.addEventListener('gattserverdisconnected', () => num_events++);
+
+ // 2. Disconnect several times.
+ await Promise.all([
+ eventPromise(device, 'gattserverdisconnected'),
+ fake_peripheral.simulateGATTDisconnection(),
+ device.gatt.disconnect(),
+ device.gatt.disconnect(),
+ ]);
+
+ // 3. Wait to catch disconnect events.
+ await new Promise(resolve => step_timeout(resolve, 50));
+
+ // 4. Ensure there is exactly 1 disconnection recorded.
+ assert_equals(num_events, 1);
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/reconnect-during-disconnected-event.https.window.js b/testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/reconnect-during-disconnected-event.https.window.js
new file mode 100644
index 0000000000..bdaf47c661
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/reconnect-during-disconnected-event.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 = 'A device that reconnects during the ' +
+ 'gattserverdisconnected event should still receive ' +
+ 'gattserverdisconnected events after re-connection.';
+
+bluetooth_test(async () => {
+ const {device, fake_peripheral} = await getConnectedHealthThermometerDevice();
+
+ const reconnectPromise = new Promise(async (resolve) => {
+ device.addEventListener('gattserverdisconnected', async () => {
+ // 2. Reconnect.
+ await fake_peripheral.setNextGATTConnectionResponse({
+ code: HCI_SUCCESS,
+ });
+ await device.gatt.connect();
+
+ // 3. Disconnect after reconnecting.
+ const disconnectPromise = eventPromise(device, 'gattserverdisconnected');
+ fake_peripheral.simulateGATTDisconnection();
+ resolve(disconnectPromise);
+ }, {once: true});
+ });
+
+ // 1. Disconnect.
+ await fake_peripheral.simulateGATTDisconnection();
+ await reconnectPromise;
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/device/watchAdvertisements/abort-before-watchAdvertisements.https.window.js b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/abort-before-watchAdvertisements.https.window.js
new file mode 100644
index 0000000000..e1ac1fb136
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/abort-before-watchAdvertisements.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 = 'watchAdvertisements() rejects if passed an aborted signal.';
+
+bluetooth_test(async (t) => {
+ let {device} = await getDiscoveredHealthThermometerDevice();
+ let abortController = new AbortController();
+ abortController.abort();
+
+ await promise_rejects_dom(
+ t, 'AbortError',
+ device.watchAdvertisements({signal: abortController.signal}));
+ assert_false(device.watchingAdvertisements);
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/device/watchAdvertisements/abort-pending-operation.https.window.js b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/abort-pending-operation.https.window.js
new file mode 100644
index 0000000000..c1022ff4a9
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/abort-pending-operation.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 = 'AbortController stops a pending watchAdvertisements() ' +
+ 'operation.';
+
+bluetooth_test(async (t) => {
+ let {device} = await getDiscoveredHealthThermometerDevice();
+ const watcher = new EventWatcher(t, device, ['advertisementreceived']);
+ let abortController = new AbortController();
+
+ let watchAdvertisementsPromise =
+ device.watchAdvertisements({signal: abortController.signal});
+ abortController.abort();
+ assert_false(device.watchingAdvertisements);
+ await promise_rejects_dom(t, 'AbortError', watchAdvertisementsPromise);
+
+ await fake_central.simulateAdvertisementReceived(
+ health_thermometer_ad_packet);
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/device/watchAdvertisements/abort-signal-stops-events.https.window.js b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/abort-signal-stops-events.https.window.js
new file mode 100644
index 0000000000..21b6883fee
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/abort-signal-stops-events.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';
+const test_desc = `AbortController stops 'advertisementreceived' ` +
+ `events from being fired on the device object.`;
+
+bluetooth_test(async (t) => {
+ let {device} = await getDiscoveredHealthThermometerDevice();
+ const watcher = new EventWatcher(t, device, ['advertisementreceived']);
+ let abortController = new AbortController();
+
+ await device.watchAdvertisements({signal: abortController.signal});
+ assert_true(device.watchingAdvertisements);
+
+ let advertisementreceivedPromise = watcher.wait_for('advertisementreceived');
+ await fake_central.simulateAdvertisementReceived(
+ health_thermometer_ad_packet);
+ await advertisementreceivedPromise;
+
+ abortController.abort();
+ assert_false(device.watchingAdvertisements);
+
+ await fake_central.simulateAdvertisementReceived(
+ health_thermometer_ad_packet);
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/device/watchAdvertisements/abort-subsequent-watchAdvertisements-call-stops-events.https.window.js b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/abort-subsequent-watchAdvertisements-call-stops-events.https.window.js
new file mode 100644
index 0000000000..a5da75012b
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/abort-subsequent-watchAdvertisements-call-stops-events.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 = 'AbortController on subsequent watchAdvertisements() call ' +
+ 'cancels the watch advertisements operation.';
+
+bluetooth_test(async (t) => {
+ let {device} = await getDiscoveredHealthThermometerDevice();
+ const watcher = new EventWatcher(t, device, ['advertisementreceived']);
+
+ // Start a watchAdvertisements() operation.
+ await device.watchAdvertisements();
+ assert_true(device.watchingAdvertisements);
+
+ // Start a second watchAdvertisements() operation after the first one
+ // resolves. This operation should resolve successfully.
+ let abortController = new AbortController();
+ await device.watchAdvertisements({signal: abortController.signal});
+ abortController.abort();
+ assert_false(device.watchingAdvertisements);
+
+ // This advertisement packet should not cause the event to be fired.
+ await fake_central.simulateAdvertisementReceived(heart_rate_ad_packet);
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/device/watchAdvertisements/advertisementreceived-event-fired.https.window.js b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/advertisementreceived-event-fired.https.window.js
new file mode 100644
index 0000000000..fff18bc47e
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/advertisementreceived-event-fired.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 = `watchAdvertisements() enables 'advertisementreceived' ` +
+ `events to be fired on the device object.`;
+
+bluetooth_test(async (t) => {
+ let {device} = await getDiscoveredHealthThermometerDevice();
+ const watcher = new EventWatcher(t, device, ['advertisementreceived']);
+
+ await device.watchAdvertisements();
+ assert_true(device.watchingAdvertisements);
+
+ // This advertisement packet represents a different device and should not
+ // cause an event to be fired on |device|.
+ await fake_central.simulateAdvertisementReceived(heart_rate_ad_packet);
+
+ let advertisementreceivedPromise = watcher.wait_for('advertisementreceived');
+ await fake_central.simulateAdvertisementReceived(
+ health_thermometer_ad_packet);
+ let evt = await advertisementreceivedPromise;
+ assert_equals(evt.device, device);
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/device/watchAdvertisements/blocklisted-manufacturer-data-filtered-from-event.https.window.js b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/blocklisted-manufacturer-data-filtered-from-event.https.window.js
new file mode 100644
index 0000000000..c73e3dbad1
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/blocklisted-manufacturer-data-filtered-from-event.https.window.js
@@ -0,0 +1,50 @@
+// 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 = `Blocked manufacturer data is filtered from the ` +
+ `advertisement event.`;
+
+const advertisement_packet_with_blocked_manufacturer_data = {
+ deviceAddress: '07:07:07:07:07:07',
+ rssi: -10,
+ scanRecord: {
+ name: 'LE Device',
+ uuids: [uuid1234],
+ manufacturerData: {
+ [nonBlocklistedManufacturerId]: nonBlocklistedManufacturerData,
+ [blocklistedManufacturerId]: blocklistedManufacturerData,
+ },
+ }
+};
+
+bluetooth_test(async (t) => {
+ let {device} = await setUpPreconnectedFakeDevice({
+ fakeDeviceOptions: {
+ address: '07:07:07:07:07:07',
+ knownServiceUUIDs: [uuid1234],
+ },
+ requestDeviceOptions: {
+ filters: [{services: [uuid1234]}],
+ optionalManufacturerData: [nonBlocklistedManufacturerId, blocklistedManufacturerId]
+ }
+ });
+ const watcher = new EventWatcher(t, device, ['advertisementreceived']);
+
+ await device.watchAdvertisements();
+ assert_true(device.watchingAdvertisements);
+
+ let advertisementreceivedPromise = watcher.wait_for('advertisementreceived');
+ await fake_central.simulateAdvertisementReceived(
+ advertisement_packet_with_blocked_manufacturer_data);
+ let evt = await advertisementreceivedPromise;
+ assert_equals(evt.device, device);
+
+ // Check if block-listed manufacturer data is filtered out properly.
+ assert_false(evt.manufacturerData.has(blocklistedManufacturerId));
+
+ // Check if non blocked-listed manufacturer still exists.
+ assert_data_maps_equal(
+ evt.manufacturerData, /*expected_key=*/ nonBlocklistedManufacturerId, nonBlocklistedManufacturerData);
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/device/watchAdvertisements/concurrent-watchAdvertisements-calls.https.window.js b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/concurrent-watchAdvertisements-calls.https.window.js
new file mode 100644
index 0000000000..cb6532be68
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/concurrent-watchAdvertisements-calls.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 = 'concurrent watchAdvertisements() calls results in the ' +
+ `second call rejecting with 'InvalidStateError'`;
+
+bluetooth_test(async (t) => {
+ let {device} = await getDiscoveredHealthThermometerDevice();
+ const watcher = new EventWatcher(t, device, ['advertisementreceived']);
+
+ // Start a watchAdvertisements() operation.
+ let firstWatchAdvertisementsPromise = device.watchAdvertisements();
+
+ // Start a second watchAdvertisements() operation. This operation should
+ // reject with 'InvalidStateError'.
+ await promise_rejects_dom(
+ t, 'InvalidStateError', device.watchAdvertisements());
+
+ // The first watchAdvertisements() operation should resolve successfully.
+ await firstWatchAdvertisementsPromise;
+
+ let advertisementreceivedPromise = watcher.wait_for('advertisementreceived');
+ await fake_central.simulateAdvertisementReceived(
+ health_thermometer_ad_packet);
+ let evt = await advertisementreceivedPromise;
+ assert_equals(evt.device, device);
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/device/watchAdvertisements/detachedIframe.https.window.js b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/detachedIframe.https.window.js
new file mode 100644
index 0000000000..202a8dab7d
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/detachedIframe.https.window.js
@@ -0,0 +1,27 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+
+bluetooth_test(async () => {
+ let iframe = document.createElement('iframe');
+ let error;
+
+ const {device} = await getHealthThermometerDeviceFromIframe(iframe);
+
+ iframe.remove();
+ // Set iframe to null to ensure that the GC cleans up as much as possible.
+ iframe = null;
+ await garbageCollect();
+
+ try {
+ await device.watchAdvertisements();
+ } catch (e) {
+ // Cannot use promise_rejects_dom() because |e| is thrown from a different
+ // global.
+ error = e;
+ }
+ assert_not_equals(error, undefined);
+ assert_equals(error.name, 'TypeError');
+}, 'watchAdvertisements() rejects in a detached context');
diff --git a/testing/web-platform/tests/bluetooth/device/watchAdvertisements/service-and-manufacturer-data-filtered-from-event.https.window.js b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/service-and-manufacturer-data-filtered-from-event.https.window.js
new file mode 100644
index 0000000000..f6b93ffb4b
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/service-and-manufacturer-data-filtered-from-event.https.window.js
@@ -0,0 +1,41 @@
+// 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 = `Service and Manufacturer that were not granted with ` +
+ `requestDevice() are filtered from the advertisement event.`;
+
+bluetooth_test(async (t) => {
+ let {device} = await setUpPreconnectedFakeDevice({
+ fakeDeviceOptions: {
+ address: '07:07:07:07:07:07',
+ knownServiceUUIDs: [uuid1234, uuid5678, uuidABCD],
+ },
+ requestDeviceOptions: {
+ filters: [{services: [uuid1234]}],
+ optionalServices: [uuid5678],
+ optionalManufacturerData: [0x0001]
+ }
+ });
+ const watcher = new EventWatcher(t, device, ['advertisementreceived']);
+
+ await device.watchAdvertisements();
+ assert_true(device.watchingAdvertisements);
+
+ let advertisementreceivedPromise = watcher.wait_for('advertisementreceived');
+ await fake_central.simulateAdvertisementReceived(
+ service_and_manufacturer_data_ad_packet);
+ let evt = await advertisementreceivedPromise;
+ assert_equals(evt.device, device);
+
+ // Check that service data is filtered out properly.
+ assert_data_maps_equal(evt.serviceData, uuid1234, uuid1234Data);
+ assert_data_maps_equal(evt.serviceData, uuid5678, uuid5678Data);
+ assert_false(evt.serviceData.has(uuidABCD));
+
+ // Check that manufacturer data is filtered out properly.
+ assert_data_maps_equal(
+ evt.manufacturerData, /*expected_key=*/ 0x0001, manufacturer1Data);
+ assert_false(evt.manufacturerData.has(0x0002));
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/device/watchAdvertisements/subsequent-watchAdvertisements-call.https.window.js b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/subsequent-watchAdvertisements-call.https.window.js
new file mode 100644
index 0000000000..797bfd1fa0
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/subsequent-watchAdvertisements-call.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 = 'subsequent watchAdvertisements() calls result in the ' +
+ 'second call resolving successfully.';
+
+bluetooth_test(async (t) => {
+ let {device} = await getDiscoveredHealthThermometerDevice();
+ const watcher = new EventWatcher(t, device, ['advertisementreceived']);
+
+ // Start a watchAdvertisements() operation.
+ await device.watchAdvertisements();
+
+ // Start a second watchAdvertisements() operation after the first one
+ // resolves. This operation should resolve successfully.
+ await device.watchAdvertisements();
+
+ let advertisementreceivedPromise = watcher.wait_for('advertisementreceived');
+ await fake_central.simulateAdvertisementReceived(
+ health_thermometer_ad_packet);
+ let evt = await advertisementreceivedPromise;
+ assert_equals(evt.device, device);
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/device/watchAdvertisements/watching-two-devices-abort-one-watchAdvertisements.https.window.js b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/watching-two-devices-abort-one-watchAdvertisements.https.window.js
new file mode 100644
index 0000000000..8be02adb34
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/watching-two-devices-abort-one-watchAdvertisements.https.window.js
@@ -0,0 +1,47 @@
+// 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 = 'AbortController while watching advertisements for two ' +
+ 'devices stops the correct watchAdvertisements() operation.';
+
+bluetooth_test(async (t) => {
+ let health_thermometer_device;
+ let heart_rate_device;
+ {
+ let {device} = await getDiscoveredHealthThermometerDevice();
+ health_thermometer_device = device;
+ }
+ {
+ let {device} = await getHeartRateDevice(
+ {requestDeviceOptions: heartRateRequestDeviceOptionsDefault});
+ heart_rate_device = device;
+ }
+ const healthThermometerWatcher =
+ new EventWatcher(t, health_thermometer_device, ['advertisementreceived']);
+ const heartRateWatcher =
+ new EventWatcher(t, heart_rate_device, ['advertisementreceived']);
+
+ await health_thermometer_device.watchAdvertisements();
+
+ let abortController = new AbortController();
+ await heart_rate_device.watchAdvertisements({signal: abortController.signal});
+
+ assert_true(health_thermometer_device.watchingAdvertisements);
+ assert_true(heart_rate_device.watchingAdvertisements);
+
+ abortController.abort();
+ assert_true(health_thermometer_device.watchingAdvertisements);
+ assert_false(heart_rate_device.watchingAdvertisements);
+
+ // This should not cause |heart_rate_device| to receive an Event.
+ await fake_central.simulateAdvertisementReceived(heart_rate_ad_packet);
+
+ let advertisementreceivedPromise =
+ healthThermometerWatcher.wait_for('advertisementreceived');
+ await fake_central.simulateAdvertisementReceived(
+ health_thermometer_ad_packet);
+ let evt = await advertisementreceivedPromise;
+ assert_equals(evt.device, health_thermometer_device);
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/device/watchAdvertisements/watching-two-devices.https.window.js b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/watching-two-devices.https.window.js
new file mode 100644
index 0000000000..32ec89a1eb
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/device/watchAdvertisements/watching-two-devices.https.window.js
@@ -0,0 +1,41 @@
+// 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 = `Events are fired on correct device with multiple ` +
+ `watchAdvertisements() calls.`;
+
+bluetooth_test(async (t) => {
+ let health_thermometer_device;
+ let heart_rate_device;
+ {
+ let {device} = await getDiscoveredHealthThermometerDevice();
+ health_thermometer_device = device;
+ }
+ {
+ let {device} = await getHeartRateDevice(
+ {requestDeviceOptions: heartRateRequestDeviceOptionsDefault});
+ heart_rate_device = device;
+ }
+ const healthThermometerWatcher =
+ new EventWatcher(t, health_thermometer_device, ['advertisementreceived']);
+ const heartRateWatcher =
+ new EventWatcher(t, heart_rate_device, ['advertisementreceived']);
+
+ await health_thermometer_device.watchAdvertisements();
+ await heart_rate_device.watchAdvertisements();
+
+ let advertisementreceivedPromise =
+ heartRateWatcher.wait_for('advertisementreceived');
+ await fake_central.simulateAdvertisementReceived(heart_rate_ad_packet);
+ let heartEvt = await advertisementreceivedPromise;
+ assert_equals(heartEvt.device, heart_rate_device);
+
+ advertisementreceivedPromise =
+ healthThermometerWatcher.wait_for('advertisementreceived');
+ await fake_central.simulateAdvertisementReceived(
+ health_thermometer_ad_packet);
+ let healthEvt = await advertisementreceivedPromise;
+ assert_equals(healthEvt.device, health_thermometer_device);
+}, test_desc);