Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2525,6 +2525,9 @@ def Action_Handler(_data_set, action_row, _bypass_bug=True):
CommonUtil.ExecLog(sModuleInfo, "Can't find module for %s" % module, 3)
return "zeuz_failed"
run_function = getattr(eval(module), function) # create a reference to the function
# Capture the BEFORE-action screen (debug/chatbot only) so the validator can
# compare it against the AFTER capture taken once the action completes.
CommonUtil.TakeScreenShot(function, pre_action=True)
start_time = time.perf_counter()
if pre_sleep:
time.sleep(pre_sleep)
Expand Down
41 changes: 35 additions & 6 deletions Framework/Utilities/CommonUtil.py
Original file line number Diff line number Diff line change
Expand Up @@ -849,9 +849,20 @@ def set_screenshot_vars(shared_variables):
ExecLog(sModuleInfo, "Error setting screenshot variables", 3)


def TakeScreenShot(function_name, local_run=False):
""" Puts TakeScreenShot into a thread, so it doesn't block test case execution """
def TakeScreenShot(function_name, local_run=False, pre_action=False):
""" Puts TakeScreenShot into a thread, so it doesn't block test case execution.

When pre_action=True, captures the screen state *before* the action runs so the
debug/chatbot validator can compare BEFORE vs AFTER. The pre-action capture only
runs in debug mode (the only mode that streams screenshots over live_log), is taken
synchronously without the post-action settle delay (we want the current state, not a
settled one), and is tagged with a distinct log marker so consumers can label it.
"""
if not ws_ss_log or performance_testing: return
# The before-image is only consumed by the debug/chatbot live_log stream, so skip it
# entirely for normal runs to avoid extra capture latency and screenshot volume.
if pre_action and not debug_status:
return
try:
if upload_on_fail and rerun_on_fail and not rerunning_on_fail and not debug_status:
return
Expand Down Expand Up @@ -879,9 +890,13 @@ def TakeScreenShot(function_name, local_run=False):
sModuleInfo, "Skipping screenshot due to screenshot or local_run setting", 0
)
return
capture_marker = (
"Capturing Pre-Action Screenshot for Action" if pre_action
else "Capturing Screenshot for Action"
)
ExecLog(
"",
"********** Capturing Screenshot for Action: %s Method: %s **********" % (function_name, Method),
"********** %s: %s Method: %s **********" % (capture_marker, function_name, Method),
4,
)
if current_action_name.strip().lower() in ("none", "undefined"):
Expand All @@ -898,6 +913,15 @@ def TakeScreenShot(function_name, local_run=False):
break
image_name = "Step#" + current_step_no + "_Action#" + current_action_no + "_" + filename

if pre_action:
# Capture synchronously and without the settle delay so the BEFORE frame is
# streamed over live_log before the action executes (and before the AFTER
# frame), keeping the two distinguishable in order on the consumer side.
Thread_ScreenShot(
function_name, image_folder, Method, Driver, image_name + "_pre", skip_delay=True
)
return

thread = executor.submit(Thread_ScreenShot, function_name, image_folder, Method, Driver, image_name)
SaveThread("screenshot", thread)

Expand Down Expand Up @@ -990,8 +1014,13 @@ def _get_window_screenshot_bbox():
return None


def Thread_ScreenShot(function_name, image_folder, Method, Driver, image_name):
""" Capture screen of mobile or desktop """
def Thread_ScreenShot(function_name, image_folder, Method, Driver, image_name, skip_delay=False):
""" Capture screen of mobile or desktop.

skip_delay=True bypasses the debug settle delay — used for pre-action (BEFORE)
captures, where the current on-screen state must be grabbed immediately rather than
after waiting for the UI to settle (which only makes sense for AFTER captures).
"""
if performance_testing: return
sModuleInfo = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME
chars_to_remove = [
Expand Down Expand Up @@ -1028,7 +1057,7 @@ def Thread_ScreenShot(function_name, image_folder, Method, Driver, image_name):
return
should_delay_before_capture = True

if should_delay_before_capture and not _wait_for_debug_screenshot_delay(sModuleInfo, function_name, Method):
if should_delay_before_capture and not skip_delay and not _wait_for_debug_screenshot_delay(sModuleInfo, function_name, Method):
return

# Capture screenshot of desktop
Expand Down
Loading