|
15 | 15 |
|
16 | 16 | import pytest |
17 | 17 | import pytest_asyncio |
18 | | -from test_helpers import execute_command |
| 18 | +from test_helpers import (execute_command, send_JSON_command, subscribe, |
| 19 | + wait_for_event) |
19 | 20 |
|
20 | 21 | from . import (BATTERY_SERVICE_UUID, |
21 | 22 | CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR_UUID, |
|
25 | 26 | create_gatt_connection, disable_simulation, setup_device, |
26 | 27 | setup_granted_device, simulate_descriptor, simulate_service) |
27 | 28 |
|
| 29 | +DESCRIPTOR_EVENT_GENERATED = 'bluetooth.descriptorEventGenerated' |
| 30 | + |
| 31 | + |
| 32 | +async def setup_descriptor(websocket, context_id: str, html, service_uuid: str, |
| 33 | + characteristic_uuid: str, characteristic_properties, |
| 34 | + descriptor_uuid: str): |
| 35 | + device_address = await setup_granted_device(websocket, context_id, html, |
| 36 | + [service_uuid]) |
| 37 | + await create_gatt_connection(websocket, context_id) |
| 38 | + await simulate_service(websocket, context_id, device_address, service_uuid, |
| 39 | + 'add') |
| 40 | + await add_characteristic(websocket, context_id, device_address, |
| 41 | + service_uuid, characteristic_uuid, |
| 42 | + characteristic_properties) |
| 43 | + await simulate_descriptor(websocket, context_id, device_address, |
| 44 | + service_uuid, characteristic_uuid, |
| 45 | + descriptor_uuid, 'add') |
| 46 | + return device_address |
| 47 | + |
28 | 48 |
|
29 | 49 | async def get_descriptors(websocket, context_id: str, service_uuid: str, |
30 | 50 | characteristic_uuid: str) -> list[str]: |
@@ -265,3 +285,137 @@ async def test_bluetooth_add_descriptor_to_unknown_characteristic( |
265 | 285 | websocket, context_id, device_address, HEART_RATE_SERVICE_UUID, |
266 | 286 | MEASUREMENT_INTERVAL_CHARACTERISTIC_UUID, |
267 | 287 | CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR_UUID, 'add') |
| 288 | + |
| 289 | + |
| 290 | +@pytest.mark.asyncio |
| 291 | +@pytest.mark.parametrize('capabilities', [{ |
| 292 | + 'goog:chromeOptions': { |
| 293 | + 'args': ['--enable-features=WebBluetooth'] |
| 294 | + } |
| 295 | +}], |
| 296 | + indirect=True) |
| 297 | +async def test_bluetooth_descriptor_write_event(websocket, context_id, html): |
| 298 | + await setup_descriptor(websocket, context_id, html, |
| 299 | + HEART_RATE_SERVICE_UUID, |
| 300 | + MEASUREMENT_INTERVAL_CHARACTERISTIC_UUID, |
| 301 | + {'write': True}, |
| 302 | + CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR_UUID) |
| 303 | + await subscribe(websocket, [DESCRIPTOR_EVENT_GENERATED]) |
| 304 | + expected_data = [42, 27] |
| 305 | + await send_JSON_command( |
| 306 | + websocket, { |
| 307 | + 'method': 'script.evaluate', |
| 308 | + 'params': { |
| 309 | + 'expression': f''' |
| 310 | + (async () => {{ |
| 311 | + const service = await device.gatt.getPrimaryService('{HEART_RATE_SERVICE_UUID}'); |
| 312 | + const characteristic = await service.getCharacteristic('{MEASUREMENT_INTERVAL_CHARACTERISTIC_UUID}'); |
| 313 | + const descriptor = await characteristic.getDescriptor('{CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR_UUID}'); |
| 314 | + await descriptor.writeValue(new Uint8Array({expected_data})); |
| 315 | + }})(); |
| 316 | + ''', |
| 317 | + 'awaitPromise': False, |
| 318 | + 'target': { |
| 319 | + 'context': context_id, |
| 320 | + }, |
| 321 | + 'userActivation': True |
| 322 | + } |
| 323 | + }) |
| 324 | + event = await wait_for_event(websocket, DESCRIPTOR_EVENT_GENERATED) |
| 325 | + assert event['params'] == { |
| 326 | + 'context': context_id, |
| 327 | + 'address': FAKE_DEVICE_ADDRESS, |
| 328 | + 'serviceUuid': HEART_RATE_SERVICE_UUID, |
| 329 | + 'characteristicUuid': MEASUREMENT_INTERVAL_CHARACTERISTIC_UUID, |
| 330 | + 'descriptorUuid': CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR_UUID, |
| 331 | + 'type': 'write', |
| 332 | + 'data': expected_data, |
| 333 | + } |
| 334 | + |
| 335 | + await execute_command( |
| 336 | + websocket, { |
| 337 | + 'method': 'bluetooth.simulateDescriptorResponse', |
| 338 | + 'params': { |
| 339 | + 'context': context_id, |
| 340 | + 'address': FAKE_DEVICE_ADDRESS, |
| 341 | + 'serviceUuid': HEART_RATE_SERVICE_UUID, |
| 342 | + 'characteristicUuid': MEASUREMENT_INTERVAL_CHARACTERISTIC_UUID, |
| 343 | + 'descriptorUuid': CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR_UUID, |
| 344 | + 'type': 'write', |
| 345 | + 'code': 0x0 |
| 346 | + } |
| 347 | + }) |
| 348 | + |
| 349 | + |
| 350 | +@pytest.mark.asyncio |
| 351 | +@pytest.mark.parametrize('capabilities', [{ |
| 352 | + 'goog:chromeOptions': { |
| 353 | + 'args': ['--enable-features=WebBluetooth'] |
| 354 | + } |
| 355 | +}], |
| 356 | + indirect=True) |
| 357 | +async def test_bluetooth_descriptor_read_event(websocket, context_id, html): |
| 358 | + await setup_descriptor(websocket, context_id, html, |
| 359 | + HEART_RATE_SERVICE_UUID, |
| 360 | + MEASUREMENT_INTERVAL_CHARACTERISTIC_UUID, |
| 361 | + {'read': True}, |
| 362 | + CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR_UUID) |
| 363 | + await subscribe(websocket, [DESCRIPTOR_EVENT_GENERATED]) |
| 364 | + await send_JSON_command( |
| 365 | + websocket, { |
| 366 | + 'method': 'script.evaluate', |
| 367 | + 'params': { |
| 368 | + 'expression': f''' |
| 369 | + let readResult; |
| 370 | + (async () => {{ |
| 371 | + const service = await device.gatt.getPrimaryService('{HEART_RATE_SERVICE_UUID}'); |
| 372 | + const characteristic = await service.getCharacteristic('{MEASUREMENT_INTERVAL_CHARACTERISTIC_UUID}'); |
| 373 | + const descriptor = await characteristic.getDescriptor('{CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR_UUID}'); |
| 374 | + readResult = await descriptor.readValue(); |
| 375 | + }})(); |
| 376 | + ''', |
| 377 | + 'awaitPromise': False, |
| 378 | + 'target': { |
| 379 | + 'context': context_id, |
| 380 | + }, |
| 381 | + 'userActivation': True |
| 382 | + } |
| 383 | + }) |
| 384 | + event = await wait_for_event(websocket, DESCRIPTOR_EVENT_GENERATED) |
| 385 | + assert event['params'] == { |
| 386 | + 'context': context_id, |
| 387 | + 'address': FAKE_DEVICE_ADDRESS, |
| 388 | + 'serviceUuid': HEART_RATE_SERVICE_UUID, |
| 389 | + 'characteristicUuid': MEASUREMENT_INTERVAL_CHARACTERISTIC_UUID, |
| 390 | + 'descriptorUuid': CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR_UUID, |
| 391 | + 'type': 'read', |
| 392 | + } |
| 393 | + |
| 394 | + expected_data = [1, 2] |
| 395 | + await execute_command( |
| 396 | + websocket, { |
| 397 | + 'method': 'bluetooth.simulateDescriptorResponse', |
| 398 | + 'params': { |
| 399 | + 'context': context_id, |
| 400 | + 'address': FAKE_DEVICE_ADDRESS, |
| 401 | + 'serviceUuid': HEART_RATE_SERVICE_UUID, |
| 402 | + 'characteristicUuid': MEASUREMENT_INTERVAL_CHARACTERISTIC_UUID, |
| 403 | + 'descriptorUuid': CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR_UUID, |
| 404 | + 'type': 'read', |
| 405 | + 'code': 0x0, |
| 406 | + 'data': expected_data |
| 407 | + } |
| 408 | + }) |
| 409 | + response = await execute_command( |
| 410 | + websocket, { |
| 411 | + 'method': 'script.evaluate', |
| 412 | + 'params': { |
| 413 | + 'expression': 'String.fromCharCode(...new Uint8Array(readResult.buffer))', |
| 414 | + 'awaitPromise': False, |
| 415 | + 'target': { |
| 416 | + 'context': context_id, |
| 417 | + }, |
| 418 | + 'userActivation': True |
| 419 | + } |
| 420 | + }) |
| 421 | + assert [ord(c) for c in response['result']['value']] == expected_data |
0 commit comments