1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-07-07 15:18:08 +00:00

feat(tests): allow for saving text layout of all screens during UI tests

[no changelog]
This commit is contained in:
grdddj 2023-01-18 11:57:32 +01:00
parent dff0699422
commit d928a390d8
5 changed files with 44 additions and 9 deletions

View File

@ -115,7 +115,7 @@ test_emu_ui: ## run ui integration tests
test_emu_ui_multicore: ## run ui integration tests using multiple cores test_emu_ui_multicore: ## run ui integration tests using multiple cores
PYTEST_TIMEOUT=200 $(PYTEST) -n auto $(TESTPATH)/device_tests $(TESTOPTS) \ PYTEST_TIMEOUT=200 $(PYTEST) -n auto $(TESTPATH)/device_tests $(TESTOPTS) \
--ui=test --ui-check-missing --not-generate-report-after-each-test \ --ui=test --ui-check-missing --not-generate-report-after-each-test --record-text-layout \
--control-emulators --model=core --random-order-seed=$(shell echo $$RANDOM) --control-emulators --model=core --random-order-seed=$(shell echo $$RANDOM)
test_emu_ui_record: ## record and hash screens for ui integration tests test_emu_ui_record: ## record and hash screens for ui integration tests

View File

@ -312,17 +312,24 @@ class DebugLink:
hold_ms=hold_ms, hold_ms=hold_ms,
) )
# Optionally saving the textual screen output
if self.screen_text_file is not None:
layout = self.read_layout()
self.save_debug_screen(layout.lines)
ret = self._call(decision, nowait=not wait) ret = self._call(decision, nowait=not wait)
if ret is not None: if ret is not None:
return LayoutContent(ret.lines) return LayoutContent(ret.lines)
# Getting the current screen after the (nowait) decision
self.save_current_screen_if_relevant(wait=False)
return None return None
def save_current_screen_if_relevant(self, wait: bool = True) -> None:
"""Optionally saving the textual screen output."""
if self.screen_text_file is not None:
if wait:
layout = self.wait_layout()
else:
layout = self.read_layout()
self.save_debug_screen(layout.lines)
def save_debug_screen(self, lines: List[str]) -> None: def save_debug_screen(self, lines: List[str]) -> None:
if self.screen_text_file is not None: if self.screen_text_file is not None:
if not self.screen_text_file.exists(): if not self.screen_text_file.exists():
@ -503,6 +510,12 @@ class DebugUI:
self.debuglink.take_t1_screenshot_if_relevant() self.debuglink.take_t1_screenshot_if_relevant()
if self.input_flow is None: if self.input_flow is None:
# Only calling screen-saver when not in input-flow
# as it collides with wait-layout of input flows.
# All input flows call debuglink.input(), so
# recording their screens that way (as well as
# possible swipes below).
self.debuglink.save_current_screen_if_relevant(wait=True)
if br.code == messages.ButtonRequestType.PinEntry: if br.code == messages.ButtonRequestType.PinEntry:
self.debuglink.input(self.get_pin()) self.debuglink.input(self.get_pin())
else: else:
@ -774,7 +787,6 @@ class TrezorClientDebugLink(TrezorClient):
def __exit__(self, exc_type: Any, value: Any, traceback: Any) -> None: def __exit__(self, exc_type: Any, value: Any, traceback: Any) -> None:
__tracebackhide__ = True # for pytest # pylint: disable=W0612 __tracebackhide__ = True # for pytest # pylint: disable=W0612
self.watch_layout(False)
# copy expected/actual responses before clearing them # copy expected/actual responses before clearing them
expected_responses = self.expected_responses expected_responses = self.expected_responses
actual_responses = self.actual_responses actual_responses = self.actual_responses

View File

@ -366,8 +366,7 @@ def pytest_addoption(parser: "Parser") -> None:
action="store_true", action="store_true",
default=False, default=False,
help="Saving debugging traces for each screen change. " help="Saving debugging traces for each screen change. "
"Will generate a report with text from all test-cases. " "Will generate a report with text from all test-cases. ",
"WARNING: does not work well with multicore (causes freezing).",
) )

View File

@ -158,6 +158,10 @@ def screen_recording(
screen_path.mkdir() screen_path.mkdir()
try: try:
if record_text_layout:
screen_text_file = screens_test_path / "screens.txt"
client.debug.watch_layout(True)
client.debug.set_screen_text_file(screen_text_file)
client.debug.start_recording(str(screen_path)) client.debug.start_recording(str(screen_path))
client.debug.set_screen_text_file(screen_text_file) client.debug.set_screen_text_file(screen_text_file)
yield yield
@ -165,6 +169,9 @@ def screen_recording(
# Wait for response to Initialize, which gives the emulator time to catch up # Wait for response to Initialize, which gives the emulator time to catch up
# and redraw the homescreen. Otherwise there's a race condition between that # and redraw the homescreen. Otherwise there's a race condition between that
# and stopping recording. # and stopping recording.
if record_text_layout:
client.debug.set_screen_text_file(None)
client.debug.watch_layout(False)
client.init_device() client.init_device()
client.debug.stop_recording() client.debug.stop_recording()
client.debug.set_screen_text_file(None) client.debug.set_screen_text_file(None)

View File

@ -204,6 +204,7 @@ def all_unique_screens(test_case_dirs: List[Path]) -> Path:
def screen_text_report(test_case_dirs: List[Path]) -> None: def screen_text_report(test_case_dirs: List[Path]) -> None:
"""Generate a report with text representation of all screens."""
with open(SCREEN_TEXT_FILE, "w") as f2: with open(SCREEN_TEXT_FILE, "w") as f2:
for test_case_dir in test_case_dirs: for test_case_dir in test_case_dirs:
screen_file = test_case_dir / "screens.txt" screen_file = test_case_dir / "screens.txt"
@ -214,6 +215,22 @@ def screen_text_report(test_case_dirs: List[Path]) -> None:
for line in f.readlines(): for line in f.readlines():
f2.write(f"\t{line}") f2.write(f"\t{line}")
# TODO: decide which is better - .txt or .html (maybe both?)
doc = dominate.document(title="Screen text report")
with doc:
for test_case_dir in test_case_dirs:
screen_file = test_case_dir / "screens.txt"
if not screen_file.exists():
continue
with a(href=f"{ALL_SCREENS}#{test_case_dir.name}"):
h2(test_case_dir.name)
with open(screen_file, "r") as f:
for line in f.readlines():
p(line)
html.write(REPORTS_PATH, doc, "screen_text.html")
def differing_screens(test_case_dirs: List[Path]) -> None: def differing_screens(test_case_dirs: List[Path]) -> None:
"""Creating an HTML page showing all the unique screens that got changed.""" """Creating an HTML page showing all the unique screens that got changed."""