Bug 1631973 [wpt PR 23157] - bluetooth: Split bluetooth-helpers.js, a=testonly
authorOvidio Henriquez <odejesush@chromium.org>
Tue, 28 Apr 2020 11:44:08 +0000
changeset 527653 4ef42579cac5b2ee7ffedecb46b89f57f89cd0f1
parent 527652 974b68ffab59f2e9e3b2c677399e1f8054440486
child 527654 d700bf57b90b613f5dee497a4a7f6a3c2d665476
push id37368
push userbtara@mozilla.com
push dateFri, 01 May 2020 21:45:51 +0000
treeherdermozilla-central@0f9c5a59e45d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstestonly
bugs1631973, 23157, 1070816, 2149909, 762594
milestone77.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1631973 [wpt PR 23157] - bluetooth: Split bluetooth-helpers.js, a=testonly Automatic update from web-platform-tests bluetooth: Split bluetooth-helpers.js This change splits the bluetooth-helpers.js files in two. The new bluetooth-test.js file contains methods for setting up the web tests and for asserting conditions. The bluetooth-helpers.js file now contains helper methods that set up fake Bluetooth devices for use in the Web Bluetooth tests. I added JsDoc style comments to the helper methods to make it clear what kinds of objects are expected as parameters and what the methods will return. I also reordered the bluetooth-helpers.js methods so that they are defined before they are used. Bug: 1070816 Change-Id: Ib5215555be2b24b11f8dea9098d83ad69719a284 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2149909 Reviewed-by: Reilly Grant <reillyg@chromium.org> Reviewed-by: James Hollyer <jameshollyer@google.com> Commit-Queue: Ovidio de Jesús Ruiz-Henríquez <odejesush@chromium.org> Cr-Commit-Position: refs/heads/master@{#762594} -- wpt-commits: 6f8f0b30a4af91762427b4ff528ed344d5636c6d wpt-pr: 23157
testing/web-platform/tests/bluetooth/README.md
testing/web-platform/tests/bluetooth/adapter/adapter-absent-getAvailability.https.window.js
testing/web-platform/tests/bluetooth/adapter/adapter-added-getAvailability.https.window.js
testing/web-platform/tests/bluetooth/adapter/adapter-powered-off-getAvailability.https.window.js
testing/web-platform/tests/bluetooth/adapter/adapter-powered-on-getAvailability.https.window.js
testing/web-platform/tests/bluetooth/adapter/adapter-powered-on-off-on-getAvailability.https.window.js
testing/web-platform/tests/bluetooth/adapter/adapter-removed-getAvailability.https.window.js
testing/web-platform/tests/bluetooth/adapter/cross-origin-iframe-getAvailability.sub.https.window.js
testing/web-platform/tests/bluetooth/characteristic/characteristicProperties.https.window.js
testing/web-platform/tests/bluetooth/characteristic/getDescriptor/gen-characteristic-is-removed.https.window.js
testing/web-platform/tests/bluetooth/characteristic/getDescriptor/gen-descriptor-get-same-object.https.window.js
testing/web-platform/tests/bluetooth/characteristic/getDescriptor/gen-service-is-removed.https.window.js
testing/web-platform/tests/bluetooth/characteristic/getDescriptors/gen-characteristic-is-removed-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/characteristic/getDescriptors/gen-characteristic-is-removed.https.window.js
testing/web-platform/tests/bluetooth/characteristic/getDescriptors/gen-descriptor-get-same-object.https.window.js
testing/web-platform/tests/bluetooth/characteristic/getDescriptors/gen-service-is-removed-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/characteristic/getDescriptors/gen-service-is-removed.https.window.js
testing/web-platform/tests/bluetooth/characteristic/notifications/characteristic-is-removed.https.window.js
testing/web-platform/tests/bluetooth/characteristic/notifications/service-is-removed.https.window.js
testing/web-platform/tests/bluetooth/characteristic/readValue/add-multiple-event-listeners.https.window.js
testing/web-platform/tests/bluetooth/characteristic/readValue/characteristic-is-removed.https.window.js
testing/web-platform/tests/bluetooth/characteristic/readValue/event-is-fired.https.window.js
testing/web-platform/tests/bluetooth/characteristic/readValue/gen-characteristic-is-removed.https.window.js
testing/web-platform/tests/bluetooth/characteristic/readValue/read-succeeds.https.window.js
testing/web-platform/tests/bluetooth/characteristic/readValue/read-updates-value.https.window.js
testing/web-platform/tests/bluetooth/characteristic/readValue/service-is-removed.https.window.js
testing/web-platform/tests/bluetooth/characteristic/service-same-from-2-characteristics.https.window.js
testing/web-platform/tests/bluetooth/characteristic/service-same-object.https.window.js
testing/web-platform/tests/bluetooth/characteristic/startNotifications/gen-characteristic-is-removed.https.window.js
testing/web-platform/tests/bluetooth/characteristic/writeValue/buffer-is-detached.https.window.js
testing/web-platform/tests/bluetooth/characteristic/writeValue/characteristic-is-removed.https.window.js
testing/web-platform/tests/bluetooth/characteristic/writeValue/gen-characteristic-is-removed.https.window.js
testing/web-platform/tests/bluetooth/characteristic/writeValue/service-is-removed.https.window.js
testing/web-platform/tests/bluetooth/characteristic/writeValue/write-succeeds.https.window.js
testing/web-platform/tests/bluetooth/descriptor/readValue/gen-service-is-removed.https.window.js
testing/web-platform/tests/bluetooth/descriptor/readValue/read-succeeds.https.window.js
testing/web-platform/tests/bluetooth/descriptor/writeValue/buffer-is-detached.https.window.js
testing/web-platform/tests/bluetooth/descriptor/writeValue/gen-service-is-removed.https.window.js
testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/disconnected.https.window.js
testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/disconnected_gc.https.window.js
testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/one-event-per-disconnection.https.window.js
testing/web-platform/tests/bluetooth/device/gattserverdisconnected-event/reconnect-during-disconnected-event.https.window.js
testing/web-platform/tests/bluetooth/getDevices/granted-devices-with-services.https.window.js
testing/web-platform/tests/bluetooth/getDevices/no-granted-devices.https.window.js
testing/web-platform/tests/bluetooth/getDevices/returns-same-bluetooth-device-object.https.window.js
testing/web-platform/tests/bluetooth/idl/idl-BluetoothDevice.https.html
testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.https.html
testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/device-with-name.https.html
testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/optional-services-missing.https.html
testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/optional-services-present.https.html
testing/web-platform/tests/bluetooth/requestDevice/blocklisted-service-in-filter.https.html
testing/web-platform/tests/bluetooth/requestDevice/blocklisted-service-in-optionalServices.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/device-name-longer-than-29-bytes.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-filter.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-filters-member.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-namePrefix.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-services-member.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/filters-xor-acceptAllDevices.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-name-unicode.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-name.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-namePrefix-unicode.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-namePrefix.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-name-unicode.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-name.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-namePrefix-unicode.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-namePrefix.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/no-arguments.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-name.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-namePrefix.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-optionalServices-member.https.html
testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-services-member.https.html
testing/web-platform/tests/bluetooth/requestDevice/cross-origin-iframe.sub.https.html
testing/web-platform/tests/bluetooth/requestDevice/discovery-succeeds.https.html
testing/web-platform/tests/bluetooth/requestDevice/doesnt-consume-user-gesture.https.html
testing/web-platform/tests/bluetooth/requestDevice/filter-matches.https.html
testing/web-platform/tests/bluetooth/requestDevice/le-not-supported.https.html
testing/web-platform/tests/bluetooth/requestDevice/name-empty-device-from-name-empty-filter.https.html
testing/web-platform/tests/bluetooth/requestDevice/not-processing-user-gesture.https.html
testing/web-platform/tests/bluetooth/requestDevice/radio-not-present.https.html
testing/web-platform/tests/bluetooth/requestDevice/request-from-iframe.https.html
testing/web-platform/tests/bluetooth/requestDevice/request-from-sandboxed-iframe.https.html
testing/web-platform/tests/bluetooth/requestDevice/same-device.https.html
testing/web-platform/tests/bluetooth/requestDevice/single-filter-single-service.https.html
testing/web-platform/tests/bluetooth/resources/bluetooth-fake-devices.js
testing/web-platform/tests/bluetooth/resources/bluetooth-helpers.js
testing/web-platform/tests/bluetooth/resources/bluetooth-scanning-helpers.js
testing/web-platform/tests/bluetooth/resources/bluetooth-test.js
testing/web-platform/tests/bluetooth/script-tests/base_test_js.template
testing/web-platform/tests/bluetooth/server/connect/connection-succeeds.https.html
testing/web-platform/tests/bluetooth/server/connect/garbage-collection-ran-during-success.https.html
testing/web-platform/tests/bluetooth/server/connect/get-same-gatt-server.https.html
testing/web-platform/tests/bluetooth/server/device-same-object.https.html
testing/web-platform/tests/bluetooth/server/disconnect/connect-disconnect-twice.https.html
testing/web-platform/tests/bluetooth/server/disconnect/detach-gc.https.html
testing/web-platform/tests/bluetooth/server/disconnect/disconnect-twice-in-a-row.https.html
testing/web-platform/tests/bluetooth/server/disconnect/gc-detach.https.html
testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-disconnect-called-before.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-disconnect-called-during-error.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-disconnect-called-during-success.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-disconnect-invalidates-objects.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-disconnected-device.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-discovery-complete-no-permission-absent-service.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-discovery-complete-service-not-found.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-garbage-collection-ran-during-error.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-garbage-collection-ran-during-success.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-get-different-service-after-reconnection.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-get-same-object.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-invalid-service-name.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-no-permission-absent-service.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-no-permission-for-any-service.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-no-permission-present-service.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-service-not-found.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryService/service-found.https.html
testing/web-platform/tests/bluetooth/server/getPrimaryService/two-iframes-from-same-origin.https.html
testing/web-platform/tests/bluetooth/server/getPrimaryServices/blocklisted-services-with-uuid.https.html
testing/web-platform/tests/bluetooth/server/getPrimaryServices/blocklisted-services.https.html
testing/web-platform/tests/bluetooth/server/getPrimaryServices/correct-services.https.html
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-before-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-before.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-during-error-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-during-error.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-during-success-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-during-success.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-invalidates-objects-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-invalidates-objects.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnected-device-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnected-device.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-discovery-complete-no-permission-absent-service-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-discovery-complete-service-not-found-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-garbage-collection-ran-during-error-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-garbage-collection-ran-during-error.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-garbage-collection-ran-during-success-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-garbage-collection-ran-during-success.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-get-different-service-after-reconnection-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-get-different-service-after-reconnection.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-get-same-object-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-get-same-object.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-invalid-service-name.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-no-permission-absent-service-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-no-permission-for-any-service-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-no-permission-for-any-service.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-no-permission-present-service-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-service-not-found-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/server/getPrimaryServices/services-found-with-uuid.https.html
testing/web-platform/tests/bluetooth/server/getPrimaryServices/services-found.https.html
testing/web-platform/tests/bluetooth/server/getPrimaryServices/services-not-found.https.html
testing/web-platform/tests/bluetooth/service/device-same-from-2-services.https.html
testing/web-platform/tests/bluetooth/service/device-same-object.https.html
testing/web-platform/tests/bluetooth/service/getCharacteristic/characteristic-found.https.html
testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-blocklisted-characteristic.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-characteristic-not-found.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-garbage-collection-ran-during-error.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-get-same-object.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-invalid-characteristic-name.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-reconnect-during.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-service-is-removed.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristics/blocklisted-characteristics.https.html
testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-found-with-uuid.https.html
testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-found.https.html
testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-not-found.https.html
testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-blocklisted-characteristic-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-characteristic-not-found-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-garbage-collection-ran-during-error-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-garbage-collection-ran-during-error.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-get-same-object-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-get-same-object.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-invalid-characteristic-name.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-reconnect-during-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-reconnect-during.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-service-is-removed-with-uuid.https.window.js
testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-service-is-removed.https.window.js
--- a/testing/web-platform/tests/bluetooth/README.md
+++ b/testing/web-platform/tests/bluetooth/README.md
@@ -5,20 +5,21 @@ Low Energy devices. Please check the [We
 details.
 
 Web Bluetooth testing relies on the [FakeBluetooth][Web Bluetooth
 Testing] test API which must be provided by browsers under test.
 
 TODO([#485]): Update the links to [FakeBluetooth][Web Bluetooth Testing] to
 point to the [Testing Web Bluetooth specification].
 
-In this test suite `resources/bluetooth-helpers.js` detects and triggers
-the API to be loaded as needed. This file also contains several helper methods
-that are used in the tests to set up fake Bluetooth devices and to assert that
-specific Bluetooth events happened.
+In this test suite `resources/bluetooth-test.js` detects and triggers
+the API to be loaded as needed. This file also contains test helper methods,
+such as for asserting that Bluetooth events are fired in a specific order.
+The `resources/bluetooth-fake-devices.js` contains several helper methods that set
+up fake Bluetooth devices.
 
 [Web Bluetooth specification]: https://WebBluetoothCG.github.io/web-bluetooth
 [Web Bluetooth Testing]:
 https://docs.google.com/document/d/1Nhv_oVDCodd1pEH_jj9k8gF4rPGb_84VYaZ9IG8M_WY/
 [#485]: https://github.com/WebBluetoothCG/web-bluetooth/issues/485
 [Testing Web Bluetooth specification]:
 https://WebBluetoothCG.github.io/web-bluetooth/tests.html
 
@@ -110,9 +111,9 @@ file an issue with the implementor's bug
 ## Chromium
 
 Mailing list: web-bluetooth@chromium.org
 
 Bug tracker: [Blink>Bluetooth]
 
 * [Web Bluetooth Service README]
 
-[Blink>Bluetooth]: https://bugs.chromium.org/p/chromium/issues/list?q=component%3ABlink%3EBluetooth&can=2
\ No newline at end of file
+[Blink>Bluetooth]: https://bugs.chromium.org/p/chromium/issues/list?q=component%3ABlink%3EBluetooth&can=2
--- a/testing/web-platform/tests/bluetooth/adapter/adapter-absent-getAvailability.https.window.js
+++ b/testing/web-platform/tests/bluetooth/adapter/adapter-absent-getAvailability.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'getAvailability() resolves with false if the system does ' +
     'not have an adapter.';
 
 bluetooth_test(async () => {
   await navigator.bluetooth.test.simulateCentral({state: 'absent'});
   let availability = await navigator.bluetooth.getAvailability();
   assert_false(
--- a/testing/web-platform/tests/bluetooth/adapter/adapter-added-getAvailability.https.window.js
+++ b/testing/web-platform/tests/bluetooth/adapter/adapter-added-getAvailability.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'getAvailability() resolves with true after adapter is ' +
     'inserted into a system with a platform that supports Bluetooth LE.';
 
 bluetooth_test(async () => {
   const fake_central =
       await navigator.bluetooth.test.simulateCentral({state: 'absent'});
   let availability = await navigator.bluetooth.getAvailability();
--- a/testing/web-platform/tests/bluetooth/adapter/adapter-powered-off-getAvailability.https.window.js
+++ b/testing/web-platform/tests/bluetooth/adapter/adapter-powered-off-getAvailability.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'getAvailability() resolves with true if the Bluetooth ' +
     'radio is powered off, but the platform that supports Bluetooth LE.';
 
 bluetooth_test(async () => {
   await navigator.bluetooth.test.simulateCentral({state: 'powered-off'});
   let availability = await navigator.bluetooth.getAvailability();
   assert_true(
--- a/testing/web-platform/tests/bluetooth/adapter/adapter-powered-on-getAvailability.https.window.js
+++ b/testing/web-platform/tests/bluetooth/adapter/adapter-powered-on-getAvailability.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'getAvailability() resolves with true if the Bluetooth ' +
     'radio is powered on and the platform supports Bluetooth LE.';
 
 bluetooth_test(async () => {
   await navigator.bluetooth.test.simulateCentral({state: 'powered-on'});
   let availability = await navigator.bluetooth.getAvailability();
   assert_true(
--- a/testing/web-platform/tests/bluetooth/adapter/adapter-powered-on-off-on-getAvailability.https.window.js
+++ b/testing/web-platform/tests/bluetooth/adapter/adapter-powered-on-off-on-getAvailability.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'getAvailability() is not affected by the powered state of ' +
     'the adapter.';
 
 bluetooth_test(async () => {
   const fake_central =
       await navigator.bluetooth.test.simulateCentral({state: 'powered-on'});
   {
--- a/testing/web-platform/tests/bluetooth/adapter/adapter-removed-getAvailability.https.window.js
+++ b/testing/web-platform/tests/bluetooth/adapter/adapter-removed-getAvailability.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'getAvailability() resolves with false after the powered ' +
     'on adapter is removed.';
 
 bluetooth_test(async () => {
   const fake_central =
       await navigator.bluetooth.test.simulateCentral({state: 'powered-on'});
   let availability = await navigator.bluetooth.getAvailability();
--- a/testing/web-platform/tests/bluetooth/adapter/cross-origin-iframe-getAvailability.sub.https.window.js
+++ b/testing/web-platform/tests/bluetooth/adapter/cross-origin-iframe-getAvailability.sub.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'getAvailability() resolves with false if called from a ' +
     'unique origin';
 const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
     '/bluetooth/resources/health-thermometer-iframe.html'
 let iframe = document.createElement('iframe');
 
 bluetooth_test(async () => {
--- a/testing/web-platform/tests/bluetooth/characteristic/characteristicProperties.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/characteristicProperties.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'HeartRate device properties';
 
 bluetooth_test(async () => {
   const {service} = await getHealthThermometerService()
   const [temperature_measurement, measurement_interval] = await Promise.all([
     service.getCharacteristic('temperature_measurement'),
     service.getCharacteristic('measurement_interval')
--- a/testing/web-platform/tests/bluetooth/characteristic/getDescriptor/gen-characteristic-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/getDescriptor/gen-characteristic-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
 const expected = new DOMException(
     'GATT Characteristic no longer exists.', 'InvalidStateError');
 let fake_peripheral, characteristic, fake_characteristic;
 
 bluetooth_test(
--- a/testing/web-platform/tests/bluetooth/characteristic/getDescriptor/gen-descriptor-get-same-object.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/getDescriptor/gen-descriptor-get-same-object.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Calls to getDescriptor should return the same object.';
 let characteristic;
 
 bluetooth_test(
     () => getMeasurementIntervalCharacteristic()
               .then(_ => ({characteristic} = _))
--- a/testing/web-platform/tests/bluetooth/characteristic/getDescriptor/gen-service-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/getDescriptor/gen-service-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 // TODO(https://crbug.com/672127) Use this test case to test the rest of
 // characteristic functions.
 'use strict';
 const test_desc = 'Service is removed. Reject with InvalidStateError.';
 const expected =
     new DOMException('GATT Service no longer exists.', 'InvalidStateError');
 let characteristic, fake_peripheral, fake_service;
--- a/testing/web-platform/tests/bluetooth/characteristic/getDescriptors/gen-characteristic-is-removed-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/getDescriptors/gen-characteristic-is-removed-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
 const expected = new DOMException(
     'GATT Characteristic no longer exists.', 'InvalidStateError');
 let fake_peripheral, characteristic, fake_characteristic;
 
 bluetooth_test(
--- a/testing/web-platform/tests/bluetooth/characteristic/getDescriptors/gen-characteristic-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/getDescriptors/gen-characteristic-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
 const expected = new DOMException(
     'GATT Characteristic no longer exists.', 'InvalidStateError');
 let fake_peripheral, characteristic, fake_characteristic;
 
 bluetooth_test(
--- a/testing/web-platform/tests/bluetooth/characteristic/getDescriptors/gen-descriptor-get-same-object.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/getDescriptors/gen-descriptor-get-same-object.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Calls to getDescriptors should return the same object.';
 let characteristic;
 
 bluetooth_test(
     () => getMeasurementIntervalCharacteristic()
               .then(_ => ({characteristic} = _))
--- a/testing/web-platform/tests/bluetooth/characteristic/getDescriptors/gen-service-is-removed-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/getDescriptors/gen-service-is-removed-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 // TODO(https://crbug.com/672127) Use this test case to test the rest of
 // characteristic functions.
 'use strict';
 const test_desc = 'Service is removed. Reject with InvalidStateError.';
 const expected =
     new DOMException('GATT Service no longer exists.', 'InvalidStateError');
 let characteristic, fake_peripheral, fake_service;
--- a/testing/web-platform/tests/bluetooth/characteristic/getDescriptors/gen-service-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/getDescriptors/gen-service-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 // TODO(https://crbug.com/672127) Use this test case to test the rest of
 // characteristic functions.
 'use strict';
 const test_desc = 'Service is removed. Reject with InvalidStateError.';
 const expected =
     new DOMException('GATT Service no longer exists.', 'InvalidStateError');
 let characteristic, fake_peripheral, fake_service;
--- a/testing/web-platform/tests/bluetooth/characteristic/notifications/characteristic-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/notifications/characteristic-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'Characteristic is removed. Reject with InvalidStateError.';
 const expected = new DOMException(
     'GATT Characteristic no longer exists.', 'InvalidStateError');
 
 bluetooth_test(async () => {
   const {characteristic, fake_characteristic} =
       await getMeasurementIntervalCharacteristic();
--- a/testing/web-platform/tests/bluetooth/characteristic/notifications/service-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/notifications/service-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'Service is removed. Reject with InvalidStateError.';
 const expected =
     new DOMException('GATT Service no longer exists.', 'InvalidStateError');
 
 bluetooth_test(async () => {
   const {characteristic, fake_peripheral, fake_service} =
       await getMeasurementIntervalCharacteristic();
--- a/testing/web-platform/tests/bluetooth/characteristic/readValue/add-multiple-event-listeners.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/readValue/add-multiple-event-listeners.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'Add multiple event listeners then readValue().';
 
 bluetooth_test(async () => {
   const {characteristic, fake_characteristic} =
       await getMeasurementIntervalCharacteristic();
   await fake_characteristic.setNextReadResponse(GATT_SUCCESS, [0, 1, 2]);
 
--- a/testing/web-platform/tests/bluetooth/characteristic/readValue/characteristic-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/readValue/characteristic-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
 const expected = new DOMException(
     'GATT Characteristic no longer exists.', 'InvalidStateError');
 
 bluetooth_test(async () => {
   const {characteristic, fake_characteristic} =
       await getMeasurementIntervalCharacteristic();
--- a/testing/web-platform/tests/bluetooth/characteristic/readValue/event-is-fired.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/readValue/event-is-fired.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'Reading a characteristic should fire an event.';
 
 bluetooth_test(async () => {
   const {characteristic, fake_characteristic} =
       await getMeasurementIntervalCharacteristic();
   await fake_characteristic.setNextReadResponse(GATT_SUCCESS, [0, 1, 2]);
 
--- a/testing/web-platform/tests/bluetooth/characteristic/readValue/gen-characteristic-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/readValue/gen-characteristic-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
 const expected = new DOMException(
     'GATT Characteristic no longer exists.', 'InvalidStateError');
 let fake_peripheral, characteristic, fake_characteristic;
 
 bluetooth_test(
--- a/testing/web-platform/tests/bluetooth/characteristic/readValue/read-succeeds.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/readValue/read-succeeds.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'A read request succeeds and returns the characteristic\'s ' +
     'value.';
 const EXPECTED_VALUE = [0, 1, 2];
 
 bluetooth_test(async () => {
   const {characteristic, fake_characteristic} =
       await getMeasurementIntervalCharacteristic();
--- a/testing/web-platform/tests/bluetooth/characteristic/readValue/read-updates-value.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/readValue/read-updates-value.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 const test_desc = 'Succesful read should update characteristic.value';
 const EXPECTED_VALUE = [0, 1, 2];
 
 bluetooth_test(async () => {
   const {characteristic, fake_characteristic} =
       await getMeasurementIntervalCharacteristic();
   assert_equals(characteristic.value, null);
 
--- a/testing/web-platform/tests/bluetooth/characteristic/readValue/service-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/readValue/service-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'Service gets removed. Reject with InvalidStateError.';
 const expected =
     new DOMException('GATT Service no longer exists.', 'InvalidStateError');
 
 bluetooth_test(async () => {
   const {characteristic, fake_peripheral, fake_service} =
       await getMeasurementIntervalCharacteristic();
--- a/testing/web-platform/tests/bluetooth/characteristic/service-same-from-2-characteristics.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/service-same-from-2-characteristics.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'Same parent service returned from multiple characteristics.';
 
 bluetooth_test(async () => {
   const {service} = await getHealthThermometerService();
   const characteristics = await Promise.all([
     service.getCharacteristic('measurement_interval'),
     service.getCharacteristic('temperature_measurement')
--- a/testing/web-platform/tests/bluetooth/characteristic/service-same-object.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/service-same-object.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = '[SameObject] test for BluetoothRemoteGATTCharacteristic ' +
     'service.';
 
 bluetooth_test(async () => {
   const {characteristic} = await getMeasurementIntervalCharacteristic();
   assert_equals(characteristic.service, characteristic.service);
 }, test_desc);
--- a/testing/web-platform/tests/bluetooth/characteristic/startNotifications/gen-characteristic-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/startNotifications/gen-characteristic-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
 const expected = new DOMException(
     'GATT Characteristic no longer exists.', 'InvalidStateError');
 let fake_peripheral, characteristic, fake_characteristic;
 
 bluetooth_test(
--- a/testing/web-platform/tests/bluetooth/characteristic/writeValue/buffer-is-detached.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/writeValue/buffer-is-detached.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'writeValue() fails when passed a detached buffer';
 
 function detachBuffer(buffer) {
   window.postMessage('', '*', [buffer]);
 }
 
 bluetooth_test(async (t) => {
--- a/testing/web-platform/tests/bluetooth/characteristic/writeValue/characteristic-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/writeValue/characteristic-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
 const expected = new DOMException(
     'GATT Characteristic no longer exists.', 'InvalidStateError');
 
 bluetooth_test(async () => {
   const {characteristic, fake_characteristic} =
       await getMeasurementIntervalCharacteristic();
--- a/testing/web-platform/tests/bluetooth/characteristic/writeValue/gen-characteristic-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/writeValue/gen-characteristic-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
 const expected = new DOMException(
     'GATT Characteristic no longer exists.', 'InvalidStateError');
 let fake_peripheral, characteristic, fake_characteristic;
 
 bluetooth_test(
--- a/testing/web-platform/tests/bluetooth/characteristic/writeValue/service-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/writeValue/service-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'Service gets removed. Reject with InvalidStateError.';
 const expected =
     new DOMException('GATT Service no longer exists.', 'InvalidStateError');
 
 bluetooth_test(async () => {
   const {characteristic, fake_peripheral, fake_service} =
       await getMeasurementIntervalCharacteristic();
--- a/testing/web-platform/tests/bluetooth/characteristic/writeValue/write-succeeds.https.window.js
+++ b/testing/web-platform/tests/bluetooth/characteristic/writeValue/write-succeeds.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'A regular write request to a writable characteristic ' +
     'should succeed.';
 
 bluetooth_test(async () => {
   const {characteristic, fake_characteristic} =
       await getMeasurementIntervalCharacteristic();
 
--- a/testing/web-platform/tests/bluetooth/descriptor/readValue/gen-service-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/descriptor/readValue/gen-service-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Service gets removed. Reject with InvalidStateError.';
 const expected =
     new DOMException('GATT Service no longer exists.', 'InvalidStateError');
 let descriptor, fake_peripheral, fake_service;
 
 bluetooth_test(
--- a/testing/web-platform/tests/bluetooth/descriptor/readValue/read-succeeds.https.window.js
+++ b/testing/web-platform/tests/bluetooth/descriptor/readValue/read-succeeds.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = `A read request succeeds and returns the descriptor's value.`;
 
 bluetooth_test(async () => {
   const {descriptor, fake_descriptor} = await getUserDescriptionDescriptor();
 
   const EXPECTED_VALUE = [0, 1, 2];
   await fake_descriptor.setNextReadResponse(GATT_SUCCESS, EXPECTED_VALUE);
--- a/testing/web-platform/tests/bluetooth/descriptor/writeValue/buffer-is-detached.https.window.js
+++ b/testing/web-platform/tests/bluetooth/descriptor/writeValue/buffer-is-detached.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'writeValue() fails when passed a detached buffer';
 
 function detachBuffer(buffer) {
   window.postMessage('', '*', [buffer]);
 }
 
 bluetooth_test(async (t) => {
--- a/testing/web-platform/tests/bluetooth/descriptor/writeValue/gen-service-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/descriptor/writeValue/gen-service-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Service gets removed. Reject with InvalidStateError.';
 const expected =
     new DOMException('GATT Service no longer exists.', 'InvalidStateError');
 let descriptor, fake_peripheral, fake_service;
 
 bluetooth_test(
--- 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
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.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');
 
--- 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
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.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.
--- 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
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.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;
--- 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
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.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();
 
--- a/testing/web-platform/tests/bluetooth/getDevices/granted-devices-with-services.https.window.js
+++ b/testing/web-platform/tests/bluetooth/getDevices/granted-devices-with-services.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'getDevices() resolves with permitted devices that can be ' +
     'GATT connected to.';
 
 bluetooth_test(async () => {
   // Set up two connectable Bluetooth devices with their services discovered.
   // One device is a Health Thermometer device with the 'health_thermometer'
   // service while the other is a Heart Rate device with the 'heart_rate'
@@ -63,9 +64,9 @@ bluetooth_test(async () => {
         assert_promise_rejects_with_message(
             devices[0].gatt.getPrimaryService('health_thermometer'),
             {name: 'SecurityError'});
       }
     }
   } catch (err) {
     assert_unreached(`${err.name}: ${err.message}`);
   }
-}, test_desc);
\ No newline at end of file
+}, test_desc);
--- a/testing/web-platform/tests/bluetooth/getDevices/no-granted-devices.https.window.js
+++ b/testing/web-platform/tests/bluetooth/getDevices/no-granted-devices.https.window.js
@@ -1,14 +1,15 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'getDevices() resolves with empty array if no device ' +
     'permissions have been granted.';
 
 bluetooth_test(async () => {
   await navigator.bluetooth.test.simulateCentral({state: 'powered-on'});
   let devices = await navigator.bluetooth.getDevices();
 
   assert_equals(
       0, devices.length, 'getDevices() should resolve with an empty array');
-}, test_desc);
\ No newline at end of file
+}, test_desc);
--- a/testing/web-platform/tests/bluetooth/getDevices/returns-same-bluetooth-device-object.https.window.js
+++ b/testing/web-platform/tests/bluetooth/getDevices/returns-same-bluetooth-device-object.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 'use strict';
 const test_desc = 'multiple calls to getDevices() resolves with the same' +
     'BluetoothDevice objects for each granted Bluetooth device.';
 
 bluetooth_test(async () => {
   await getConnectedHealthThermometerDevice();
   let firstDevices = await navigator.bluetooth.getDevices();
   assert_equals(
@@ -14,9 +15,9 @@ bluetooth_test(async () => {
   let secondDevices = await navigator.bluetooth.getDevices();
   assert_equals(
       secondDevices.length, 1,
       'getDevices() should return the granted device.');
   assert_equals(
       firstDevices[0], secondDevices[0],
       'getDevices() should produce the same BluetoothDevice objects for a ' +
           'given Bluetooth device.');
-}, test_desc);
\ No newline at end of file
+}, test_desc);
--- a/testing/web-platform/tests/bluetooth/idl/idl-BluetoothDevice.https.html
+++ b/testing/web-platform/tests/bluetooth/idl/idl-BluetoothDevice.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc_idl = 'BluetoothDevice IDL test.';
 
 test(() => {
   assert_throws_js(
       TypeError, () => new BluetoothDevice(),
       'the constructor should not be callable with "new"');
--- a/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Device with empty name and no UUIDs nearby. Should be ' +
     'found if acceptAllDevices is true.';
 
 bluetooth_test(
     () =>
         setUpPreconnectedDevice({name: ''})
--- a/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/device-with-name.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/device-with-name.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 const test_desc =
     'A device with name and no UUIDs nearby. Should be found if ' +
     'acceptAllDevices is true.';
 const name = 'LE Device';
 
 bluetooth_test(
     () =>
--- a/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/optional-services-missing.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/optional-services-missing.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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',
--- a/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/optional-services-present.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/acceptAllDevices/optional-services-present.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'requestDevice called with acceptAllDevices: true and with ' +
     'optionalServices. Should get access to services.';
 
 bluetooth_test(
     () => getTwoHealthThermometerServicesDevice()
               .then(() => requestDeviceWithTrustedClick({
--- a/testing/web-platform/tests/bluetooth/requestDevice/blocklisted-service-in-filter.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/blocklisted-service-in-filter.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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. ' +
         'https://goo.gl/4NeimX',
     'SecurityError');
--- a/testing/web-platform/tests/bluetooth/requestDevice/blocklisted-service-in-optionalServices.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/blocklisted-service-in-optionalServices.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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',
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/device-name-longer-than-29-bytes.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/device-name-longer-than-29-bytes.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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(
     () => setUpPreconnectedDevice({name: DEVICE_NAME})
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-filter.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-filter.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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),
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-filters-member.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-filters-member.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'An empty |filters| member should result in a TypeError';
 const expected = new DOMException(
     'Failed to execute \'requestDevice\' on ' +
         '\'Bluetooth\': \'filters\' member must be non-empty to find any devices.',
     new TypeError());
 
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-namePrefix.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-namePrefix.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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']}]},
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-services-member.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/empty-services-member.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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(
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/filters-xor-acceptAllDevices.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/filters-xor-acceptAllDevices.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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.',
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-name-unicode.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-name-unicode.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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());
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-name.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-name.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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);
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-namePrefix-unicode.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-namePrefix-unicode.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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());
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-namePrefix.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-namePrefix.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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);
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-name-unicode.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-name-unicode.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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(
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-name.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-name.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'A device name of 248 bytes is valid.';
 const DEVICE_NAME = 'a'.repeat(248);
 
 bluetooth_test(
     () => setUpPreconnectedDevice({name: DEVICE_NAME})
               .then(
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-namePrefix-unicode.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-namePrefix-unicode.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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(
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-namePrefix.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/max-length-namePrefix.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'A device namePrefix of 248 bytes is valid.';
 const DEVICE_NAME = 'a'.repeat(248);
 
 bluetooth_test(
     () => setUpPreconnectedDevice({name: DEVICE_NAME})
               .then(
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/no-arguments.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/no-arguments.https.html
@@ -1,15 +1,16 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharness-helpers.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'requestDevice() requires an argument.';
 const expected = new TypeError();
 
 promise_test(
     () => assert_promise_rejects_with_message(
         requestDeviceWithTrustedClick(), expected),
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-name.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-name.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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);
 
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-namePrefix.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-namePrefix.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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);
 
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-optionalServices-member.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-optionalServices-member.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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'],
--- a/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-services-member.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-services-member.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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 => {
--- a/testing/web-platform/tests/bluetooth/requestDevice/cross-origin-iframe.sub.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/cross-origin-iframe.sub.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <body>
 <script>
 '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');
--- a/testing/web-platform/tests/bluetooth/requestDevice/discovery-succeeds.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/discovery-succeeds.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Discover a device using alias, name, or UUID.';
 
 bluetooth_test(
     () => getConnectedHealthThermometerDevice()
               // Chrome will always close the previous chooser in the process of
               // handling a user gesture for the next request, so these need to
--- a/testing/web-platform/tests/bluetooth/requestDevice/doesnt-consume-user-gesture.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/doesnt-consume-user-gesture.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'requestDevice calls do not consume user gestures.';
 
 bluetooth_test(
     () => setUpHealthThermometerAndHeartRateDevices().then(
         () => callWithTrustedClick(() => {
           let first = navigator.bluetooth.requestDevice(
--- a/testing/web-platform/tests/bluetooth/requestDevice/filter-matches.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/filter-matches.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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 test_specs = [
--- a/testing/web-platform/tests/bluetooth/requestDevice/le-not-supported.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/le-not-supported.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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(
--- a/testing/web-platform/tests/bluetooth/requestDevice/name-empty-device-from-name-empty-filter.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/name-empty-device-from-name-empty-filter.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'An empty name device can be obtained by empty name filter.'
 
 bluetooth_test(
     () =>
         setUpPreconnectedDevice({name: ''})
             .then(() => requestDeviceWithTrustedClick({filters: [{name: ''}]}))
--- a/testing/web-platform/tests/bluetooth/requestDevice/not-processing-user-gesture.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/not-processing-user-gesture.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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');
 
--- a/testing/web-platform/tests/bluetooth/requestDevice/radio-not-present.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/radio-not-present.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Reject with NotFoundError if there is no BT radio present.';
 const expected =
     new DOMException('Bluetooth adapter not available.', 'NotFoundError');
 
 bluetooth_test(
     () => navigator.bluetooth.test.simulateCentral({state: 'absent'})
--- a/testing/web-platform/tests/bluetooth/requestDevice/request-from-iframe.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/request-from-iframe.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 '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'));
 }
 
--- a/testing/web-platform/tests/bluetooth/requestDevice/request-from-sandboxed-iframe.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/request-from-sandboxed-iframe.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <body>
 <script>
 'use strict';
 const test_desc = 'Request device from a unique origin. ' +
     'Should reject with SecurityError.';
 const expected = 'SecurityError: requestDevice() called from cross-origin ' +
     'iframe.';
 
--- a/testing/web-platform/tests/bluetooth/requestDevice/same-device.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/same-device.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Returned device should always be the same.';
 let devices = [];
 let push = device => devices.push(device);
 
 bluetooth_test(
     () => setUpHealthThermometerAndHeartRateDevices()
--- a/testing/web-platform/tests/bluetooth/requestDevice/single-filter-single-service.https.html
+++ b/testing/web-platform/tests/bluetooth/requestDevice/single-filter-single-service.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Simple filter selects matching device.';
 
 bluetooth_test(
     () => setUpHealthThermometerAndHeartRateDevices()
               .then(
                   () => requestDeviceWithTrustedClick(
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/resources/bluetooth-fake-devices.js
@@ -0,0 +1,991 @@
+'use strict';
+
+/* Bluetooth Constants */
+
+/**
+ * HCI Error Codes.
+ * Used for simulateGATT{Dis}ConnectionResponse. For a complete list of
+ * possible error codes see BT 4.2 Vol 2 Part D 1.3 List Of Error Codes.
+ */
+const HCI_SUCCESS = 0x0000;
+const HCI_CONNECTION_TIMEOUT = 0x0008;
+
+/**
+ * GATT Error codes.
+ * Used for GATT operations responses. BT 4.2 Vol 3 Part F 3.4.1.1 Error
+ * Response
+ */
+const GATT_SUCCESS = 0x0000;
+const GATT_INVALID_HANDLE = 0x0001;
+
+/* Bluetooth UUID Constants */
+
+/* Service UUIDs */
+var blocklist_test_service_uuid = '611c954a-263b-4f4a-aab6-01ddb953f985';
+var request_disconnection_service_uuid = '01d7d889-7451-419f-aeb8-d65e7b9277af';
+
+/* Characteristic UUIDs */
+var blocklist_exclude_reads_characteristic_uuid =
+    'bad1c9a2-9a5b-4015-8b60-1579bbbf2135';
+var request_disconnection_characteristic_uuid =
+    '01d7d88a-7451-419f-aeb8-d65e7b9277af';
+
+/* Descriptor UUIDs */
+var blocklist_test_descriptor_uuid = 'bad2ddcf-60db-45cd-bef9-fd72b153cf7c';
+var blocklist_exclude_reads_descriptor_uuid =
+    'bad3ec61-3cc3-4954-9702-7977df514114';
+
+/**
+ * Helper objects that associate Bluetooth names, aliases, and UUIDs. These are
+ * useful for tests that check that the same result is produces when using all
+ * three methods of referring to a Bluetooth UUID.
+ */
+var generic_access = {
+  alias: 0x1800,
+  name: 'generic_access',
+  uuid: '00001800-0000-1000-8000-00805f9b34fb'
+};
+var device_name = {
+  alias: 0x2a00,
+  name: 'gap.device_name',
+  uuid: '00002a00-0000-1000-8000-00805f9b34fb'
+};
+var reconnection_address = {
+  alias: 0x2a03,
+  name: 'gap.reconnection_address',
+  uuid: '00002a03-0000-1000-8000-00805f9b34fb'
+};
+var heart_rate = {
+  alias: 0x180d,
+  name: 'heart_rate',
+  uuid: '0000180d-0000-1000-8000-00805f9b34fb'
+};
+var health_thermometer = {
+  alias: 0x1809,
+  name: 'health_thermometer',
+  uuid: '00001809-0000-1000-8000-00805f9b34fb'
+};
+var body_sensor_location = {
+  alias: 0x2a38,
+  name: 'body_sensor_location',
+  uuid: '00002a38-0000-1000-8000-00805f9b34fb'
+};
+var glucose = {
+  alias: 0x1808,
+  name: 'glucose',
+  uuid: '00001808-0000-1000-8000-00805f9b34fb'
+};
+var battery_service = {
+  alias: 0x180f,
+  name: 'battery_service',
+  uuid: '0000180f-0000-1000-8000-00805f9b34fb'
+};
+var battery_level = {
+  alias: 0x2A19,
+  name: 'battery_level',
+  uuid: '00002a19-0000-1000-8000-00805f9b34fb'
+};
+var user_description = {
+  alias: 0x2901,
+  name: 'gatt.characteristic_user_description',
+  uuid: '00002901-0000-1000-8000-00805f9b34fb'
+};
+var client_characteristic_configuration = {
+  alias: 0x2902,
+  name: 'gatt.client_characteristic_configuration',
+  uuid: '00002902-0000-1000-8000-00805f9b34fb'
+};
+var measurement_interval = {
+  alias: 0x2a21,
+  name: 'measurement_interval',
+  uuid: '00002a21-0000-1000-8000-00805f9b34fb'
+};
+
+/**
+ * An advertisement packet object that simulates a device.
+ * @type {ScanResult}
+ */
+const health_thermometer_ad_packet = {
+  deviceAddress: '09:09:09:09:09:09',
+  rssi: -10,
+  scanRecord: {
+    name: 'Health Thermometer',
+    uuids: [health_thermometer.uuid],
+  },
+};
+
+/** Bluetooth Helpers */
+
+/**
+ * Helper class to create a BluetoothCharacteristicProperties object using an
+ * array of strings corresponding to the property bit to set.
+ */
+class TestCharacteristicProperties {
+  /** @param {Array<string>} properties */
+  constructor(properties) {
+    this.broadcast = false;
+    this.read = false;
+    this.writeWithoutResponse = false;
+    this.write = false;
+    this.notify = false;
+    this.indicate = false;
+    this.authenticatedSignedWrites = false;
+    this.reliableWrite = false;
+    this.writableAuxiliaries = false;
+
+    properties.forEach(val => {
+      if (this.hasOwnProperty(val))
+        this[val] = true;
+      else
+        throw `Invalid member '${val}'`;
+    });
+  }
+}
+
+/**
+ * Produces an array of BluetoothLEScanFilterInit objects containing the list of
+ * services in |services| and various permutations of the other
+ * BluetoothLEScanFilterInit properties. This method is used to test that the
+ * |services| are valid so the other properties do not matter.
+ * @param {BluetoothServiceUUID} services
+ * @returns {Array<RequestDeviceOptions>} A list of options containing
+ *     |services| and various permutations of other options.
+ */
+function generateRequestDeviceArgsWithServices(services = ['heart_rate']) {
+  return [
+    {filters: [{services: services}]},
+    {filters: [{services: services, name: 'Name'}]},
+    {filters: [{services: services, namePrefix: 'Pre'}]},
+    {filters: [{services: services, name: 'Name', namePrefix: 'Pre'}]},
+    {filters: [{services: services}], optionalServices: ['heart_rate']}, {
+      filters: [{services: services, name: 'Name'}],
+      optionalServices: ['heart_rate']
+    },
+    {
+      filters: [{services: services, namePrefix: 'Pre'}],
+      optionalServices: ['heart_rate']
+    },
+    {
+      filters: [{services: services, name: 'Name', namePrefix: 'Pre'}],
+      optionalServices: ['heart_rate']
+    }
+  ];
+}
+
+/**
+ * Causes |fake_peripheral| to disconnect and returns a promise that resolves
+ * once `gattserverdisconnected` has been fired on |device|.
+ * @param {BluetoothDevice} device The device to check if the
+ *     `gattserverdisconnected` promise was fired.
+ * @param {FakePeripheral} fake_peripheral The device fake that represents
+ *     |device|.
+ * @returns {Promise<Array<Object>>} A promise that resolves when the device has
+ *     successfully disconnected.
+ */
+function simulateGATTDisconnectionAndWait(device, fake_peripheral) {
+  return Promise.all([
+    eventPromise(device, 'gattserverdisconnected'),
+    fake_peripheral.simulateGATTDisconnection(),
+  ]);
+}
+
+/**
+ * Returns an array containing two FakePeripherals corresponding
+ * to the simulated devices.
+ * @returns {Promise<Array<FakePeripheral>>} The fake devices are initialized as
+ *     Health Thermometer and Heart Rate devices.
+ */
+function setUpHealthThermometerAndHeartRateDevices() {
+  return navigator.bluetooth.test.simulateCentral({state: 'powered-on'})
+      .then(fake_central => Promise.all([
+        fake_central.simulatePreconnectedPeripheral({
+          address: '09:09:09:09:09:09',
+          name: 'Health Thermometer',
+          knownServiceUUIDs: ['generic_access', 'health_thermometer'],
+        }),
+        fake_central.simulatePreconnectedPeripheral({
+          address: '08:08:08:08:08:08',
+          name: 'Heart Rate',
+          knownServiceUUIDs: ['generic_access', 'heart_rate'],
+        })
+      ]));
+}
+
+/**
+ * Simulates a pre-connected device with |address|, |name| and
+ * |knownServiceUUIDs|.
+ * @param {string} address The device MAC address.
+ * @param {string} name The device name.
+ * @param {Array<string>} knownServiceUUIDs An array of GATT service UUIDs to
+ *     set up the fake with.
+ * @returns {Promise<FakePeripheral>} The fake devices are initialized with the
+ *     parameter values.
+ */
+function setUpPreconnectedDevice({
+  address = '00:00:00:00:00:00',
+  name = 'LE Device',
+  knownServiceUUIDs = []
+}) {
+  return navigator.bluetooth.test.simulateCentral({state: 'powered-on'})
+      .then(fake_central => fake_central.simulatePreconnectedPeripheral({
+        address: address,
+        name: name,
+        knownServiceUUIDs: knownServiceUUIDs,
+      }));
+}
+
+/** Blocklisted GATT Device Helper Methods */
+
+/**
+ * Returns an object containing a BluetoothDevice discovered using |options|,
+ * its corresponding FakePeripheral and FakeRemoteGATTServices.
+ * The simulated device is called 'Blocklist Device' and it has one known
+ * service UUID |blocklist_test_service_uuid|. The |blocklist_test_service_uuid|
+ * service contains two characteristics:
+ *   - |blocklist_exclude_reads_characteristic_uuid| (read, write)
+ *   - 'gap.peripheral_privacy_flag' (read, write)
+ * The 'gap.peripheral_privacy_flag' characteristic contains three descriptors:
+ *   - |blocklist_test_descriptor_uuid|
+ *   - |blocklist_exclude_reads_descriptor_uuid|
+ *   - 'gatt.client_characteristic_configuration'
+ * These are special UUIDs that have been added to the blocklist found at
+ * https://github.com/WebBluetoothCG/registries/blob/master/gatt_blocklist.txt
+ * There are also test UUIDs that have been added to the test environment which
+ * other implementations should add as test UUIDs as well.
+ * The device has been connected to and its attributes are ready to be
+ * discovered.
+ * @returns {Promise<{device: BluetoothDevice, fake_peripheral: FakePeripheral,
+ *     fake_blocklist_test_service: FakeRemoteGATTService,
+ *     fake_blocklist_exclude_reads_characteristic:
+ *         FakeRemoteGATTCharacteristic,
+ *     fake_blocklist_exclude_writes_characteristic:
+ *         FakeRemoteGATTCharacteristic,
+ *     fake_blocklist_descriptor: FakeRemoteGATTDescriptor,
+ *     fake_blocklist_exclude_reads_descriptor: FakeRemoteGATTDescriptor,
+ *     fake_blocklist_exclude_writes_descriptor: FakeRemoteGATTDescriptor}>} An
+ *         object containing the BluetoothDevice object and its corresponding
+ *         GATT fake objects.
+ */
+function getBlocklistDevice(options = {
+  filters: [{services: [blocklist_test_service_uuid]}]
+}) {
+  let device, fake_peripheral, fake_blocklist_test_service,
+      fake_blocklist_exclude_reads_characteristic,
+      fake_blocklist_exclude_writes_characteristic, fake_blocklist_descriptor,
+      fake_blocklist_exclude_reads_descriptor,
+      fake_blocklist_exclude_writes_descriptor;
+  return setUpPreconnectedDevice({
+           address: '11:11:11:11:11:11',
+           name: 'Blocklist Device',
+           knownServiceUUIDs: ['generic_access', blocklist_test_service_uuid],
+         })
+      .then(_ => fake_peripheral = _)
+      .then(() => requestDeviceWithTrustedClick(options))
+      .then(_ => device = _)
+      .then(() => fake_peripheral.setNextGATTConnectionResponse({
+        code: HCI_SUCCESS,
+      }))
+      .then(() => device.gatt.connect())
+      .then(() => fake_peripheral.addFakeService({
+        uuid: blocklist_test_service_uuid,
+      }))
+      .then(_ => fake_blocklist_test_service = _)
+      .then(() => fake_blocklist_test_service.addFakeCharacteristic({
+        uuid: blocklist_exclude_reads_characteristic_uuid,
+        properties: ['read', 'write'],
+      }))
+      .then(_ => fake_blocklist_exclude_reads_characteristic = _)
+      .then(() => fake_blocklist_test_service.addFakeCharacteristic({
+        uuid: 'gap.peripheral_privacy_flag',
+        properties: ['read', 'write'],
+      }))
+      .then(_ => fake_blocklist_exclude_writes_characteristic = _)
+      .then(
+          () => fake_blocklist_exclude_writes_characteristic.addFakeDescriptor(
+              {uuid: blocklist_test_descriptor_uuid}))
+      .then(_ => fake_blocklist_descriptor = _)
+      .then(
+          () => fake_blocklist_exclude_writes_characteristic.addFakeDescriptor(
+              {uuid: blocklist_exclude_reads_descriptor_uuid}))
+      .then(_ => fake_blocklist_exclude_reads_descriptor = _)
+      .then(
+          () => fake_blocklist_exclude_writes_characteristic.addFakeDescriptor(
+              {uuid: 'gatt.client_characteristic_configuration'}))
+      .then(_ => fake_blocklist_exclude_writes_descriptor = _)
+      .then(() => fake_peripheral.setNextGATTDiscoveryResponse({
+        code: HCI_SUCCESS,
+      }))
+      .then(() => ({
+              device,
+              fake_peripheral,
+              fake_blocklist_test_service,
+              fake_blocklist_exclude_reads_characteristic,
+              fake_blocklist_exclude_writes_characteristic,
+              fake_blocklist_descriptor,
+              fake_blocklist_exclude_reads_descriptor,
+              fake_blocklist_exclude_writes_descriptor,
+            }));
+}
+
+/**
+ * Returns an object containing a Blocklist Test BluetoothRemoveGattService and
+ * its corresponding FakeRemoteGATTService.
+ * @returns {Promise<{device: BluetoothDevice, fake_peripheral: FakePeripheral,
+ *     fake_blocklist_test_service: FakeRemoteGATTService,
+ *     fake_blocklist_exclude_reads_characteristic:
+ *         FakeRemoteGATTCharacteristic,
+ *     fake_blocklist_exclude_writes_characteristic:
+ *         FakeRemoteGATTCharacteristic,
+ *     fake_blocklist_descriptor: FakeRemoteGATTDescriptor,
+ *     fake_blocklist_exclude_reads_descriptor: FakeRemoteGATTDescriptor,
+ *     fake_blocklist_exclude_writes_descriptor: FakeRemoteGATTDescriptor,
+ *     service: BluetoothRemoteGATTService,
+ *     fake_service: FakeBluetoothRemoteGATTService}>} An object containing the
+ *         BluetoothDevice object and its corresponding GATT fake objects.
+ */
+function getBlocklistTestService() {
+  let result;
+  return getBlocklistDevice()
+      .then(_ => result = _)
+      .then(
+          () =>
+              result.device.gatt.getPrimaryService(blocklist_test_service_uuid))
+      .then(service => Object.assign(result, {
+        service,
+        fake_service: result.fake_blocklist_test_service,
+      }));
+}
+
+/**
+ * Returns an object containing a blocklisted BluetoothRemoteGATTCharacteristic
+ * that excludes reads and its corresponding FakeRemoteGATTCharacteristic.
+ * @returns {Promise<{device: BluetoothDevice, fake_peripheral: FakePeripheral,
+ *     fake_blocklist_test_service: FakeRemoteGATTService,
+ *     fake_blocklist_exclude_reads_characteristic:
+ *         FakeRemoteGATTCharacteristic,
+ *     fake_blocklist_exclude_writes_characteristic:
+ *         FakeRemoteGATTCharacteristic,
+ *     fake_blocklist_descriptor: FakeRemoteGATTDescriptor,
+ *     fake_blocklist_exclude_reads_descriptor: FakeRemoteGATTDescriptor,
+ *     fake_blocklist_exclude_writes_descriptor: FakeRemoteGATTDescriptor,
+ *     service: BluetoothRemoteGATTService,
+ *     fake_service: FakeBluetoothRemoteGATTService,
+ *     characteristic: BluetoothRemoteGATTCharacteristic,
+ *     fake_characteristic: FakeBluetoothRemoteGATTCharacteristic}>} An object
+ *         containing the BluetoothDevice object and its corresponding GATT fake
+ *         objects.
+ */
+function getBlocklistExcludeReadsCharacteristic() {
+  let result, fake_characteristic;
+  return getBlocklistTestService()
+      .then(_ => result = _)
+      .then(
+          () => result.service.getCharacteristic(
+              blocklist_exclude_reads_characteristic_uuid))
+      .then(characteristic => Object.assign(result, {
+        characteristic,
+        fake_characteristic: result.fake_blocklist_exclude_reads_characteristic
+      }));
+}
+
+/**
+ * Returns an object containing a blocklisted BluetoothRemoteGATTCharacteristic
+ * that excludes writes and its corresponding FakeRemoteGATTCharacteristic.
+ * @returns {Promise<{device: BluetoothDevice, fake_peripheral: FakePeripheral,
+ *     fake_blocklist_test_service: FakeRemoteGATTService,
+ *     fake_blocklist_exclude_reads_characteristic:
+ *         FakeRemoteGATTCharacteristic,
+ *     fake_blocklist_exclude_writes_characteristic:
+ *         FakeRemoteGATTCharacteristic,
+ *     fake_blocklist_descriptor: FakeRemoteGATTDescriptor,
+ *     fake_blocklist_exclude_reads_descriptor: FakeRemoteGATTDescriptor,
+ *     fake_blocklist_exclude_writes_descriptor: FakeRemoteGATTDescriptor,
+ *     service: BluetoothRemoteGATTService,
+ *     fake_service: FakeBluetoothRemoteGATTService,
+ *     characteristic: BluetoothRemoteGATTCharacteristic,
+ *     fake_characteristic: FakeBluetoothRemoteGATTCharacteristic}>} An object
+ *         containing the BluetoothDevice object and its corresponding GATT fake
+ *         objects.
+ */
+function getBlocklistExcludeWritesCharacteristic() {
+  let result, fake_characteristic;
+  return getBlocklistTestService()
+      .then(_ => result = _)
+      .then(
+          () => result.service.getCharacteristic('gap.peripheral_privacy_flag'))
+      .then(characteristic => Object.assign(result, {
+        characteristic,
+        fake_characteristic: result.fake_blocklist_exclude_writes_characteristic
+      }));
+}
+
+/**
+ * Returns an object containing a blocklisted BluetoothRemoteGATTDescriptor that
+ * excludes reads and its corresponding FakeRemoteGATTDescriptor.
+ * @returns {Promise<{device: BluetoothDevice, fake_peripheral: FakePeripheral,
+ *     fake_blocklist_test_service: FakeRemoteGATTService,
+ *     fake_blocklist_exclude_reads_characteristic:
+ *         FakeRemoteGATTCharacteristic,
+ *     fake_blocklist_exclude_writes_characteristic:
+ *         FakeRemoteGATTCharacteristic,
+ *     fake_blocklist_descriptor: FakeRemoteGATTDescriptor,
+ *     fake_blocklist_exclude_reads_descriptor: FakeRemoteGATTDescriptor,
+ *     fake_blocklist_exclude_writes_descriptor: FakeRemoteGATTDescriptor,
+ *     service: BluetoothRemoteGATTService,
+ *     fake_service: FakeBluetoothRemoteGATTService,
+ *     characteristic: BluetoothRemoteGATTCharacteristic,
+ *     fake_characteristic: FakeBluetoothRemoteGATTCharacteristic,
+ *     descriptor: BluetoothRemoteGATTDescriptor,
+ *     fake_descriptor: FakeBluetoothRemoteGATTDescriptor}>} An object
+ *         containing the BluetoothDevice object and its corresponding GATT fake
+ *         objects.
+ */
+function getBlocklistExcludeReadsDescriptor() {
+  let result;
+  return getBlocklistExcludeWritesCharacteristic()
+      .then(_ => result = _)
+      .then(
+          () => result.characteristic.getDescriptor(
+              blocklist_exclude_reads_descriptor_uuid))
+      .then(descriptor => Object.assign(result, {
+        descriptor,
+        fake_descriptor: result.fake_blocklist_exclude_reads_descriptor
+      }));
+}
+
+/**
+ * Returns an object containing a blocklisted BluetoothRemoteGATTDescriptor that
+ * excludes writes and its corresponding FakeRemoteGATTDescriptor.
+ * @returns {Promise<{device: BluetoothDevice, fake_peripheral: FakePeripheral,
+ *     fake_blocklist_test_service: FakeRemoteGATTService,
+ *     fake_blocklist_exclude_reads_characteristic:
+ *         FakeRemoteGATTCharacteristic,
+ *     fake_blocklist_exclude_writes_characteristic:
+ *         FakeRemoteGATTCharacteristic,
+ *     fake_blocklist_descriptor: FakeRemoteGATTDescriptor,
+ *     fake_blocklist_exclude_reads_descriptor: FakeRemoteGATTDescriptor,
+ *     fake_blocklist_exclude_writes_descriptor: FakeRemoteGATTDescriptor,
+ *     service: BluetoothRemoteGATTService,
+ *     fake_service: FakeBluetoothRemoteGATTService,
+ *     characteristic: BluetoothRemoteGATTCharacteristic,
+ *     fake_characteristic: FakeBluetoothRemoteGATTCharacteristic,
+ *     descriptor: BluetoothRemoteGATTDescriptor,
+ *     fake_descriptor: FakeBluetoothRemoteGATTDescriptor}>} An object
+ *         containing the BluetoothDevice object and its corresponding GATT fake
+ *         objects.
+ */
+function getBlocklistExcludeWritesDescriptor() {
+  let result;
+  return getBlocklistExcludeWritesCharacteristic()
+      .then(_ => result = _)
+      .then(
+          () => result.characteristic.getDescriptor(
+              'gatt.client_characteristic_configuration'))
+      .then(descriptor => Object.assign(result, {
+        descriptor: descriptor,
+        fake_descriptor: result.fake_blocklist_exclude_writes_descriptor,
+      }));
+}
+
+/** Bluetooth HID Device Helper Methods */
+
+/**
+ * Similar to getHealthThermometerDevice except the GATT discovery
+ * response has not been set yet so more attributes can still be added.
+ * TODO(crbug.com/719816): Add descriptors.
+ * @param {RequestDeviceOptions} options The options for requesting a Bluetooth
+ *     Device.
+ * @returns {device: BluetoothDevice, fake_peripheral: FakePeripheral} An object
+ *     containing a requested BluetoothDevice and its fake counter part.
+ */
+function getConnectedHIDDevice(options) {
+  let device, fake_peripheral;
+  return setUpPreconnectedDevice({
+           address: '10:10:10:10:10:10',
+           name: 'HID Device',
+           knownServiceUUIDs: [
+             'generic_access',
+             'device_information',
+             'human_interface_device',
+           ],
+         })
+      .then(_ => (fake_peripheral = _))
+      .then(() => requestDeviceWithTrustedClick(options))
+      .then(_ => (device = _))
+      .then(() => fake_peripheral.setNextGATTConnectionResponse({
+        code: HCI_SUCCESS,
+      }))
+      .then(() => device.gatt.connect())
+      .then(() => fake_peripheral.addFakeService({
+        uuid: 'generic_access',
+      }))
+      .then(() => fake_peripheral.addFakeService({
+        uuid: 'device_information',
+      }))
+      // Blocklisted Characteristic:
+      // https://github.com/WebBluetoothCG/registries/blob/master/gatt_blocklist.txt
+      .then(dev_info => dev_info.addFakeCharacteristic({
+        uuid: 'serial_number_string',
+        properties: ['read'],
+      }))
+      .then(() => fake_peripheral.addFakeService({
+        uuid: 'human_interface_device',
+      }))
+      .then(() => ({device, fake_peripheral}));
+}
+
+/**
+ * Returns a BluetoothDevice discovered using |options| and its
+ * corresponding FakePeripheral.
+ * The simulated device is called 'HID Device' it has three known service
+ * UUIDs: 'generic_access', 'device_information', 'human_interface_device'.
+ * The primary service with 'device_information' UUID has a characteristics
+ * with UUID 'serial_number_string'. The device has been connected to and its
+ * attributes are ready to be discovered.
+ * @param {RequestDeviceOptions} options The options for requesting a Bluetooth
+ *     Device.
+ * @returns {device: BluetoothDevice, fake_peripheral: FakePeripheral} An object
+ *     containing a requested BluetoothDevice and its fake counter part.
+ */
+function getHIDDevice(options) {
+  let device, fake_peripheral;
+  return getConnectedHIDDevice(options)
+      .then(_ => ({device, fake_peripheral} = _))
+      .then(() => fake_peripheral.setNextGATTDiscoveryResponse({
+        code: HCI_SUCCESS,
+      }))
+      .then(() => ({device, fake_peripheral}));
+}
+
+/** Health Thermometer Bluetooth Device Helper Methods */
+
+/**
+ * Returns a FakePeripheral that corresponds to a simulated pre-connected device
+ * called 'Health Thermometer'. The device has two known serviceUUIDs:
+ * 'generic_access' and 'health_thermometer'.
+ * @returns {FakePeripheral} The device fake initialized as a Health
+ *     Thermometer device.
+ */
+function setUpHealthThermometerDevice() {
+  return setUpPreconnectedDevice({
+    address: '09:09:09:09:09:09',
+    name: 'Health Thermometer',
+    knownServiceUUIDs: ['generic_access', 'health_thermometer'],
+  });
+}
+
+/**
+ * Returns the same fake peripheral as setUpHealthThermometerDevice() except
+ * that connecting to the peripheral will succeed.
+ * @returns {Promise<FakePeripheral>} The device fake initialized as a
+ *     connectable Health Thermometer device.
+ */
+function setUpConnectableHealthThermometerDevice() {
+  let fake_peripheral;
+  return setUpHealthThermometerDevice()
+      .then(_ => fake_peripheral = _)
+      .then(() => fake_peripheral.setNextGATTConnectionResponse({
+        code: HCI_SUCCESS,
+      }))
+      .then(() => fake_peripheral);
+}
+
+/**
+ * Populates a fake_peripheral with various fakes appropriate for a health
+ * thermometer. This resolves to an associative array composed of the fakes,
+ * including the |fake_peripheral|.
+ * @param {FakePeripheral} fake_peripheral The Bluetooth fake to populate GATT
+ *     services, characteristics, and descriptors on.
+ * @returns {Promise<{fake_peripheral: FakePeripheral,
+ *     fake_generic_access: FakeRemoteGATTService,
+ *     fake_health_thermometer: FakeRemoteGATTService,
+ *     fake_measurement_interval: FakeRemoteGATTCharacteristic,
+ *     fake_cccd: FakeRemoteGATTDescriptor,
+ *     fake_user_description: FakeRemoteGATTDescriptor,
+ *     fake_temperature_measurement: FakeRemoteGATTCharacteristic,
+ *     fake_temperature_type: FakeRemoteGATTCharacteristic}>} The FakePeripheral
+ * passed into this method along with the fake GATT services, characteristics,
+ *         and descriptors added to it.
+ */
+function populateHealthThermometerFakes(fake_peripheral) {
+  let fake_generic_access, fake_health_thermometer, fake_measurement_interval,
+      fake_user_description, fake_cccd, fake_temperature_measurement,
+      fake_temperature_type;
+  return fake_peripheral.addFakeService({uuid: 'generic_access'})
+      .then(_ => fake_generic_access = _)
+      .then(() => fake_peripheral.addFakeService({
+        uuid: 'health_thermometer',
+      }))
+      .then(_ => fake_health_thermometer = _)
+      .then(() => fake_health_thermometer.addFakeCharacteristic({
+        uuid: 'measurement_interval',
+        properties: ['read', 'write', 'indicate'],
+      }))
+      .then(_ => fake_measurement_interval = _)
+      .then(() => fake_measurement_interval.addFakeDescriptor({
+        uuid: 'gatt.characteristic_user_description',
+      }))
+      .then(_ => fake_user_description = _)
+      .then(() => fake_measurement_interval.addFakeDescriptor({
+        uuid: 'gatt.client_characteristic_configuration',
+      }))
+      .then(_ => fake_cccd = _)
+      .then(() => fake_health_thermometer.addFakeCharacteristic({
+        uuid: 'temperature_measurement',
+        properties: ['indicate'],
+      }))
+      .then(_ => fake_temperature_measurement = _)
+      .then(() => fake_health_thermometer.addFakeCharacteristic({
+        uuid: 'temperature_type',
+        properties: ['read'],
+      }))
+      .then(_ => fake_temperature_type = _)
+      .then(() => ({
+              fake_peripheral,
+              fake_generic_access,
+              fake_health_thermometer,
+              fake_measurement_interval,
+              fake_cccd,
+              fake_user_description,
+              fake_temperature_measurement,
+              fake_temperature_type,
+            }));
+}
+
+/**
+ * Returns the same device and fake peripheral as getHealthThermometerDevice()
+ * after another frame (an iframe we insert) discovered the device,
+ * connected to it and discovered its services.
+ * @param {RequestDeviceOptions} options The options for requesting a Bluetooth
+ *     Device.
+ * @returns {Promise<{device: BluetoothDevice, fakes: {
+ *         fake_peripheral: FakePeripheral,
+ *         fake_generic_access: FakeRemoteGATTService,
+ *         fake_health_thermometer: FakeRemoteGATTService,
+ *         fake_measurement_interval: FakeRemoteGATTCharacteristic,
+ *         fake_cccd: FakeRemoteGATTDescriptor,
+ *         fake_user_description: FakeRemoteGATTDescriptor,
+ *         fake_temperature_measurement: FakeRemoteGATTCharacteristic,
+ *         fake_temperature_type: FakeRemoteGATTCharacteristic}}>} An object
+ *         containing a requested BluetoothDevice and all of the GATT fake
+ *         objects.
+ */
+function getHealthThermometerDeviceWithServicesDiscovered(options) {
+  let device, fake_peripheral, fakes;
+  let iframe = document.createElement('iframe');
+  return setUpConnectableHealthThermometerDevice()
+      .then(_ => fake_peripheral = _)
+      .then(() => populateHealthThermometerFakes(fake_peripheral))
+      .then(_ => fakes = _)
+      .then(() => fake_peripheral.setNextGATTDiscoveryResponse({
+        code: HCI_SUCCESS,
+      }))
+      .then(
+          () => new Promise(resolve => {
+            let src = '/bluetooth/resources/health-thermometer-iframe.html';
+            // TODO(509038): Can be removed once LayoutTests/bluetooth/* that
+            // use health-thermometer-iframe.html have been moved to
+            // LayoutTests/external/wpt/bluetooth/*
+            if (window.location.pathname.includes('/LayoutTests/')) {
+              src =
+                  '../../../external/wpt/bluetooth/resources/health-thermometer-iframe.html';
+            }
+            iframe.src = src;
+            document.body.appendChild(iframe);
+            iframe.addEventListener('load', resolve);
+          }))
+      .then(() => new Promise((resolve, reject) => {
+              callWithTrustedClick(() => {
+                iframe.contentWindow.postMessage(
+                    {type: 'DiscoverServices', options: options}, '*');
+              });
+
+              function messageHandler(messageEvent) {
+                if (messageEvent.data == 'DiscoveryComplete') {
+                  window.removeEventListener('message', messageHandler);
+                  resolve();
+                } else {
+                  reject(new Error(`Unexpected message: ${messageEvent.data}`));
+                }
+              }
+              window.addEventListener('message', messageHandler);
+            }))
+      .then(() => requestDeviceWithTrustedClick(options))
+      .then(_ => device = _)
+      .then(device => device.gatt.connect())
+      .then(_ => Object.assign({device}, fakes));
+}
+
+/**
+ * Similar to getHealthThermometerDevice() except the device
+ * is not connected and thus its services have not been
+ * discovered.
+ * @param {RequestDeviceOptions} options The options for requesting a Bluetooth
+ *     Device.
+ * @returns {device: BluetoothDevice, fake_peripheral: FakePeripheral} An object
+ *     containing a requested BluetoothDevice and its fake counter part.
+ */
+function getDiscoveredHealthThermometerDevice(options = {
+  filters: [{services: ['health_thermometer']}]
+}) {
+  return setUpHealthThermometerDevice().then(fake_peripheral => {
+    return requestDeviceWithTrustedClick(options).then(
+        device => ({device: device, fake_peripheral: fake_peripheral}));
+  });
+}
+
+/**
+ * Similar to getHealthThermometerDevice() except the device has no services,
+ * characteristics, or descriptors.
+ * @param {RequestDeviceOptions} options The options for requesting a Bluetooth
+ *     Device.
+ * @returns {device: BluetoothDevice, fake_peripheral: FakePeripheral} An object
+ *     containing a requested BluetoothDevice and its fake counter part.
+ */
+function getEmptyHealthThermometerDevice(options) {
+  return getDiscoveredHealthThermometerDevice(options).then(
+      ({device, fake_peripheral}) => {
+        return fake_peripheral
+            .setNextGATTConnectionResponse({code: HCI_SUCCESS})
+            .then(() => device.gatt.connect())
+            .then(
+                () => fake_peripheral.setNextGATTDiscoveryResponse(
+                    {code: HCI_SUCCESS}))
+            .then(() => ({device: device, fake_peripheral: fake_peripheral}));
+      });
+}
+
+/**
+ * Similar to getHealthThermometerService() except the service has no
+ * characteristics or included services.
+ * @param {RequestDeviceOptions} options The options for requesting a Bluetooth
+ *     Device.
+ * @returns {service: BluetoothRemoteGATTService,
+ *     fake_health_thermometer: FakeRemoteGATTService} An object containing the
+ * health themometer service object and its corresponding fake.
+ */
+function getEmptyHealthThermometerService(options) {
+  let device;
+  let fake_peripheral;
+  let fake_health_thermometer;
+  return getDiscoveredHealthThermometerDevice(options)
+      .then(result => ({device, fake_peripheral} = result))
+      .then(
+          () => fake_peripheral.setNextGATTConnectionResponse(
+              {code: HCI_SUCCESS}))
+      .then(() => device.gatt.connect())
+      .then(() => fake_peripheral.addFakeService({uuid: 'health_thermometer'}))
+      .then(s => fake_health_thermometer = s)
+      .then(
+          () =>
+              fake_peripheral.setNextGATTDiscoveryResponse({code: HCI_SUCCESS}))
+      .then(() => device.gatt.getPrimaryService('health_thermometer'))
+      .then(service => ({
+              service: service,
+              fake_health_thermometer: fake_health_thermometer,
+            }));
+}
+
+/**
+ * Similar to getHealthThermometerDevice except the GATT discovery
+ * response has not been set yet so more attributes can still be added.
+ * @param {RequestDeviceOptions} options The options for requesting a Bluetooth
+ *     Device.
+ * @returns {Promise<{device: BluetoothDevice, fakes: {
+ *         fake_peripheral: FakePeripheral,
+ *         fake_generic_access: FakeRemoteGATTService,
+ *         fake_health_thermometer: FakeRemoteGATTService,
+ *         fake_measurement_interval: FakeRemoteGATTCharacteristic,
+ *         fake_cccd: FakeRemoteGATTDescriptor,
+ *         fake_user_description: FakeRemoteGATTDescriptor,
+ *         fake_temperature_measurement: FakeRemoteGATTCharacteristic,
+ *         fake_temperature_type: FakeRemoteGATTCharacteristic}}>} An object
+ *         containing a requested BluetoothDevice and all of the GATT fake
+ *         objects.
+ */
+function getConnectedHealthThermometerDevice(options) {
+  let device, fake_peripheral, fakes;
+  return getDiscoveredHealthThermometerDevice(options)
+      .then(_ => ({device, fake_peripheral} = _))
+      .then(() => fake_peripheral.setNextGATTConnectionResponse({
+        code: HCI_SUCCESS,
+      }))
+      .then(() => populateHealthThermometerFakes(fake_peripheral))
+      .then(_ => fakes = _)
+      .then(() => device.gatt.connect())
+      .then(() => Object.assign({device}, fakes));
+}
+
+/**
+ * Returns an object containing a BluetoothDevice discovered using |options|,
+ * its corresponding FakePeripheral and FakeRemoteGATTServices.
+ * The simulated device is called 'Health Thermometer' it has two known service
+ * UUIDs: 'generic_access' and 'health_thermometer' which correspond to two
+ * services with the same UUIDs. The 'health thermometer' service contains three
+ * characteristics:
+ *  - 'temperature_measurement' (indicate),
+ *  - 'temperature_type' (read),
+ *  - 'measurement_interval' (read, write, indicate)
+ * The 'measurement_interval' characteristic contains a
+ * 'gatt.client_characteristic_configuration' descriptor and a
+ * 'characteristic_user_description' descriptor.
+ * The device has been connected to and its attributes are ready to be
+ * discovered.
+ * @param {RequestDeviceOptions} options The options for requesting a Bluetooth
+ *     Device.
+ * @returns {Promise<{device: BluetoothDevice, fakes: {
+ *         fake_peripheral: FakePeripheral,
+ *         fake_generic_access: FakeRemoteGATTService,
+ *         fake_health_thermometer: FakeRemoteGATTService,
+ *         fake_measurement_interval: FakeRemoteGATTCharacteristic,
+ *         fake_cccd: FakeRemoteGATTDescriptor,
+ *         fake_user_description: FakeRemoteGATTDescriptor,
+ *         fake_temperature_measurement: FakeRemoteGATTCharacteristic,
+ *         fake_temperature_type: FakeRemoteGATTCharacteristic}}>} An object
+ *         containing a requested BluetoothDevice and all of the GATT fake
+ *         objects.
+ */
+function getHealthThermometerDevice(options) {
+  let result;
+  return getConnectedHealthThermometerDevice(options)
+      .then(_ => result = _)
+      .then(() => result.fake_peripheral.setNextGATTDiscoveryResponse({
+        code: HCI_SUCCESS,
+      }))
+      .then(() => result);
+}
+
+/**
+ * Similar to getHealthThermometerDevice except that the peripheral has two
+ * 'health_thermometer' services.
+ * @param {RequestDeviceOptions} options The options for requesting a Bluetooth
+ *     Device.
+ * @returns {Promise<{device: BluetoothDevice, fake_peripheral: FakePeripheral,
+ *     fake_generic_access: FakeRemoteGATTService, fake_health_thermometer1:
+ * FakeRemoteGATTService, fake_health_thermometer2: FakeRemoteGATTService}>} An
+ * object containing a requested Bluetooth device and two fake health
+ * thermometer GATT services.
+ */
+function getTwoHealthThermometerServicesDevice(options) {
+  let device;
+  let fake_peripheral;
+  let fake_generic_access;
+  let fake_health_thermometer1;
+  let fake_health_thermometer2;
+
+  return getConnectedHealthThermometerDevice(options)
+      .then(result => {
+        ({
+          device,
+          fake_peripheral,
+          fake_generic_access,
+          fake_health_thermometer: fake_health_thermometer1,
+        } = result);
+      })
+      .then(() => fake_peripheral.addFakeService({uuid: 'health_thermometer'}))
+      .then(s => fake_health_thermometer2 = s)
+      .then(
+          () =>
+              fake_peripheral.setNextGATTDiscoveryResponse({code: HCI_SUCCESS}))
+      .then(() => ({
+              device: device,
+              fake_peripheral: fake_peripheral,
+              fake_generic_access: fake_generic_access,
+              fake_health_thermometer1: fake_health_thermometer1,
+              fake_health_thermometer2: fake_health_thermometer2
+            }));
+}
+
+/**
+ * Returns an object containing a Health Thermometer BluetoothRemoteGattService
+ * and its corresponding FakeRemoteGATTService.
+ * @returns {Promise<{device: BluetoothDevice, fakes: {
+ *         fake_peripheral: FakePeripheral,
+ *         fake_generic_access: FakeRemoteGATTService,
+ *         fake_health_thermometer: FakeRemoteGATTService,
+ *         fake_measurement_interval: FakeRemoteGATTCharacteristic,
+ *         fake_cccd: FakeRemoteGATTDescriptor,
+ *         fake_user_description: FakeRemoteGATTDescriptor,
+ *         fake_temperature_measurement: FakeRemoteGATTCharacteristic,
+ *         fake_temperature_type: FakeRemoteGATTCharacteristic,
+ *         service: BluetoothRemoteGATTService,
+ *         fake_service: FakeRemoteGATTService}}>} An object
+ *         containing a requested BluetoothDevice and all of the GATT fake
+ *         objects.
+ */
+function getHealthThermometerService() {
+  let result;
+  return getHealthThermometerDevice()
+      .then(r => result = r)
+      .then(() => result.device.gatt.getPrimaryService('health_thermometer'))
+      .then(service => Object.assign(result, {
+        service,
+        fake_service: result.fake_health_thermometer,
+      }));
+}
+
+/**
+ * Returns an object containing a Measurement Interval
+ * BluetoothRemoteGATTCharacteristic and its corresponding
+ * FakeRemoteGATTCharacteristic.
+ * @returns {Promise<{device: BluetoothDevice, fakes: {
+ *         fake_peripheral: FakePeripheral,
+ *         fake_generic_access: FakeRemoteGATTService,
+ *         fake_health_thermometer: FakeRemoteGATTService,
+ *         fake_measurement_interval: FakeRemoteGATTCharacteristic,
+ *         fake_cccd: FakeRemoteGATTDescriptor,
+ *         fake_user_description: FakeRemoteGATTDescriptor,
+ *         fake_temperature_measurement: FakeRemoteGATTCharacteristic,
+ *         fake_temperature_type: FakeRemoteGATTCharacteristic,
+ *         service: BluetoothRemoteGATTService,
+ *         fake_service: FakeRemoteGATTService,
+ *         characteristic: BluetoothRemoteGATTCharacteristic,
+ *         fake_characteristic: FakeRemoteGATTCharacteristic}}>} An object
+ *         containing a requested BluetoothDevice and all of the GATT fake
+ *         objects.
+ */
+function getMeasurementIntervalCharacteristic() {
+  let result;
+  return getHealthThermometerService()
+      .then(r => result = r)
+      .then(() => result.service.getCharacteristic('measurement_interval'))
+      .then(characteristic => Object.assign(result, {
+        characteristic,
+        fake_characteristic: result.fake_measurement_interval,
+      }));
+}
+
+/**
+ * Returns an object containing a User Description
+ * BluetoothRemoteGATTDescriptor and its corresponding
+ * FakeRemoteGATTDescriptor.
+ * @returns {Promise<{device: BluetoothDevice, fakes: {
+ *         fake_peripheral: FakePeripheral,
+ *         fake_generic_access: FakeRemoteGATTService,
+ *         fake_health_thermometer: FakeRemoteGATTService,
+ *         fake_measurement_interval: FakeRemoteGATTCharacteristic,
+ *         fake_cccd: FakeRemoteGATTDescriptor,
+ *         fake_user_description: FakeRemoteGATTDescriptor,
+ *         fake_temperature_measurement: FakeRemoteGATTCharacteristic,
+ *         fake_temperature_type: FakeRemoteGATTCharacteristic,
+ *         service: BluetoothRemoteGATTService,
+ *         fake_service: FakeRemoteGATTService,
+ *         characteristic: BluetoothRemoteGATTCharacteristic,
+ *         fake_characteristic: FakeRemoteGATTCharacteristic
+ *         descriptor: BluetoothRemoteGATTDescriptor,
+ *         fake_descriptor: FakeRemoteGATTDescriptor}}>} An object
+ *         containing a requested BluetoothDevice and all of the GATT fake
+ *         objects.
+ */
+function getUserDescriptionDescriptor() {
+  let result;
+  return getMeasurementIntervalCharacteristic()
+      .then(r => result = r)
+      .then(
+          () => result.characteristic.getDescriptor(
+              'gatt.characteristic_user_description'))
+      .then(descriptor => Object.assign(result, {
+        descriptor,
+        fake_descriptor: result.fake_user_description,
+      }));
+}
deleted file mode 100644
--- a/testing/web-platform/tests/bluetooth/resources/bluetooth-helpers.js
+++ /dev/null
@@ -1,1022 +0,0 @@
-'use strict';
-
-function loadScript(path) {
-  let script = document.createElement('script');
-  let promise = new Promise(resolve => script.onload = resolve);
-  script.src = path;
-  script.async = false;
-  document.head.appendChild(script);
-  return promise;
-}
-
-function loadScripts(paths) {
-  let chain = Promise.resolve();
-  for (let path of paths) {
-    chain = chain.then(() => loadScript(path));
-  }
-  return chain;
-}
-
-function performChromiumSetup() {
-  // Make sure we are actually on Chromium with Mojo enabled.
-  if (typeof Mojo === 'undefined') {
-    return;
-  }
-
-  // Load the Chromium-specific resources.
-  let prefix = '/resources/chromium';
-  let genPrefix = '/gen';
-  let extra = [];
-  const pathname = window.location.pathname;
-  if (pathname.includes('/LayoutTests/') || pathname.includes('/web_tests/')) {
-    let root = pathname.match(/.*(?:LayoutTests|web_tests)/);
-    prefix = `${root}/external/wpt/resources/chromium`;
-    extra = [
-      `${root}/resources/bluetooth/bluetooth-fake-adapter.js`,
-    ];
-    genPrefix = 'file:///gen';
-  } else if (window.location.pathname.startsWith('/bluetooth/https/')) {
-    extra = [
-      '/js-test-resources/bluetooth/bluetooth-fake-adapter.js',
-    ];
-  }
-  return loadScripts([
-    `${genPrefix}/layout_test_data/mojo/public/js/mojo_bindings.js`,
-    `${genPrefix}/content/test/data/mojo_web_test_helper_test.mojom.js`,
-    `${genPrefix}/device/bluetooth/public/mojom/uuid.mojom.js`,
-    `${genPrefix}/url/mojom/origin.mojom.js`,
-    `${genPrefix}/device/bluetooth/public/mojom/test/fake_bluetooth.mojom.js`,
-    `${genPrefix}/content/shell/common/web_test/fake_bluetooth_chooser.mojom.js`,
-    `${prefix}/web-bluetooth-test.js`,
-  ].concat(extra))
-      // Call setBluetoothFakeAdapter() to clean up any fake adapters left over
-      // by legacy tests.
-      // Legacy tests that use setBluetoothFakeAdapter() sometimes fail to clean
-      // their fake adapter. This is not a problem for these tests because the
-      // next setBluetoothFakeAdapter() will clean it up anyway but it is a
-      // problem for the new tests that do not use setBluetoothFakeAdapter().
-      // TODO(crbug.com/569709): Remove once setBluetoothFakeAdapter is no
-      // longer used.
-      .then(() => typeof setBluetoothFakeAdapter === 'undefined' ?
-          undefined : setBluetoothFakeAdapter(''));
-}
-
-
-// These tests rely on the User Agent providing an implementation of the
-// Web Bluetooth Testing API.
-// https://docs.google.com/document/d/1Nhv_oVDCodd1pEH_jj9k8gF4rPGb_84VYaZ9IG8M_WY/edit?ts=59b6d823#heading=h.7nki9mck5t64
-function bluetooth_test(func, name, properties) {
-  Promise.resolve()
-    .then(() => promise_test(t => Promise.resolve()
-      // Trigger Chromium-specific setup.
-      .then(performChromiumSetup)
-      .then(() => func(t))
-      .then(() => navigator.bluetooth.test.allResponsesConsumed())
-      .then(consumed => assert_true(consumed)), name, properties));
-}
-
-// HCI Error Codes. Used for simulateGATT[Dis]ConnectionResponse.
-// For a complete list of possible error codes see
-// BT 4.2 Vol 2 Part D 1.3 List Of Error Codes.
-const HCI_SUCCESS = 0x0000;
-const HCI_CONNECTION_TIMEOUT = 0x0008;
-
-// GATT Error codes. Used for GATT operations responses.
-// BT 4.2 Vol 3 Part F 3.4.1.1 Error Response
-const GATT_SUCCESS        = 0x0000;
-const GATT_INVALID_HANDLE = 0x0001;
-
-// Bluetooth UUID constants:
-// Services:
-var blocklist_test_service_uuid = "611c954a-263b-4f4a-aab6-01ddb953f985";
-var request_disconnection_service_uuid = "01d7d889-7451-419f-aeb8-d65e7b9277af";
-// Characteristics:
-var blocklist_exclude_reads_characteristic_uuid =
-  "bad1c9a2-9a5b-4015-8b60-1579bbbf2135";
-var request_disconnection_characteristic_uuid =
-  "01d7d88a-7451-419f-aeb8-d65e7b9277af";
-// Descriptors:
-var blocklist_test_descriptor_uuid = "bad2ddcf-60db-45cd-bef9-fd72b153cf7c";
-var blocklist_exclude_reads_descriptor_uuid =
-    "bad3ec61-3cc3-4954-9702-7977df514114";
-
-// Sometimes we need to test that using either the name, alias, or UUID
-// produces the same result. The following objects help us do that.
-var generic_access = {
-  alias: 0x1800,
-  name: 'generic_access',
-  uuid: '00001800-0000-1000-8000-00805f9b34fb'
-};
-var device_name = {
-  alias: 0x2a00,
-  name: 'gap.device_name',
-  uuid: '00002a00-0000-1000-8000-00805f9b34fb'
-};
-var reconnection_address = {
-  alias: 0x2a03,
-  name: 'gap.reconnection_address',
-  uuid: '00002a03-0000-1000-8000-00805f9b34fb'
-};
-var heart_rate = {
-  alias: 0x180d,
-  name: 'heart_rate',
-  uuid: '0000180d-0000-1000-8000-00805f9b34fb'
-};
-var health_thermometer = {
-  alias: 0x1809,
-  name: 'health_thermometer',
-  uuid: '00001809-0000-1000-8000-00805f9b34fb'
-};
-var body_sensor_location = {
-  alias: 0x2a38,
-  name: 'body_sensor_location',
-  uuid: '00002a38-0000-1000-8000-00805f9b34fb'
-};
-var glucose = {
-  alias: 0x1808,
-  name: 'glucose',
-  uuid: '00001808-0000-1000-8000-00805f9b34fb'
-};
-var battery_service = {
-  alias: 0x180f,
-  name: 'battery_service',
-  uuid: '0000180f-0000-1000-8000-00805f9b34fb'
-};
-var battery_level = {
-  alias: 0x2A19,
-  name: 'battery_level',
-  uuid: '00002a19-0000-1000-8000-00805f9b34fb'
-};
-var user_description = {
-  alias: 0x2901,
-  name: 'gatt.characteristic_user_description',
-  uuid: '00002901-0000-1000-8000-00805f9b34fb'
-};
-var client_characteristic_configuration = {
-  alias: 0x2902,
-  name: 'gatt.client_characteristic_configuration',
-  uuid: '00002902-0000-1000-8000-00805f9b34fb'
-};
-var measurement_interval = {
-  alias: 0x2a21,
-  name: 'measurement_interval',
-  uuid: '00002a21-0000-1000-8000-00805f9b34fb'
-};
-
-// The following tests make sure the Web Bluetooth implementation
-// responds correctly to the different types of errors the
-// underlying platform might return for GATT operations.
-
-// Each browser should map these characteristics to specific code paths
-// that result in different errors thus increasing code coverage
-// when testing. Therefore some of these characteristics might not be useful
-// for all browsers.
-//
-// TODO(ortuno): According to the testing spec errorUUID(0x101) to
-// errorUUID(0x1ff) should be use for the uuids of the characteristics.
-var gatt_errors_tests = [{
-  testName: 'GATT Error: Unknown.',
-  uuid: errorUUID(0xA1),
-  error: new DOMException(
-      'GATT Error Unknown.',
-      'NotSupportedError')
-}, {
-  testName: 'GATT Error: Failed.',
-  uuid: errorUUID(0xA2),
-  error: new DOMException(
-      'GATT operation failed for unknown reason.',
-      'NotSupportedError')
-}, {
-  testName: 'GATT Error: In Progress.',
-  uuid: errorUUID(0xA3),
-  error: new DOMException(
-      'GATT operation already in progress.',
-      'NetworkError')
-}, {
-  testName: 'GATT Error: Invalid Length.',
-  uuid: errorUUID(0xA4),
-  error: new DOMException(
-      'GATT Error: invalid attribute length.',
-      'InvalidModificationError')
-}, {
-  testName: 'GATT Error: Not Permitted.',
-  uuid: errorUUID(0xA5),
-  error: new DOMException(
-      'GATT operation not permitted.',
-      'NotSupportedError')
-}, {
-  testName: 'GATT Error: Not Authorized.',
-  uuid: errorUUID(0xA6),
-  error: new DOMException(
-      'GATT operation not authorized.',
-      'SecurityError')
-}, {
-  testName: 'GATT Error: Not Paired.',
-  uuid: errorUUID(0xA7),
-  // TODO(ortuno): Change to InsufficientAuthenticationError or similiar
-  // once https://github.com/WebBluetoothCG/web-bluetooth/issues/137 is
-  // resolved.
-  error: new DOMException(
-      'GATT Error: Not paired.',
-      'NetworkError')
-}, {
-  testName: 'GATT Error: Not Supported.',
-  uuid: errorUUID(0xA8),
-  error: new DOMException(
-      'GATT Error: Not supported.',
-      'NotSupportedError')
-}];
-
-// Waits until the document has finished loading.
-function waitForDocumentReady() {
-  return new Promise(resolve => {
-    if (document.readyState === 'complete') {
-      resolve();
-    }
-
-    window.addEventListener('load', () => {
-      resolve();
-    }, {once: true});
-  });
-}
-
-function callWithTrustedClick(callback) {
-  return waitForDocumentReady()
-    .then(() => new Promise(resolve => {
-      let button = document.createElement('button');
-      button.textContent = 'click to continue test';
-      button.style.display = 'block';
-      button.style.fontSize = '20px';
-      button.style.padding = '10px';
-      button.onclick = () => {
-        document.body.removeChild(button);
-        resolve(callback());
-      };
-      document.body.appendChild(button);
-      test_driver.click(button);
-    }));
-}
-
-// Calls requestDevice() in a context that's 'allowed to show a popup'.
-function requestDeviceWithTrustedClick() {
-  let args = arguments;
-  return callWithTrustedClick(
-      () => navigator.bluetooth.requestDevice.apply(navigator.bluetooth, args));
-}
-
-// Calls requestLEScan() in a context that's 'allowed to show a popup'.
-function requestLEScanWithTrustedClick() {
-  let args = arguments;
-  return callWithTrustedClick(
-      () => navigator.bluetooth.requestLEScan.apply(navigator.bluetooth, args));
-}
-
-// errorUUID(alias) returns a UUID with the top 32 bits of
-// '00000000-97e5-4cd7-b9f1-f5a427670c59' replaced with the bits of |alias|.
-// For example, errorUUID(0xDEADBEEF) returns
-// 'deadbeef-97e5-4cd7-b9f1-f5a427670c59'. The bottom 96 bits of error UUIDs
-// were generated as a type 4 (random) UUID.
-function errorUUID(uuidAlias) {
-  // Make the number positive.
-  uuidAlias >>>= 0;
-  // Append the alias as a hex number.
-  var strAlias = '0000000' + uuidAlias.toString(16);
-  // Get last 8 digits of strAlias.
-  strAlias = strAlias.substr(-8);
-  // Append Base Error UUID
-  return strAlias + '-97e5-4cd7-b9f1-f5a427670c59';
-}
-
-// Function to test that a promise rejects with the expected error type and
-// message.
-function assert_promise_rejects_with_message(promise, expected, description) {
-  return promise.then(() => {
-    assert_unreached('Promise should have rejected: ' + description);
-  }, error => {
-    assert_equals(error.name, expected.name, 'Unexpected Error Name:');
-    if (expected.message) {
-      assert_equals(error.message, expected.message, 'Unexpected Error Message:');
-    }
-  });
-}
-
-function runGarbageCollection()
-{
-  // Run gc() as a promise.
-  return new Promise(
-      function(resolve, reject) {
-        GCController.collect();
-        step_timeout(resolve, 0);
-      });
-}
-
-function eventPromise(target, type, options) {
-  return new Promise(resolve => {
-    let wrapper = function(event) {
-      target.removeEventListener(type, wrapper);
-      resolve(event);
-    };
-    target.addEventListener(type, wrapper, options);
-  });
-}
-
-// Helper function to assert that events are fired and a promise resolved
-// in the correct order.
-// 'event' should be passed as |should_be_first| to indicate that the events
-// should be fired first, otherwise 'promiseresolved' should be passed.
-// Attaches |num_listeners| |event| listeners to |object|. If all events have
-// been fired and the promise resolved in the correct order, returns a promise
-// that fulfills with the result of |object|.|func()| and |event.target.value|
-// of each of event listeners. Otherwise throws an error.
-function assert_promise_event_order_(should_be_first, object, func, event, num_listeners) {
-  let order = [];
-  let event_promises = [];
-  for (let i = 0; i < num_listeners; i++) {
-    event_promises.push(new Promise(resolve => {
-      let event_listener = (e) => {
-        object.removeEventListener(event, event_listener);
-        order.push('event');
-        resolve(e.target.value);
-      };
-      object.addEventListener(event, event_listener);
-    }));
-  }
-
-  let func_promise = object[func]().then(result => {
-    order.push('promiseresolved');
-    return result;
-  });
-
-  return Promise.all([func_promise, ...event_promises])
-    .then((result) => {
-      if (should_be_first !== order[0]) {
-        throw should_be_first === 'promiseresolved' ?
-                      `'${event}' was fired before promise resolved.` :
-                      `Promise resolved before '${event}' was fired.`;
-      }
-
-      if (order[0] !== 'promiseresolved' &&
-          order[order.length - 1] !== 'promiseresolved') {
-        throw 'Promise resolved in between event listeners.';
-      }
-
-      return result;
-    });
-}
-
-// See assert_promise_event_order_ above.
-function assert_promise_resolves_before_event(
-  object, func, event, num_listeners=1) {
-  return assert_promise_event_order_(
-    'promiseresolved', object, func, event, num_listeners);
-}
-
-// See assert_promise_event_order_ above.
-function assert_promise_resolves_after_event(
-  object, func, event, num_listeners=1) {
-  return assert_promise_event_order_(
-    'event', object, func, event, num_listeners);
-}
-
-// Returns a promise that resolves after 100ms unless
-// the the event is fired on the object in which case
-// the promise rejects.
-function assert_no_events(object, event_name) {
-  return new Promise((resolve, reject) => {
-    let event_listener = (e) => {
-      object.removeEventListener(event_name, event_listener);
-      assert_unreached('Object should not fire an event.');
-    };
-    object.addEventListener(event_name, event_listener);
-    // TODO: Remove timeout.
-    // http://crbug.com/543884
-    step_timeout(() => {
-      object.removeEventListener(event_name, event_listener);
-      resolve();
-    }, 100);
-  });
-}
-
-class TestCharacteristicProperties {
-  // |properties| is an array of strings for property bits to be set
-  // as true.
-  constructor(properties) {
-    this.broadcast                 = false;
-    this.read                      = false;
-    this.writeWithoutResponse      = false;
-    this.write                     = false;
-    this.notify                    = false;
-    this.indicate                  = false;
-    this.authenticatedSignedWrites = false;
-    this.reliableWrite             = false;
-    this.writableAuxiliaries       = false;
-
-    properties.forEach(val => {
-      if (this.hasOwnProperty(val))
-        this[val] = true;
-      else
-        throw `Invalid member '${val}'`;
-    });
-  }
-}
-
-function assert_properties_equal(properties, expected_properties) {
-  for (let key in expected_properties) {
-    assert_equals(properties[key], expected_properties[key]);
-  }
-}
-
-class EventCatcher {
-  constructor(object, event) {
-    this.eventFired = false;
-    let event_listener = () => {
-      object.removeEventListener(event, event_listener);
-      this.eventFired = true;
-    };
-    object.addEventListener(event, event_listener);
-  }
-}
-
-// Returns a function that when called returns a promise that resolves when
-// the device has disconnected. Example:
-// device.gatt.connect()
-//   .then(gatt => get_request_disconnection(gatt))
-//   .then(requestDisconnection => requestDisconnection())
-//   .then(() => // device is now disconnected)
-function get_request_disconnection(gattServer) {
-  return gattServer.getPrimaryService(request_disconnection_service_uuid)
-    .then(service => service.getCharacteristic(request_disconnection_characteristic_uuid))
-    .then(characteristic => {
-      return () => assert_promise_rejects_with_message(
-        characteristic.writeValue(new Uint8Array([0])),
-        new DOMException(
-          'GATT Server is disconnected. Cannot perform GATT operations. ' +
-          '(Re)connect first with `device.gatt.connect`.',
-          'NetworkError'));
-    });
-}
-
-function generateRequestDeviceArgsWithServices(services = ['heart_rate']) {
-  return [{
-    filters: [{ services: services }]
-  }, {
-    filters: [{ services: services, name: 'Name' }]
-  }, {
-    filters: [{ services: services, namePrefix: 'Pre' }]
-  }, {
-    filters: [{ services: services, name: 'Name', namePrefix: 'Pre' }]
-  }, {
-    filters: [{ services: services }],
-    optionalServices: ['heart_rate']
-  }, {
-    filters: [{ services: services, name: 'Name' }],
-    optionalServices: ['heart_rate']
-  }, {
-    filters: [{ services: services, namePrefix: 'Pre' }],
-    optionalServices: ['heart_rate']
-  }, {
-    filters: [{ services: services, name: 'Name', namePrefix: 'Pre' }],
-    optionalServices: ['heart_rate']
-  }];
-}
-
-// Causes |fake_peripheral| to disconnect and returns a promise that resolves
-// once `gattserverdisconnected` has been fired on |device|.
-function simulateGATTDisconnectionAndWait(device, fake_peripheral) {
-  return Promise.all([
-    eventPromise(device, 'gattserverdisconnected'),
-    fake_peripheral.simulateGATTDisconnection(),
-  ]);
-}
-
-// Simulates a pre-connected device with |address|, |name| and
-// |knownServiceUUIDs|.
-function setUpPreconnectedDevice({
-  address = '00:00:00:00:00:00', name = 'LE Device', knownServiceUUIDs = []}) {
-  return navigator.bluetooth.test.simulateCentral({state: 'powered-on'})
-    .then(fake_central => fake_central.simulatePreconnectedPeripheral({
-      address: address,
-      name: name,
-      knownServiceUUIDs: knownServiceUUIDs,
-    }));
-}
-
-const health_thermometer_ad_packet = {
-  deviceAddress: '09:09:09:09:09:09',
-  rssi: -10,
-  scanRecord: {
-    name: 'Health Thermometer',
-    uuids: [health_thermometer.uuid],
-  },
-};
-
-// Returns a FakePeripheral that corresponds to a simulated pre-connected device
-// called 'Health Thermometer'. The device has two known serviceUUIDs:
-// 'generic_access' and 'health_thermometer'.
-function setUpHealthThermometerDevice() {
-  return setUpPreconnectedDevice({
-    address: '09:09:09:09:09:09',
-    name: 'Health Thermometer',
-    knownServiceUUIDs: ['generic_access', 'health_thermometer'],
-  });
-}
-
-// Returns an array containing two FakePeripherals corresponding
-// to the simulated devices.
-function setUpHealthThermometerAndHeartRateDevices() {
-  return navigator.bluetooth.test.simulateCentral({state: 'powered-on'})
-   .then(fake_central => Promise.all([
-     fake_central.simulatePreconnectedPeripheral({
-       address: '09:09:09:09:09:09',
-       name: 'Health Thermometer',
-       knownServiceUUIDs: ['generic_access', 'health_thermometer'],
-     }),
-     fake_central.simulatePreconnectedPeripheral({
-       address: '08:08:08:08:08:08',
-       name: 'Heart Rate',
-       knownServiceUUIDs: ['generic_access', 'heart_rate'],
-     })]));
-}
-
-// Returns the same fake peripheral as setUpHealthThermometerDevice() except
-// that connecting to the peripheral will succeed.
-function setUpConnectableHealthThermometerDevice() {
-  let fake_peripheral;
-  return setUpHealthThermometerDevice()
-    .then(_ => fake_peripheral = _)
-    .then(() => fake_peripheral.setNextGATTConnectionResponse({
-      code: HCI_SUCCESS,
-    }))
-    .then(() => fake_peripheral);
-}
-
-// Returns an object containing a BluetoothDevice discovered using |options|,
-// its corresponding FakePeripheral and FakeRemoteGATTServices.
-// The simulated device is called 'Health Thermometer' it has two known service
-// UUIDs: 'generic_access' and 'health_thermometer' which correspond to two
-// services with the same UUIDs. The 'health thermometer' service contains three
-// characteristics:
-//  - 'temperature_measurement' (indicate),
-//  - 'temperature_type' (read),
-//  - 'measurement_interval' (read, write, indicate)
-// The 'measurement_interval' characteristic contains a
-// 'gatt.client_characteristic_configuration' descriptor and a
-// 'characteristic_user_description' descriptor.
-// The device has been connected to and its attributes are ready to be
-// discovered.
-function getHealthThermometerDevice(options) {
-  let result;
-  return getConnectedHealthThermometerDevice(options)
-    .then(_ => result = _)
-    .then(() => result.fake_peripheral.setNextGATTDiscoveryResponse({
-      code: HCI_SUCCESS,
-    }))
-    .then(() => result);
-}
-
-// Similar to getHealthThermometerDevice except that the peripheral has
-// two 'health_thermometer' services.
-function getTwoHealthThermometerServicesDevice(options) {
-  let device;
-  let fake_peripheral;
-  let fake_generic_access;
-  let fake_health_thermometer1;
-  let fake_health_thermometer2;
-
-  return getConnectedHealthThermometerDevice(options)
-    .then(result => {
-      ({
-        device,
-        fake_peripheral,
-        fake_generic_access,
-        fake_health_thermometer: fake_health_thermometer1,
-      } = result);
-    })
-    .then(() => fake_peripheral.addFakeService({uuid: 'health_thermometer'}))
-    .then(s => fake_health_thermometer2 = s)
-    .then(() => fake_peripheral.setNextGATTDiscoveryResponse({
-      code: HCI_SUCCESS}))
-    .then(() => ({
-      device: device,
-      fake_peripheral: fake_peripheral,
-      fake_generic_access: fake_generic_access,
-      fake_health_thermometer1: fake_health_thermometer1,
-      fake_health_thermometer2: fake_health_thermometer2
-    }));
-}
-
-// Returns an object containing a Health Thermometer BluetoothRemoteGattService
-// and its corresponding FakeRemoteGATTService.
-function getHealthThermometerService() {
-  let result;
-  return getHealthThermometerDevice()
-    .then(r => result = r)
-    .then(() => result.device.gatt.getPrimaryService('health_thermometer'))
-    .then(service => Object.assign(result, {
-      service,
-      fake_service: result.fake_health_thermometer,
-    }));
-}
-
-// Returns an object containing a Measurement Interval
-// BluetoothRemoteGATTCharacteristic and its corresponding
-// FakeRemoteGATTCharacteristic.
-function getMeasurementIntervalCharacteristic() {
-  let result;
-  return getHealthThermometerService()
-    .then(r => result = r)
-    .then(() => result.service.getCharacteristic('measurement_interval'))
-    .then(characteristic => Object.assign(result, {
-      characteristic,
-      fake_characteristic: result.fake_measurement_interval,
-    }));
-}
-
-function getUserDescriptionDescriptor() {
-  let result;
-  return getMeasurementIntervalCharacteristic()
-    .then(r => result = r)
-    .then(() => result.characteristic.getDescriptor(
-        'gatt.characteristic_user_description'))
-    .then(descriptor => Object.assign(result, {
-      descriptor,
-      fake_descriptor: result.fake_user_description,
-    }));
-}
-
-// Populates a fake_peripheral with various fakes appropriate for a health
-// thermometer.  This resolves to an associative array composed of the fakes,
-// including the |fake_peripheral|.
-function populateHealthThermometerFakes(fake_peripheral) {
-  let fake_generic_access, fake_health_thermometer, fake_measurement_interval,
-      fake_user_description, fake_cccd, fake_temperature_measurement,
-      fake_temperature_type;
-  return fake_peripheral.addFakeService({uuid: 'generic_access'})
-    .then(_ => fake_generic_access = _)
-    .then(() => fake_peripheral.addFakeService({
-        uuid: 'health_thermometer',
-    }))
-    .then(_ => fake_health_thermometer = _)
-    .then(() => fake_health_thermometer.addFakeCharacteristic({
-      uuid: 'measurement_interval',
-      properties: ['read', 'write', 'indicate'],
-    }))
-    .then(_ => fake_measurement_interval = _)
-    .then(() => fake_measurement_interval.addFakeDescriptor({
-      uuid: 'gatt.characteristic_user_description',
-    }))
-    .then(_ => fake_user_description = _)
-    .then(() => fake_measurement_interval.addFakeDescriptor({
-      uuid: 'gatt.client_characteristic_configuration',
-    }))
-    .then(_ => fake_cccd = _)
-    .then(() => fake_health_thermometer.addFakeCharacteristic({
-      uuid: 'temperature_measurement',
-      properties: ['indicate'],
-    }))
-    .then(_ => fake_temperature_measurement = _)
-    .then(() => fake_health_thermometer.addFakeCharacteristic({
-      uuid: 'temperature_type',
-      properties: ['read'],
-    }))
-    .then(_ => fake_temperature_type = _)
-    .then(() => ({
-      fake_peripheral,
-      fake_generic_access,
-      fake_health_thermometer,
-      fake_measurement_interval,
-      fake_cccd,
-      fake_user_description,
-      fake_temperature_measurement,
-      fake_temperature_type,
-    }));
-}
-
-// Similar to getHealthThermometerDevice except the GATT discovery
-// response has not been set yet so more attributes can still be added.
-function getConnectedHealthThermometerDevice(options) {
-  let device, fake_peripheral, fakes;
-  return getDiscoveredHealthThermometerDevice(options)
-    .then(_ => ({device, fake_peripheral} = _))
-    .then(() => fake_peripheral.setNextGATTConnectionResponse({
-      code: HCI_SUCCESS,
-    }))
-    .then(() => populateHealthThermometerFakes(fake_peripheral))
-    .then(_ => fakes = _)
-    .then(() => device.gatt.connect())
-    .then(() => Object.assign({device}, fakes));
-}
-
-// Returns an object containing a BluetoothDevice discovered using |options|,
-// its corresponding FakePeripheral and FakeRemoteGATTServices.
-// The simulated device is called 'Blocklist Device' and it has one known
-// service UUIDs |blocklist_test_service_uuid| which
-// correspond to a service with the same UUID. The
-// |blocklist_test_service_uuid| service contains two characteristics:
-//   - |blocklist_exclude_reads_characteristic_uuid| (read, write)
-//   - 'gap.peripheral_privacy_flag' (read, write)
-// The 'gap.peripheral_privacy_flag' characteristic contains three descriptors:
-//   - |blocklist_test_descriptor_uuid|
-//   - |blocklist_exclude_reads_descriptor_uuid|
-//   - 'gatt.client_characteristic_configuration'
-// These are special UUIDs that have been added to the blocklist found at
-// https://github.com/WebBluetoothCG/registries/blob/master/gatt_blocklist.txt
-// There are also test UUIDs that have been added to the test environment which
-// other implementations should add as test UUIDs as well.
-// The device has been connected to and its attributes are ready to be
-// discovered.
-function getBlocklistDevice(
-    options = {filters: [{services: [blocklist_test_service_uuid]}]}) {
-  let device, fake_peripheral, fake_blocklist_test_service,
-      fake_blocklist_exclude_reads_characteristic,
-      fake_blocklist_exclude_writes_characteristic,
-      fake_blocklist_descriptor,
-      fake_blocklist_exclude_reads_descriptor,
-      fake_blocklist_exclude_writes_descriptor;
-  return setUpPreconnectedDevice({
-    address: '11:11:11:11:11:11',
-    name: 'Blocklist Device',
-    knownServiceUUIDs: ['generic_access', blocklist_test_service_uuid],
-  })
-      .then(_ => fake_peripheral = _)
-      .then(() => requestDeviceWithTrustedClick(options))
-      .then(_ => device = _)
-      .then(() => fake_peripheral.setNextGATTConnectionResponse({
-        code: HCI_SUCCESS,
-      }))
-      .then(() => device.gatt.connect())
-      .then(() => fake_peripheral.addFakeService({
-        uuid: blocklist_test_service_uuid,
-      }))
-      .then(_ => fake_blocklist_test_service = _)
-      .then(() => fake_blocklist_test_service.addFakeCharacteristic({
-        uuid: blocklist_exclude_reads_characteristic_uuid,
-        properties: ['read', 'write'],
-      }))
-      .then(_ => fake_blocklist_exclude_reads_characteristic = _)
-      .then(() => fake_blocklist_test_service.addFakeCharacteristic({
-        uuid: 'gap.peripheral_privacy_flag',
-        properties: ['read', 'write'],
-      }))
-      .then(_ => fake_blocklist_exclude_writes_characteristic = _)
-      .then(() => fake_blocklist_exclude_writes_characteristic
-          .addFakeDescriptor({uuid: blocklist_test_descriptor_uuid}))
-      .then(_ => fake_blocklist_descriptor = _)
-      .then(() => fake_blocklist_exclude_writes_characteristic
-          .addFakeDescriptor({uuid: blocklist_exclude_reads_descriptor_uuid}))
-      .then(_ => fake_blocklist_exclude_reads_descriptor = _)
-      .then(() => fake_blocklist_exclude_writes_characteristic
-          .addFakeDescriptor({
-            uuid: 'gatt.client_characteristic_configuration'
-          }))
-      .then(_ => fake_blocklist_exclude_writes_descriptor = _)
-      .then(() => fake_peripheral.setNextGATTDiscoveryResponse({
-        code: HCI_SUCCESS,
-      }))
-      .then(() => ({
-        device,
-        fake_peripheral,
-        fake_blocklist_test_service,
-        fake_blocklist_exclude_reads_characteristic,
-        fake_blocklist_exclude_writes_characteristic,
-        fake_blocklist_descriptor,
-        fake_blocklist_exclude_reads_descriptor,
-        fake_blocklist_exclude_writes_descriptor,
-      }));
-}
-
-// Returns an object containing a Blocklist Test BluetoothRemoveGattService and
-// its corresponding FakeRemoteGATTService.
-function getBlocklistTestService() {
-  let result;
-  return getBlocklistDevice()
-      .then(_ => result = _)
-      .then(() =>
-          result.device.gatt.getPrimaryService(blocklist_test_service_uuid))
-      .then(service => Object.assign(result, {
-        service,
-        fake_service: result.fake_blocklist_test_service,
-      }));
-}
-
-// Returns an object containing a blocklisted BluetoothRemoteGATTCharacteristic
-// that excludes reads and its corresponding FakeRemoteGATTCharacteristic.
-function getBlocklistExcludeReadsCharacteristic() {
-  let result, fake_characteristic;
-  return getBlocklistTestService()
-      .then(_ => result = _)
-      .then(() => result.service.getCharacteristic(
-          blocklist_exclude_reads_characteristic_uuid))
-      .then(characteristic =>
-          Object.assign(
-              result, {
-                characteristic,
-                fake_characteristic:
-                    result.fake_blocklist_exclude_reads_characteristic
-              }));
-}
-
-// Returns an object containing a blocklisted BluetoothRemoteGATTCharacteristic
-// that excludes writes and its corresponding FakeRemoteGATTCharacteristic.
-function getBlocklistExcludeWritesCharacteristic() {
-  let result, fake_characteristic;
-  return getBlocklistTestService()
-      .then(_ => result = _)
-      .then(() => result.service.getCharacteristic(
-          'gap.peripheral_privacy_flag'))
-      .then(characteristic =>
-          Object.assign(
-              result, {
-                characteristic,
-                fake_characteristic:
-                    result.fake_blocklist_exclude_writes_characteristic
-              }));
-}
-
-// Returns an object containing a blocklisted BluetoothRemoteGATTDescriptor that
-// excludes reads and its corresponding FakeRemoteGATTDescriptor.
-function getBlocklistExcludeReadsDescriptor() {
-  let result;
-  return getBlocklistExcludeWritesCharacteristic()
-      .then(_ => result = _)
-      .then(() => result.characteristic.getDescriptor(
-          blocklist_exclude_reads_descriptor_uuid))
-      .then(descriptor => Object.assign(
-          result, {
-            descriptor,
-            fake_descriptor: result.fake_blocklist_exclude_reads_descriptor
-          }));
-}
-
-// Returns an object containing a blocklisted BluetoothRemoteGATTDescriptor that
-// excludes writes and its corresponding FakeRemoteGATTDescriptor.
-function getBlocklistExcludeWritesDescriptor() {
-  let result;
-  return getBlocklistExcludeWritesCharacteristic()
-      .then(_ => result = _)
-      .then(() => result.characteristic.getDescriptor(
-          'gatt.client_characteristic_configuration'))
-      .then(descriptor => Object.assign(
-          result, {
-            descriptor: descriptor,
-            fake_descriptor: result.fake_blocklist_exclude_writes_descriptor,
-          }));
-}
-
-// Returns the same device and fake peripheral as getHealthThermometerDevice()
-// after another frame (an iframe we insert) discovered the device,
-// connected to it and discovered its services.
-function getHealthThermometerDeviceWithServicesDiscovered(options) {
-  let device, fake_peripheral, fakes;
-  let iframe = document.createElement('iframe');
-  return setUpConnectableHealthThermometerDevice()
-    .then(_ => fake_peripheral = _)
-    .then(() => populateHealthThermometerFakes(fake_peripheral))
-    .then(_ => fakes = _)
-    .then(() => fake_peripheral.setNextGATTDiscoveryResponse({
-      code: HCI_SUCCESS,
-    }))
-    .then(() => new Promise(resolve => {
-      let src = '/bluetooth/resources/health-thermometer-iframe.html';
-      // TODO(509038): Can be removed once LayoutTests/bluetooth/* that use
-      // health-thermometer-iframe.html have been moved to
-      // LayoutTests/external/wpt/bluetooth/*
-      if (window.location.pathname.includes('/LayoutTests/')) {
-        src = '../../../external/wpt/bluetooth/resources/health-thermometer-iframe.html';
-      }
-      iframe.src = src;
-      document.body.appendChild(iframe);
-      iframe.addEventListener('load', resolve);
-    }))
-    .then(() => new Promise((resolve, reject) => {
-      callWithTrustedClick(() => {
-        iframe.contentWindow.postMessage({
-          type: 'DiscoverServices',
-          options: options
-        }, '*');
-      });
-
-      function messageHandler(messageEvent) {
-        if (messageEvent.data == 'DiscoveryComplete') {
-          window.removeEventListener('message', messageHandler);
-          resolve();
-        } else {
-          reject(new Error(`Unexpected message: ${messageEvent.data}`));
-        }
-      }
-      window.addEventListener('message', messageHandler);
-    }))
-    .then(() => requestDeviceWithTrustedClick(options))
-    .then(_ => device = _)
-    .then(device => device.gatt.connect())
-    .then(_ => Object.assign({device}, fakes));
-}
-
-// Similar to getHealthThermometerDevice() except the device has no services,
-// characteristics, or descriptors.
-function getEmptyHealthThermometerDevice(options) {
-  return getDiscoveredHealthThermometerDevice(options)
-    .then(({device, fake_peripheral}) => {
-      return fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS})
-        .then(() => device.gatt.connect())
-        .then(() => fake_peripheral.setNextGATTDiscoveryResponse({
-          code: HCI_SUCCESS}))
-        .then(() => ({
-          device: device,
-          fake_peripheral: fake_peripheral
-        }));
-    });
-}
-
-// Similar to getHealthThermometerService() except the service has no
-// characteristics or included services.
-function getEmptyHealthThermometerService(options) {
-  let device;
-  let fake_peripheral;
-  let fake_health_thermometer;
-  return getDiscoveredHealthThermometerDevice(options)
-    .then(result => ({device, fake_peripheral} = result))
-    .then(() => fake_peripheral.setNextGATTConnectionResponse({
-      code: HCI_SUCCESS}))
-    .then(() => device.gatt.connect())
-    .then(() => fake_peripheral.addFakeService({uuid: 'health_thermometer'}))
-    .then(s => fake_health_thermometer = s)
-    .then(() => fake_peripheral.setNextGATTDiscoveryResponse({
-      code: HCI_SUCCESS}))
-    .then(() => device.gatt.getPrimaryService('health_thermometer'))
-    .then(service => ({
-      service: service,
-      fake_health_thermometer: fake_health_thermometer,
-    }));
-}
-
-// Returns a BluetoothDevice discovered using |options| and its
-// corresponding FakePeripheral.
-// The simulated device is called 'HID Device' it has three known service
-// UUIDs: 'generic_access', 'device_information', 'human_interface_device'.
-// The primary service with 'device_information' UUID has a characteristics
-// with UUID 'serial_number_string'. The device has been connected to and its
-// attributes are ready to be discovered.
-function getHIDDevice(options) {
-  let device, fake_peripheral;
-  return getConnectedHIDDevice(options)
-    .then(_ => ({device, fake_peripheral} = _))
-    .then(() => fake_peripheral.setNextGATTDiscoveryResponse({
-      code: HCI_SUCCESS,
-    }))
-    .then(() => ({device, fake_peripheral}));
-}
-
-// Similar to getHealthThermometerDevice except the GATT discovery
-// response has not been set yet so more attributes can still be added.
-// TODO(crbug.com/719816): Add descriptors.
-function getConnectedHIDDevice(options) {
-  let device, fake_peripheral;
-  return setUpPreconnectedDevice({
-      address: '10:10:10:10:10:10',
-      name: 'HID Device',
-      knownServiceUUIDs: [
-        'generic_access',
-        'device_information',
-        'human_interface_device',
-      ],
-    })
-    .then(_ => (fake_peripheral = _))
-    .then(() => requestDeviceWithTrustedClick(options))
-    .then(_ => (device = _))
-    .then(() => fake_peripheral.setNextGATTConnectionResponse({
-      code: HCI_SUCCESS,
-    }))
-    .then(() => device.gatt.connect())
-    .then(() => fake_peripheral.addFakeService({
-      uuid: 'generic_access',
-    }))
-    .then(() => fake_peripheral.addFakeService({
-      uuid: 'device_information',
-    }))
-    // Blocklisted Characteristic:
-    // https://github.com/WebBluetoothCG/registries/blob/master/gatt_blocklist.txt
-    .then(dev_info => dev_info.addFakeCharacteristic({
-      uuid: 'serial_number_string',
-      properties: ['read'],
-    }))
-    .then(() => fake_peripheral.addFakeService({
-      uuid: 'human_interface_device',
-    }))
-    .then(() => ({device, fake_peripheral}));
-}
-
-// Similar to getHealthThermometerDevice() except the device
-// is not connected and thus its services have not been
-// discovered.
-function getDiscoveredHealthThermometerDevice(
-  options = {filters: [{services: ['health_thermometer']}]}) {
-  return setUpHealthThermometerDevice()
-  .then(fake_peripheral => {
-    return requestDeviceWithTrustedClick(options)
-      .then(device => ({
-        device: device,
-        fake_peripheral: fake_peripheral
-      }));
-  });
-}
--- a/testing/web-platform/tests/bluetooth/resources/bluetooth-scanning-helpers.js
+++ b/testing/web-platform/tests/bluetooth/resources/bluetooth-scanning-helpers.js
@@ -34,9 +34,9 @@ function verifyBluetoothAdvertisingEvent
   assert_equals(data[0], e.manufacturerData.get(224).getUint8(0))
   assert_equals(data[1], e.manufacturerData.get(224).getUint8(1))
   assert_equals(data[2], e.manufacturerData.get(224).getUint8(2))
 
   assert_equals(e.serviceData.constructor.name, 'BluetoothServiceDataMap')
   assert_equals(data[0], e.serviceData.get(health_uuid).getUint8(0))
   assert_equals(data[1], e.serviceData.get(health_uuid).getUint8(1))
   assert_equals(data[2], e.serviceData.get(health_uuid).getUint8(2))
-}
\ No newline at end of file
+}
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/resources/bluetooth-test.js
@@ -0,0 +1,384 @@
+'use strict';
+
+/**
+ * Test Setup Helpers
+ */
+
+/**
+ * Loads a script by creating a <script> element pointing to |path|.
+ * @param {string} path The path of the script to load.
+ * @returns {Promise<void>} Resolves when the script has finished loading.
+ */
+function loadScript(path) {
+  let script = document.createElement('script');
+  let promise = new Promise(resolve => script.onload = resolve);
+  script.src = path;
+  script.async = false;
+  document.head.appendChild(script);
+  return promise;
+}
+
+/**
+ * Loads the scripts in |paths|.
+ * @param {string[]} paths
+ * @returns {Promise<void>} A promise chain that resolves when all scripts have
+ *     finished loading.
+ */
+function loadScripts(paths) {
+  let chain = Promise.resolve();
+  for (let path of paths) {
+    chain = chain.then(() => loadScript(path));
+  }
+  return chain;
+}
+
+/**
+ * Performs the Chromium specific setup necessary to run the tests in the
+ * Chromium browser. This test file is shared between Web Platform Tests and
+ * Blink Web Tests, so this method figures out the correct paths to use for
+ * loading scripts.
+ *
+ * TODO(https://crbug.com/569709): Update this description when all Web
+ * Bluetooth Blink Web Tests have been migrated into this repository.
+ * @returns {Promise<void>} Resolves when Chromium specific setup is complete.
+ */
+function performChromiumSetup() {
+  // Make sure we are actually on Chromium with Mojo enabled.
+  if (typeof Mojo === 'undefined') {
+    return;
+  }
+
+  // Load the Chromium-specific resources.
+  let prefix = '/resources/chromium';
+  let genPrefix = '/gen';
+  let extra = [];
+  const pathname = window.location.pathname;
+  if (pathname.includes('/LayoutTests/') || pathname.includes('/web_tests/')) {
+    let root = pathname.match(/.*(?:LayoutTests|web_tests)/);
+    prefix = `${root}/external/wpt/resources/chromium`;
+    extra = [
+      `${root}/resources/bluetooth/bluetooth-fake-adapter.js`,
+    ];
+    genPrefix = 'file:///gen';
+  } else if (window.location.pathname.startsWith('/bluetooth/https/')) {
+    extra = [
+      '/js-test-resources/bluetooth/bluetooth-fake-adapter.js',
+    ];
+  }
+  return loadScripts([
+           `${genPrefix}/layout_test_data/mojo/public/js/mojo_bindings.js`,
+           `${genPrefix}/content/test/data/mojo_web_test_helper_test.mojom.js`,
+           `${genPrefix}/device/bluetooth/public/mojom/uuid.mojom.js`,
+           `${genPrefix}/url/mojom/origin.mojom.js`,
+           `${genPrefix}/device/bluetooth/public/mojom/test/fake_bluetooth.mojom.js`,
+           `${genPrefix}/content/shell/common/web_test/fake_bluetooth_chooser.mojom.js`,
+           `${prefix}/web-bluetooth-test.js`,
+         ].concat(extra))
+      // Call setBluetoothFakeAdapter() to clean up any fake adapters left over
+      // by legacy tests.
+      // Legacy tests that use setBluetoothFakeAdapter() sometimes fail to clean
+      // their fake adapter. This is not a problem for these tests because the
+      // next setBluetoothFakeAdapter() will clean it up anyway but it is a
+      // problem for the new tests that do not use setBluetoothFakeAdapter().
+      // TODO(https://crbug.com/569709): Remove once setBluetoothFakeAdapter is
+      // no longer used.
+      .then(
+          () => typeof setBluetoothFakeAdapter === 'undefined' ?
+              undefined :
+              setBluetoothFakeAdapter(''));
+}
+
+/**
+ * These tests rely on the User Agent providing an implementation of the Web
+ * Bluetooth Testing API.
+ * https://docs.google.com/document/d/1Nhv_oVDCodd1pEH_jj9k8gF4rPGb_84VYaZ9IG8M_WY/edit?ts=59b6d823#heading=h.7nki9mck5t64
+ * @param {function{*}: Promise<*>} test_function The Web Bluetooth test to run.
+ * @param {string} name The name or description of the test.
+ * @param {object} properties An object containing extra options for the test.
+ * @returns {Promise<void>} Resolves if Web Bluetooth test ran successfully, or
+ *     rejects if the test failed.
+ */
+function bluetooth_test(test_function, name, properties) {
+  Promise.resolve().then(
+      () => promise_test(
+          t => Promise
+                   .resolve()
+                   // Trigger Chromium-specific setup.
+                   .then(performChromiumSetup)
+                   .then(() => test_function(t))
+                   .then(() => navigator.bluetooth.test.allResponsesConsumed())
+                   .then(consumed => assert_true(consumed)),
+          name, properties));
+}
+
+/**
+ * Test Helpers
+ */
+
+/**
+ * Waits until the document has finished loading.
+ * @returns {Promise<void>} Resolves if the document is already completely
+ *     loaded or when the 'onload' event is fired.
+ */
+function waitForDocumentReady() {
+  return new Promise(resolve => {
+    if (document.readyState === 'complete') {
+      resolve();
+    }
+
+    window.addEventListener('load', () => {
+      resolve();
+    }, {once: true});
+  });
+}
+
+/**
+ * Simulates a user activation prior to running |callback|.
+ * @param {Function} callback The function to run after the user activation.
+ * @returns {Promise<*>} Resolves when the user activation has been simulated
+ *     with the result of |callback|.
+ */
+function callWithTrustedClick(callback) {
+  return waitForDocumentReady().then(() => new Promise(resolve => {
+                                       let button =
+                                           document.createElement('button');
+                                       button.textContent =
+                                           'click to continue test';
+                                       button.style.display = 'block';
+                                       button.style.fontSize = '20px';
+                                       button.style.padding = '10px';
+                                       button.onclick = () => {
+                                         document.body.removeChild(button);
+                                         resolve(callback());
+                                       };
+                                       document.body.appendChild(button);
+                                       test_driver.click(button);
+                                     }));
+}
+
+/**
+ * Calls requestDevice() in a context that's 'allowed to show a popup'.
+ * @returns {Promise<BluetoothDevice>} Resolves with a Bluetooth device if
+ *     successful or rejects with an error.
+ */
+function requestDeviceWithTrustedClick() {
+  let args = arguments;
+  return callWithTrustedClick(
+      () => navigator.bluetooth.requestDevice.apply(navigator.bluetooth, args));
+}
+
+/**
+ * Calls requestLEScan() in a context that's 'allowed to show a popup'.
+ * @returns {Promise<BluetoothLEScan>} Resolves with the properties of the scan
+ *     if successful or rejects with an error.
+ */
+function requestLEScanWithTrustedClick() {
+  let args = arguments;
+  return callWithTrustedClick(
+      () => navigator.bluetooth.requestLEScan.apply(navigator.bluetooth, args));
+}
+
+/**
+ * Function to test that a promise rejects with the expected error type and
+ * message.
+ * @param {Promise} promise
+ * @param {object} expected
+ * @param {string} description
+ * @returns {Promise<void>} Resolves if |promise| rejected with |expected|
+ *     error.
+ */
+function assert_promise_rejects_with_message(promise, expected, description) {
+  return promise.then(
+      () => {
+        assert_unreached('Promise should have rejected: ' + description);
+      },
+      error => {
+        assert_equals(error.name, expected.name, 'Unexpected Error Name:');
+        if (expected.message) {
+          assert_equals(
+              error.message, expected.message, 'Unexpected Error Message:');
+        }
+      });
+}
+
+/**
+ * Runs the garbage collection.
+ * @returns {Promise<void>} Resolves when garbage collection has finished.
+ */
+function runGarbageCollection() {
+  // Run gc() as a promise.
+  return new Promise(function(resolve, reject) {
+    GCController.collect();
+    step_timeout(resolve, 0);
+  });
+}
+
+/**
+ * Helper class that can be created to check that an event has fired.
+ */
+class EventCatcher {
+  /**
+   * @param {EventTarget} object The object to listen for events on.
+   * @param {string} event The type of event to listen for.
+   */
+  constructor(object, event) {
+    /** @type {boolean} */
+    this.eventFired = false;
+
+    /** @type {function()} */
+    let event_listener = () => {
+      object.removeEventListener(event, event_listener);
+      this.eventFired = true;
+    };
+    object.addEventListener(event, event_listener);
+  }
+}
+
+/**
+ * Notifies when the event |type| has fired.
+ * @param {EventTarget} target The object to listen for the event.
+ * @param {string} type The type of event to listen for.
+ * @param {object} options Characteristics about the event listener.
+ * @returns {Promise<Event>} Resolves when an event of |type| has fired.
+ */
+function eventPromise(target, type, options) {
+  return new Promise(resolve => {
+    let wrapper = function(event) {
+      target.removeEventListener(type, wrapper);
+      resolve(event);
+    };
+    target.addEventListener(type, wrapper, options);
+  });
+}
+
+/**
+ * The action that should occur first in assert_promise_event_order_().
+ * @enum {string}
+ */
+const ShouldBeFirst = {
+  EVENT: 'event',
+  PROMISE_RESOLUTION: 'promiseresolved',
+};
+
+/**
+ * Helper function to assert that events are fired and a promise resolved
+ * in the correct order.
+ * 'event' should be passed as |should_be_first| to indicate that the events
+ * should be fired first, otherwise 'promiseresolved' should be passed.
+ * Attaches |num_listeners| |event| listeners to |object|. If all events have
+ * been fired and the promise resolved in the correct order, returns a promise
+ * that fulfills with the result of |object|.|func()| and |event.target.value|
+ * of each of event listeners. Otherwise throws an error.
+ * @param {ShouldBeFirst} should_be_first Indicates whether |func| should
+ *     resolve before |event| is fired.
+ * @param {EventTarget} object The target object to add event listeners to.
+ * @param {function(*): Promise<*>} func The function to test the resolution
+ *     order for.
+ * @param {string} event The event type to listen for.
+ * @param {number} num_listeners The number of events to listen for.
+ * @returns {Promise<*>} The return value of |func|.
+ */
+function assert_promise_event_order_(
+    should_be_first, object, func, event, num_listeners) {
+  let order = [];
+  let event_promises = [];
+  for (let i = 0; i < num_listeners; i++) {
+    event_promises.push(new Promise(resolve => {
+      let event_listener = (e) => {
+        object.removeEventListener(event, event_listener);
+        order.push(ShouldBeFirst.EVENT);
+        resolve(e.target.value);
+      };
+      object.addEventListener(event, event_listener);
+    }));
+  }
+
+  let func_promise = object[func]().then(result => {
+    order.push(ShouldBeFirst.PROMISE_RESOLUTION);
+    return result;
+  });
+
+  return Promise.all([func_promise, ...event_promises]).then((result) => {
+    if (should_be_first !== order[0]) {
+      throw should_be_first === ShouldBeFirst.PROMISE_RESOLUTION ?
+          `'${event}' was fired before promise resolved.` :
+          `Promise resolved before '${event}' was fired.`;
+    }
+
+    if (order[0] !== ShouldBeFirst.PROMISE_RESOLUTION &&
+        order[order.length - 1] !== ShouldBeFirst.PROMISE_RESOLUTION) {
+      throw 'Promise resolved in between event listeners.';
+    }
+
+    return result;
+  });
+}
+
+/**
+ * Asserts that the promise returned by |func| resolves before events of type
+ * |event| are fired |num_listeners| times on |object|. See
+ * assert_promise_event_order_ above for more details.
+ * @param {EventTarget} object  The target object to add event listeners to.
+ * @param {function(*): Promise<*>} func The function whose promise should
+ *     resolve first.
+ * @param {string} event The event type to listen for.
+ * @param {number} num_listeners The number of events to listen for.
+ * @returns {Promise<*>} The return value of |func|.
+ */
+function assert_promise_resolves_before_event(
+    object, func, event, num_listeners = 1) {
+  return assert_promise_event_order_(
+      ShouldBeFirst.PROMISE_RESOLUTION, object, func, event, num_listeners);
+}
+
+/**
+ * Asserts that the promise returned by |func| resolves after events of type
+ * |event| are fired |num_listeners| times on |object|. See
+ * assert_promise_event_order_ above for more details.
+ * @param {EventTarget} object  The target object to add event listeners to.
+ * @param {function(*): Promise<*>} func The function whose promise should
+ *     resolve first.
+ * @param {string} event The event type to listen for.
+ * @param {number} num_listeners The number of events to listen for.
+ * @returns {Promise<*>} The return value of |func|.
+ */
+function assert_promise_resolves_after_event(
+    object, func, event, num_listeners = 1) {
+  return assert_promise_event_order_(
+      ShouldBeFirst.EVENT, object, func, event, num_listeners);
+}
+
+/**
+ * Returns a promise that resolves after 100ms unless the the event is fired on
+ * the object in which case the promise rejects.
+ * @param {EventTarget} object The target object to listen for events.
+ * @param {string} event_name The event type to listen for.
+ * @returns {Promise<void>} Resolves if no events were fired.
+ */
+function assert_no_events(object, event_name) {
+  return new Promise((resolve, reject) => {
+    let event_listener = (e) => {
+      object.removeEventListener(event_name, event_listener);
+      assert_unreached('Object should not fire an event.');
+    };
+    object.addEventListener(event_name, event_listener);
+    // TODO: Remove timeout.
+    // http://crbug.com/543884
+    step_timeout(() => {
+      object.removeEventListener(event_name, event_listener);
+      resolve();
+    }, 100);
+  });
+}
+
+/**
+ * Asserts that |properties| contains the same properties in
+ * |expected_properties| with equivalent values.
+ * @param {object} properties Actual object to compare.
+ * @param {object} expected_properties Expected object to compare with.
+ */
+function assert_properties_equal(properties, expected_properties) {
+  for (let key in expected_properties) {
+    assert_equals(properties[key], expected_properties[key]);
+  }
+}
--- a/testing/web-platform/tests/bluetooth/script-tests/base_test_js.template
+++ b/testing/web-platform/tests/bluetooth/script-tests/base_test_js.template
@@ -1,5 +1,6 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 TEST
--- a/testing/web-platform/tests/bluetooth/server/connect/connection-succeeds.https.html
+++ b/testing/web-platform/tests/bluetooth/server/connect/connection-succeeds.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Device will connect';
 let device, fake_peripheral;
 
 bluetooth_test(() => getDiscoveredHealthThermometerDevice()
     .then(_ => ({device, fake_peripheral} = _))
     .then(() =>
--- a/testing/web-platform/tests/bluetooth/server/connect/garbage-collection-ran-during-success.https.html
+++ b/testing/web-platform/tests/bluetooth/server/connect/garbage-collection-ran-during-success.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Garbage Collection ran during a connect call that ' +
     'succeeds. Should not crash.';
 let device, fake_peripheral;
 
 bluetooth_test(() => getDiscoveredHealthThermometerDevice()
     .then(_ => ({device, fake_peripheral} = _))
--- a/testing/web-platform/tests/bluetooth/server/connect/get-same-gatt-server.https.html
+++ b/testing/web-platform/tests/bluetooth/server/connect/get-same-gatt-server.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Multiple connects should return the same gatt object.';
 let device, fake_peripheral;
 
 bluetooth_test(() => getDiscoveredHealthThermometerDevice()
     .then(_ => ({device, fake_peripheral} = _))
     .then(() =>
--- a/testing/web-platform/tests/bluetooth/server/device-same-object.https.html
+++ b/testing/web-platform/tests/bluetooth/server/device-same-object.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = '[SameObject] test for BluetoothRemoteGATTServer\'s device.';
 let device, fake_peripheral;
 
 bluetooth_test(
     () => getDiscoveredHealthThermometerDevice()
               .then(_ => ({device, fake_peripheral} = _))
--- a/testing/web-platform/tests/bluetooth/server/disconnect/connect-disconnect-twice.https.html
+++ b/testing/web-platform/tests/bluetooth/server/disconnect/connect-disconnect-twice.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Connect + Disconnect twice still results in ' +
   '\'connected\' being false.';
 let device, fake_peripheral;
 
 // TODO(569716): Test that the disconnect signal was sent to the device.
 bluetooth_test(() => getDiscoveredHealthThermometerDevice()
--- a/testing/web-platform/tests/bluetooth/server/disconnect/detach-gc.https.html
+++ b/testing/web-platform/tests/bluetooth/server/disconnect/detach-gc.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <body>
 <script>
 'use strict';
 const test_desc = 'Detach frame then garbage collect. We shouldn\'t crash.';
 let iframe = document.createElement('iframe');
 
 bluetooth_test(() => setUpConnectableHealthThermometerDevice()
     // 1. Load the iframe.
--- a/testing/web-platform/tests/bluetooth/server/disconnect/disconnect-twice-in-a-row.https.html
+++ b/testing/web-platform/tests/bluetooth/server/disconnect/disconnect-twice-in-a-row.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Calling disconnect twice in a row still results in ' +
   '\'connected\' being false.';
 let device, fake_peripheral;
 
 // TODO(569716): Test that the disconnect signal was sent to the device.
 bluetooth_test(() => getDiscoveredHealthThermometerDevice()
--- a/testing/web-platform/tests/bluetooth/server/disconnect/gc-detach.https.html
+++ b/testing/web-platform/tests/bluetooth/server/disconnect/gc-detach.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <body>
 <script>
 'use strict';
 const test_desc = 'Garbage collect then detach frame. We shouldn\'t crash.';
 let iframe = document.createElement('iframe');
 
 bluetooth_test(() => setUpConnectableHealthThermometerDevice()
     // 1. Load the iframe.
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-disconnect-called-before.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-disconnect-called-before.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'disconnect() called before getPrimaryService. ' +
     'Reject with NetworkError.';
 const expected = new DOMException(
     `Failed to execute 'getPrimaryService' on 'BluetoothRemoteGATTServer': ` +
     `GATT Server is disconnected. Cannot retrieve services. (Re)connect ` +
     `first with \`device.gatt.connect\`.`,
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-disconnect-called-during-error.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-disconnect-called-during-error.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'disconnect() called during a getPrimaryService ' +
     'call that fails. Reject with NetworkError.';
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve services. (Re)connect ' +
         'first with `device.gatt.connect`.',
     'NetworkError');
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-disconnect-called-during-success.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-disconnect-called-during-success.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'disconnect() called during a getPrimaryService call that ' +
     'succeeds. Reject with NetworkError.';
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve services. (Re)connect ' +
         'first with `device.gatt.connect`.',
     'NetworkError');
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-disconnect-invalidates-objects.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-disconnect-invalidates-objects.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Calls on services after we disconnect and connect again. ' +
     'Should reject with InvalidStateError.';
 let device, services;
 
 function createDOMException(func, uuid) {
   return new DOMException(
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-disconnected-device.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-disconnected-device.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'getPrimaryService called before connecting. Reject with ' +
     'NetworkError.';
 const expected = new DOMException(
     `Failed to execute 'getPrimaryService' on 'BluetoothRemoteGATTServer': ` +
     `GATT Server is disconnected. Cannot retrieve services. (Re)connect ` +
     `first with \`device.gatt.connect\`.`,
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-discovery-complete-no-permission-absent-service.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-discovery-complete-no-permission-absent-service.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Request for absent service without permission. Should ' +
     'Reject with SecurityError even if services have been discovered already.';
 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',
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-discovery-complete-service-not-found.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-discovery-complete-service-not-found.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Request for absent service. Must reject with ' +
     'NotFoundError even when the services have previously been discovered.';
 
 bluetooth_test(
     () => getHealthThermometerDeviceWithServicesDiscovered({
             filters: [{services: ['health_thermometer']}],
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-garbage-collection-ran-during-error.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-garbage-collection-ran-during-error.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Garbage Collection ran during a getPrimaryService ' +
     'call that failed. Should not crash.'
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve services. (Re)connect first ' +
         'with `device.gatt.connect`.',
     'NetworkError');
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-garbage-collection-ran-during-success.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-garbage-collection-ran-during-success.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc =
     'Garbage Collection ran during a getPrimaryService call that ' +
     'succeeds. Should not crash.';
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve services. ' +
         '(Re)connect first with `device.gatt.connect`.',
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-get-different-service-after-reconnection.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-get-different-service-after-reconnection.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc =
     'Calls to getPrimaryService after a disconnection should return ' +
     'a different object.';
 let device, services_first_connection, services_second_connection;
 
 bluetooth_test(
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-get-same-object.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-get-same-object.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Calls to getPrimaryService should return the same object.';
 let device;
 
 bluetooth_test(
     () => getHealthThermometerDevice({
             filters: [{services: ['health_thermometer']}],
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-invalid-service-name.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-invalid-service-name.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Wrong Service name. Reject with TypeError.';
 const expected = new DOMException(
     'Failed to execute \'getPrimaryService\' on ' +
         '\'BluetoothRemoteGATTServer\': Invalid Service name: ' +
         '\'wrong_name\'. It must be a valid UUID alias (e.g. 0x1234), ' +
         'UUID (lowercase hex characters e.g. ' +
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-no-permission-absent-service.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-no-permission-absent-service.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Request for absent service without permission. ' +
     'Reject with SecurityError.';
 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',
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-no-permission-for-any-service.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-no-permission-for-any-service.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Request for present service without permission to access ' +
     'any service. Reject with SecurityError.';
 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',
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-no-permission-present-service.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-no-permission-present-service.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Request for present service without permission. ' +
     'Reject with SecurityError.';
 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');
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-service-not-found.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/gen-service-not-found.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Request for absent service. Reject with NotFoundError.';
 
 bluetooth_test(
     () => getHealthThermometerDevice({
             filters: [{services: ['health_thermometer']}],
             optionalServices: ['glucose']
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/service-found.https.html
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/service-found.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Request for service. Should return right service';
 let device;
 
 bluetooth_test(() => getHealthThermometerDevice({
   filters: [{services: ['health_thermometer']}],
   optionalServices: ['generic_access']
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryService/two-iframes-from-same-origin.https.html
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryService/two-iframes-from-same-origin.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 "use strict";
 const test_desc = 'Two iframes in the same origin should be able to access ' +
     'each other\'s services';
 
 const iframe1 = document.createElement('iframe');
 const iframe2 = document.createElement('iframe');
 
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/blocklisted-services-with-uuid.https.html
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/blocklisted-services-with-uuid.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Request for services. Does not return blocklisted service.';
 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');
 
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/blocklisted-services.https.html
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/blocklisted-services.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Request for services. Does not return blocklisted service.';
 
 bluetooth_test(() => getHIDDevice({
   filters: [{services: ['device_information']}],
   optionalServices: ['generic_access', 'human_interface_device']
 })
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/correct-services.https.html
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/correct-services.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Find correct services with UUID.';
 let device, fake_peripheral;
 
 bluetooth_test(() => getConnectedHealthThermometerDevice({
   filters: [{services: ['health_thermometer']}]
 })
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-before-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-before-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'disconnect() called before getPrimaryServices. ' +
     'Reject with NetworkError.';
 const expected = new DOMException(
     `Failed to execute 'getPrimaryServices' on 'BluetoothRemoteGATTServer': ` +
     `GATT Server is disconnected. Cannot retrieve services. (Re)connect ` +
     `first with \`device.gatt.connect\`.`,
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-before.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-before.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'disconnect() called before getPrimaryServices. ' +
     'Reject with NetworkError.';
 const expected = new DOMException(
     `Failed to execute 'getPrimaryServices' on 'BluetoothRemoteGATTServer': ` +
     `GATT Server is disconnected. Cannot retrieve services. (Re)connect ` +
     `first with \`device.gatt.connect\`.`,
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-during-error-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-during-error-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'disconnect() called during a getPrimaryServices ' +
     'call that fails. Reject with NetworkError.';
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve services. (Re)connect ' +
         'first with `device.gatt.connect`.',
     'NetworkError');
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-during-error.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-during-error.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'disconnect() called during a getPrimaryServices ' +
     'call that fails. Reject with NetworkError.';
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve services. (Re)connect ' +
         'first with `device.gatt.connect`.',
     'NetworkError');
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-during-success-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-during-success-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'disconnect() called during a getPrimaryServices call that ' +
     'succeeds. Reject with NetworkError.';
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve services. (Re)connect ' +
         'first with `device.gatt.connect`.',
     'NetworkError');
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-during-success.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-called-during-success.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'disconnect() called during a getPrimaryServices call that ' +
     'succeeds. Reject with NetworkError.';
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve services. (Re)connect ' +
         'first with `device.gatt.connect`.',
     'NetworkError');
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-invalidates-objects-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-invalidates-objects-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Calls on services after we disconnect and connect again. ' +
     'Should reject with InvalidStateError.';
 let device, services;
 
 function createDOMException(func, uuid) {
   return new DOMException(
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-invalidates-objects.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnect-invalidates-objects.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Calls on services after we disconnect and connect again. ' +
     'Should reject with InvalidStateError.';
 let device, services;
 
 function createDOMException(func, uuid) {
   return new DOMException(
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnected-device-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnected-device-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'getPrimaryServices called before connecting. Reject with ' +
     'NetworkError.';
 const expected = new DOMException(
     `Failed to execute 'getPrimaryServices' on 'BluetoothRemoteGATTServer': ` +
     `GATT Server is disconnected. Cannot retrieve services. (Re)connect ` +
     `first with \`device.gatt.connect\`.`,
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnected-device.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-disconnected-device.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'getPrimaryServices called before connecting. Reject with ' +
     'NetworkError.';
 const expected = new DOMException(
     `Failed to execute 'getPrimaryServices' on 'BluetoothRemoteGATTServer': ` +
     `GATT Server is disconnected. Cannot retrieve services. (Re)connect ` +
     `first with \`device.gatt.connect\`.`,
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-discovery-complete-no-permission-absent-service-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-discovery-complete-no-permission-absent-service-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Request for absent service without permission. Should ' +
     'Reject with SecurityError even if services have been discovered already.';
 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',
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-discovery-complete-service-not-found-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-discovery-complete-service-not-found-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Request for absent service. Must reject with ' +
     'NotFoundError even when the services have previously been discovered.';
 
 bluetooth_test(
     () => getHealthThermometerDeviceWithServicesDiscovered({
             filters: [{services: ['health_thermometer']}],
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-garbage-collection-ran-during-error-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-garbage-collection-ran-during-error-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Garbage Collection ran during a getPrimaryServices ' +
     'call that failed. Should not crash.'
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve services. (Re)connect first ' +
         'with `device.gatt.connect`.',
     'NetworkError');
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-garbage-collection-ran-during-error.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-garbage-collection-ran-during-error.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Garbage Collection ran during a getPrimaryServices ' +
     'call that failed. Should not crash.'
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve services. (Re)connect first ' +
         'with `device.gatt.connect`.',
     'NetworkError');
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-garbage-collection-ran-during-success-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-garbage-collection-ran-during-success-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc =
     'Garbage Collection ran during a getPrimaryServices call that ' +
     'succeeds. Should not crash.';
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve services. ' +
         '(Re)connect first with `device.gatt.connect`.',
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-garbage-collection-ran-during-success.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-garbage-collection-ran-during-success.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc =
     'Garbage Collection ran during a getPrimaryServices call that ' +
     'succeeds. Should not crash.';
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve services. ' +
         '(Re)connect first with `device.gatt.connect`.',
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-get-different-service-after-reconnection-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-get-different-service-after-reconnection-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc =
     'Calls to getPrimaryServices after a disconnection should return ' +
     'a different object.';
 let device, services_first_connection, services_second_connection;
 
 bluetooth_test(
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-get-different-service-after-reconnection.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-get-different-service-after-reconnection.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc =
     'Calls to getPrimaryServices after a disconnection should return ' +
     'a different object.';
 let device, services_first_connection, services_second_connection;
 
 bluetooth_test(
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-get-same-object-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-get-same-object-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Calls to getPrimaryServices should return the same object.';
 let device;
 
 bluetooth_test(
     () => getHealthThermometerDevice({
             filters: [{services: ['health_thermometer']}],
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-get-same-object.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-get-same-object.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Calls to getPrimaryServices should return the same object.';
 let device;
 
 bluetooth_test(
     () =>
         getHealthThermometerDevice({
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-invalid-service-name.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-invalid-service-name.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Wrong Service name. Reject with TypeError.';
 const expected = new DOMException(
     'Failed to execute \'getPrimaryServices\' on ' +
         '\'BluetoothRemoteGATTServer\': Invalid Service name: ' +
         '\'wrong_name\'. It must be a valid UUID alias (e.g. 0x1234), ' +
         'UUID (lowercase hex characters e.g. ' +
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-no-permission-absent-service-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-no-permission-absent-service-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Request for absent service without permission. ' +
     'Reject with SecurityError.';
 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',
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-no-permission-for-any-service-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-no-permission-for-any-service-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Request for present service without permission to access ' +
     'any service. Reject with SecurityError.';
 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',
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-no-permission-for-any-service.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-no-permission-for-any-service.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Request for present service without permission to access ' +
     'any service. Reject with SecurityError.';
 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',
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-no-permission-present-service-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-no-permission-present-service-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Request for present service without permission. ' +
     'Reject with SecurityError.';
 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');
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-service-not-found-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/gen-service-not-found-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Request for absent service. Reject with NotFoundError.';
 
 bluetooth_test(
     () => getHealthThermometerDevice({
             filters: [{services: ['health_thermometer']}],
             optionalServices: ['glucose']
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/services-found-with-uuid.https.html
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/services-found-with-uuid.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Request for services. Should return right number of ' +
     'services.';
 
 bluetooth_test(() => getTwoHealthThermometerServicesDevice({
   filters: [{services: ['health_thermometer']}]
 })
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/services-found.https.html
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/services-found.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Find all services in a device.';
 
 bluetooth_test(() => getTwoHealthThermometerServicesDevice({
   filters: [{services: ['health_thermometer']}],
   optionalServices: ['generic_access']
 })
--- a/testing/web-platform/tests/bluetooth/server/getPrimaryServices/services-not-found.https.html
+++ b/testing/web-platform/tests/bluetooth/server/getPrimaryServices/services-not-found.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Request for services in a device with no services. Reject ' +
     'with NotFoundError.';
 const expected = new DOMException('No Services found in device.',
     'NotFoundError');
 
 bluetooth_test(() => getEmptyHealthThermometerDevice()
--- a/testing/web-platform/tests/bluetooth/service/device-same-from-2-services.https.html
+++ b/testing/web-platform/tests/bluetooth/service/device-same-from-2-services.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Same parent device returned from multiple services.';
 
 bluetooth_test(
     () => getTwoHealthThermometerServicesDevice(
               {filters: [{services: ['health_thermometer']}]})
               .then(
--- a/testing/web-platform/tests/bluetooth/service/device-same-object.https.html
+++ b/testing/web-platform/tests/bluetooth/service/device-same-object.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = '[SameObject] test for BluetoothRemoteGATTService device.';
 
 bluetooth_test(
     () => getHealthThermometerDevice(
               {filters: [{services: ['health_thermometer']}]})
               .then(
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristic/characteristic-found.https.html
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/characteristic-found.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Request for characteristic. Should return right ' +
     'characteristic.';
 let device, service;
 
 bluetooth_test(() => getHealthThermometerDevice()
     .then(_ => ({device} = _))
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-blocklisted-characteristic.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-blocklisted-characteristic.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Serial Number String characteristic is blocklisted. ' +
     'Should reject with SecurityError.';
 const expected = new DOMException(
     'getCharacteristic(s) called with blocklisted UUID. https://goo.gl/4NeimX',
     'SecurityError');
 
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-characteristic-not-found.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-characteristic-not-found.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Request for absent characteristics with UUID. ' +
     'Reject with NotFoundError.';
 
 bluetooth_test(
     () => getEmptyHealthThermometerService().then(
         ({service}) => assert_promise_rejects_with_message(
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-garbage-collection-ran-during-error.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-garbage-collection-ran-during-error.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Garbage Collection ran during getCharacteristic ' +
     'call that fails. Should not crash';
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve characteristics. ' +
         '(Re)connect first with `device.gatt.connect`.',
     'NetworkError');
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-get-same-object.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-get-same-object.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Calls to getCharacteristic should return the same object.';
 
 bluetooth_test(
     () =>
         getHealthThermometerService()
             .then(({service}) => Promise.all([
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-invalid-characteristic-name.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-invalid-characteristic-name.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Wrong Characteristic name. Reject with TypeError.';
 const expected = new DOMException(
     'Failed to execute \'getCharacteristic\' on ' +
         '\'BluetoothRemoteGATTService\': Invalid Characteristic name: ' +
         '\'wrong_name\'. ' +
         'It must be a valid UUID alias (e.g. 0x1234), ' +
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-reconnect-during.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-reconnect-during.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'disconnect() and connect() called during ' +
     'getCharacteristic. Reject with NetworkError.';
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve characteristics. ' +
         '(Re)connect first with `device.gatt.connect`.',
     'NetworkError');
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-service-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-service-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Service is removed before getCharacteristic call. ' +
     'Reject with InvalidStateError.';
 const expected =
     new DOMException('GATT Service no longer exists.', 'InvalidStateError');
 let service, fake_service, fake_peripheral;
 
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristics/blocklisted-characteristics.https.html
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/blocklisted-characteristics.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'The Device Information service is composed of blocklisted ' +
     'characteristics so we shouldn\'t find any.';
 const expected = new DOMException('No Characteristics found in service.',
     'NotFoundError');
 let device;
 
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-found-with-uuid.https.html
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-found-with-uuid.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Find characteristics with UUID in service.';
 let device, fake_peripheral;
 
 bluetooth_test(() => getDiscoveredHealthThermometerDevice()
     .then(_ => ({device, fake_peripheral} = _ ))
     // Setup a device with two measurement intervals.
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-found.https.html
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-found.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Find all characteristics in a service.';
 let device, fake_peripheral;
 
 bluetooth_test(() => getDiscoveredHealthThermometerDevice()
     .then(_ => ({device, fake_peripheral} = _))
     // Setup a device with two measurement intervals.
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-not-found.https.html
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-not-found.https.html
@@ -1,14 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/bluetooth/resources/bluetooth-test.js"></script>
+<script src="/bluetooth/resources/bluetooth-fake-devices.js"></script>
 <script>
 'use strict';
 const test_desc = 'Request for absent characteristics. Reject with ' +
     'NotFoundError.';
 const expected = new DOMException('No Characteristics found in service.',
     'NotFoundError');
 let service;
 
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-blocklisted-characteristic-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-blocklisted-characteristic-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Serial Number String characteristic is blocklisted. ' +
     'Should reject with SecurityError.';
 const expected = new DOMException(
     'getCharacteristic(s) called with blocklisted UUID. https://goo.gl/4NeimX',
     'SecurityError');
 
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-characteristic-not-found-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-characteristic-not-found-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Request for absent characteristics with UUID. ' +
     'Reject with NotFoundError.';
 
 bluetooth_test(
     () => getEmptyHealthThermometerService().then(
         ({service}) => assert_promise_rejects_with_message(
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-garbage-collection-ran-during-error-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-garbage-collection-ran-during-error-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Garbage Collection ran during getCharacteristics ' +
     'call that fails. Should not crash';
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve characteristics. ' +
         '(Re)connect first with `device.gatt.connect`.',
     'NetworkError');
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-garbage-collection-ran-during-error.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-garbage-collection-ran-during-error.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Garbage Collection ran during getCharacteristics ' +
     'call that fails. Should not crash';
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve characteristics. ' +
         '(Re)connect first with `device.gatt.connect`.',
     'NetworkError');
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-get-same-object-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-get-same-object-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Calls to getCharacteristics should return the same object.';
 
 bluetooth_test(
     () =>
         getHealthThermometerService()
             .then(({service}) => Promise.all([
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-get-same-object.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-get-same-object.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Calls to getCharacteristics should return the same object.';
 
 bluetooth_test(
     () =>
         getHealthThermometerService()
             .then(({service}) => Promise.all([
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-invalid-characteristic-name.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-invalid-characteristic-name.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Wrong Characteristic name. Reject with TypeError.';
 const expected = new DOMException(
     'Failed to execute \'getCharacteristics\' on ' +
         '\'BluetoothRemoteGATTService\': Invalid Characteristic name: ' +
         '\'wrong_name\'. ' +
         'It must be a valid UUID alias (e.g. 0x1234), ' +
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-reconnect-during-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-reconnect-during-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'disconnect() and connect() called during ' +
     'getCharacteristics. Reject with NetworkError.';
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve characteristics. ' +
         '(Re)connect first with `device.gatt.connect`.',
     'NetworkError');
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-reconnect-during.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-reconnect-during.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'disconnect() and connect() called during ' +
     'getCharacteristics. Reject with NetworkError.';
 const expected = new DOMException(
     'GATT Server is disconnected. Cannot retrieve characteristics. ' +
         '(Re)connect first with `device.gatt.connect`.',
     'NetworkError');
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-service-is-removed-with-uuid.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-service-is-removed-with-uuid.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Service is removed before getCharacteristics call. ' +
     'Reject with InvalidStateError.';
 const expected =
     new DOMException('GATT Service no longer exists.', 'InvalidStateError');
 let service, fake_service, fake_peripheral;
 
--- a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-service-is-removed.https.window.js
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-service-is-removed.https.window.js
@@ -1,11 +1,12 @@
 // META: script=/resources/testdriver.js
 // META: script=/resources/testdriver-vendor.js
-// META: script=/bluetooth/resources/bluetooth-helpers.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
 // Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
 'use strict';
 const test_desc = 'Service is removed before getCharacteristics call. ' +
     'Reject with InvalidStateError.';
 const expected =
     new DOMException('GATT Service no longer exists.', 'InvalidStateError');
 let service, fake_service, fake_peripheral;