|
22 | 22 | import copy
|
23 | 23 | from contextlib import (contextmanager, asynccontextmanager)
|
24 | 24 | from importlib import import_module
|
| 25 | +import json |
25 | 26 | import pkgutil
|
26 | 27 | import warnings
|
27 | 28 | import sys
|
@@ -710,13 +711,16 @@ def find_elements_by_css_selector(self, css_selector):
|
710 | 711 | warnings.warn("find_elements_by_* commands are deprecated. Please use find_elements() instead")
|
711 | 712 | return self.find_elements(by=By.CSS_SELECTOR, value=css_selector)
|
712 | 713 |
|
713 |
| - def pin_script(self, script): |
| 714 | + def pin_script(self, script, script_key=None): |
714 | 715 | """
|
715 | 716 |
|
716 | 717 | """
|
717 |
| - script_key = ScriptKey() |
718 |
| - self.pinned_scripts[script_key.id] = script |
719 |
| - return script_key |
| 718 | + if not script_key: |
| 719 | + _script_key = ScriptKey() |
| 720 | + else: |
| 721 | + _script_key = ScriptKey(script_key) |
| 722 | + self.pinned_scripts[_script_key.id] = script |
| 723 | + return _script_key |
720 | 724 |
|
721 | 725 | def unpin(self, script_key):
|
722 | 726 | """
|
@@ -1483,6 +1487,42 @@ def get_log(self, log_type):
|
1483 | 1487 | """
|
1484 | 1488 | return self.execute(Command.GET_LOG, {'type': log_type})['value']
|
1485 | 1489 |
|
| 1490 | + @asynccontextmanager |
| 1491 | + async def log_mutation_events(self): |
| 1492 | + """ |
| 1493 | + Listens for mutation events and emits them as it finds them |
| 1494 | +
|
| 1495 | + :Usage: |
| 1496 | + :: |
| 1497 | +
|
| 1498 | + """ |
| 1499 | + _pkg = '.'.join(__name__.split('.')[:-1]) |
| 1500 | + mutation_listener_js = pkgutil.get_data(_pkg, 'mutation-listener.js').decode('utf8').strip() |
| 1501 | + |
| 1502 | + assert sys.version_info >= (3, 7) |
| 1503 | + global cdp |
| 1504 | + async with self._get_bidi_connection(): |
| 1505 | + global devtools |
| 1506 | + page = cdp.get_session_context('page.enable') |
| 1507 | + await page.execute(devtools.page.enable()) |
| 1508 | + runtime = cdp.get_session_context('runtime.enable') |
| 1509 | + await runtime.execute(devtools.runtime.enable()) |
| 1510 | + await runtime.execute(devtools.runtime.add_binding("__webdriver_attribute")) |
| 1511 | + self.pin_script(mutation_listener_js) |
| 1512 | + script_key = await page.execute(devtools.page.add_script_to_evaluate_on_new_document(mutation_listener_js)) |
| 1513 | + self.pin_script(mutation_listener_js, script_key) |
| 1514 | + self.execute_script(f"return {mutation_listener_js}") |
| 1515 | + event = {} |
| 1516 | + async with runtime.wait_for(devtools.runtime.BindingCalled) as evnt: |
| 1517 | + yield event |
| 1518 | + |
| 1519 | + payload = json.loads(evnt.value.payload) |
| 1520 | + elements = self.find_elements(By.CSS_SELECTOR, "*[data-__webdriver_id={}".format(payload['target'])) |
| 1521 | + # event["element"] = elements[0] |
| 1522 | + event["attribute_name"] = payload['name'] |
| 1523 | + event["current_value"] = payload['value'] |
| 1524 | + event["old_value"] = payload['oldValue'] |
| 1525 | + |
1486 | 1526 | @asynccontextmanager
|
1487 | 1527 | async def add_js_error_listener(self):
|
1488 | 1528 | """
|
|
0 commit comments