Skip to content

Commit 43b16bd

Browse files
committed
Allow for running a script in an arbitrary frame context
1 parent 178ab72 commit 43b16bd

File tree

2 files changed

+64
-9
lines changed

2 files changed

+64
-9
lines changed

internal/devtools.py

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ def __init__(self, options, job, task, use_devtools_video, is_webkit, is_ios):
8888
self.main_thread_blocked = False
8989
self.stylesheets = {}
9090
self.headers = {}
91+
self.execution_contexts = {}
92+
self.execution_context = None
9193
self.trace_parser = None
9294
self.prepare()
9395
self.html_body = False
@@ -564,6 +566,12 @@ def stop_recording(self):
564566
# Add the audit issues to the page data
565567
if len(self.audit_issues):
566568
self.task['page_data']['audit_issues'] = self.audit_issues
569+
# Add the list of execution contexts
570+
contexts = []
571+
for id in self.execution_contexts:
572+
contexts.append(self.execution_contexts[id])
573+
if len(contexts):
574+
self.task['page_data']['execution_contexts'] = contexts
567575
# Process the timeline data
568576
if self.trace_parser is not None:
569577
start = monotonic()
@@ -1174,7 +1182,7 @@ def colors_are_similar(self, color1, color2, threshold=15):
11741182
similar = False
11751183
return similar
11761184

1177-
def execute_js(self, script):
1185+
def execute_js(self, script, use_execution_context=False):
11781186
"""Run the provided JS in the browser and return the result"""
11791187
if self.must_exit:
11801188
return
@@ -1183,18 +1191,35 @@ def execute_js(self, script):
11831191
if self.is_webkit:
11841192
response = self.send_command('Runtime.evaluate', {'expression': script, 'returnByValue': True}, timeout=30, wait=True)
11851193
else:
1186-
response = self.send_command("Runtime.evaluate",
1187-
{'expression': script,
1188-
'awaitPromise': True,
1189-
'returnByValue': True,
1190-
'timeout': 30000},
1191-
wait=True, timeout=30)
1194+
params = {'expression': script,
1195+
'awaitPromise': True,
1196+
'returnByValue': True,
1197+
'timeout': 30000}
1198+
if use_execution_context and self.execution_context is not None:
1199+
params['contextId'] = self.execution_context
1200+
response = self.send_command("Runtime.evaluate", params, wait=True, timeout=30)
11921201
if response is not None and 'result' in response and\
11931202
'result' in response['result'] and\
11941203
'value' in response['result']['result']:
11951204
ret = response['result']['result']['value']
11961205
return ret
11971206

1207+
def set_execution_context(self, target):
1208+
""" Set the js execution context by matching id, origin or name """
1209+
if len(target):
1210+
parts = target.split('=', 1)
1211+
if len(parts) == 2:
1212+
key = parts[0].strip()
1213+
value = parts[1].strip()
1214+
if key in ['id', 'name', 'origin'] and len(value):
1215+
for id in self.execution_contexts:
1216+
context = self.execution_contexts[id]
1217+
if key in context and context[key] == value:
1218+
self.execution_context = id
1219+
break
1220+
else:
1221+
self.execution_context = None
1222+
11981223
def set_header(self, header):
11991224
"""Add/modify a header on the outbound requests"""
12001225
if header is not None and len(header):
@@ -1309,6 +1334,7 @@ def enable_target(self, target_id=None):
13091334
self.send_command('Network.enable', {}, target_id=target_id)
13101335
self.send_command('Console.enable', {}, target_id=target_id)
13111336
self.send_command('Log.enable', {}, target_id=target_id)
1337+
self.send_command('Runtime.enable', {}, target_id=target_id)
13121338
self.send_command('Log.startViolationsReport', {'config': [{'name': 'discouragedAPIUse', 'threshold': -1}]}, target_id=target_id)
13131339
self.send_command('Audits.enable', {}, target_id=target_id)
13141340
self.job['shaper'].apply(target_id=target_id)
@@ -1423,6 +1449,8 @@ def process_message(self, msg, target_id=None):
14231449
self.process_css_event(event, msg)
14241450
elif category == 'Debugger':
14251451
self.process_debugger_event(event, msg)
1452+
elif category == 'Runtime':
1453+
self.process_runtime_event(event, msg)
14261454
elif category == 'Target':
14271455
log_event = False
14281456
self.process_target_event(event, msg)
@@ -1545,6 +1573,26 @@ def process_debugger_event(self, event, msg):
15451573
if event == 'paused':
15461574
self.send_command('Debugger.resume', {})
15471575

1576+
def process_runtime_event(self, event, msg):
1577+
"""Handle Runtime.* events"""
1578+
if event == 'executionContextCreated':
1579+
if 'params' in msg and 'context' in msg['params'] and 'id' in msg['params']['context'] and 'origin':
1580+
context = msg['params']['context']
1581+
id = context['id']
1582+
ctx = {'id': id}
1583+
if 'origin' in context:
1584+
ctx['origin'] = context['origin']
1585+
if 'name' in context:
1586+
ctx['name'] = context['name']
1587+
self.execution_contexts[id] = ctx
1588+
logging.debug('Execution context created: %s', json.dumps(context))
1589+
elif event == 'executionContextDestroyed':
1590+
if 'params' in msg and 'executionContextId' in msg['params']:
1591+
id = msg['params']['executionContextId']
1592+
if id in self.execution_contexts:
1593+
del self.execution_contexts[id]
1594+
logging.debug('Execution context %d deleted', id)
1595+
15481596
def process_network_event(self, event, msg, target_id=None):
15491597
"""Process Network.* dev tools events"""
15501598
if event == 'requestIntercepted':

internal/devtools_browser.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -689,9 +689,16 @@ def process_command(self, command):
689689
needs_mark = True
690690
if self.task['combine_steps']:
691691
needs_mark = False
692-
script = self.prepare_script_for_record(script, needs_mark) #pylint: disable=no-member
692+
if self.devtools.execution_context is not None:
693+
# Clear the orange frame as a separate step to make sure it is done in the correct context
694+
clear_script = self.prepare_script_for_record('', needs_mark)
695+
self.devtools.execute_js(clear_script)
696+
else:
697+
script = self.prepare_script_for_record(script, needs_mark) #pylint: disable=no-member
693698
self.devtools.start_navigating()
694-
self.devtools.execute_js(script)
699+
self.devtools.execute_js(script, True)
700+
elif command['command'] == 'setexecutioncontext':
701+
self.devtools.set_execution_context(command['target'])
695702
elif command['command'] == 'sleep':
696703
available_sleep = 60 - self.total_sleep
697704
delay = min(available_sleep, max(0, int(re.search(r'\d+', str(command['target'])).group())))

0 commit comments

Comments
 (0)