diff --git a/core/Makefile b/core/Makefile index 20da39ebc0..e4b54d19d3 100644 --- a/core/Makefile +++ b/core/Makefile @@ -115,7 +115,7 @@ test_emu_ui: ## run ui integration tests test_emu_ui_multicore: ## run ui integration tests using multiple cores 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) test_emu_ui_record: ## record and hash screens for ui integration tests diff --git a/python/src/trezorlib/debuglink.py b/python/src/trezorlib/debuglink.py index e50d2fdb56..8dc7dce24f 100644 --- a/python/src/trezorlib/debuglink.py +++ b/python/src/trezorlib/debuglink.py @@ -312,17 +312,24 @@ class DebugLink: 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) if ret is not None: return LayoutContent(ret.lines) + # Getting the current screen after the (nowait) decision + self.save_current_screen_if_relevant(wait=False) + 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: if self.screen_text_file is not None: if not self.screen_text_file.exists(): @@ -503,6 +510,12 @@ class DebugUI: self.debuglink.take_t1_screenshot_if_relevant() 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: self.debuglink.input(self.get_pin()) else: @@ -774,7 +787,6 @@ class TrezorClientDebugLink(TrezorClient): def __exit__(self, exc_type: Any, value: Any, traceback: Any) -> None: __tracebackhide__ = True # for pytest # pylint: disable=W0612 - self.watch_layout(False) # copy expected/actual responses before clearing them expected_responses = self.expected_responses actual_responses = self.actual_responses diff --git a/tests/conftest.py b/tests/conftest.py index 737175aca1..438f682b35 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -366,8 +366,7 @@ def pytest_addoption(parser: "Parser") -> None: action="store_true", default=False, help="Saving debugging traces for each screen change. " - "Will generate a report with text from all test-cases. " - "WARNING: does not work well with multicore (causes freezing).", + "Will generate a report with text from all test-cases. ", ) diff --git a/tests/ui_tests/__init__.py b/tests/ui_tests/__init__.py index b5be41838e..f21c7ad7b3 100644 --- a/tests/ui_tests/__init__.py +++ b/tests/ui_tests/__init__.py @@ -158,6 +158,10 @@ def screen_recording( screen_path.mkdir() 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.set_screen_text_file(screen_text_file) yield @@ -165,6 +169,9 @@ def screen_recording( # 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 stopping recording. + if record_text_layout: + client.debug.set_screen_text_file(None) + client.debug.watch_layout(False) client.init_device() client.debug.stop_recording() client.debug.set_screen_text_file(None) diff --git a/tests/ui_tests/reporting/testreport.py b/tests/ui_tests/reporting/testreport.py index f84f7eeb4b..b2a3305084 100644 --- a/tests/ui_tests/reporting/testreport.py +++ b/tests/ui_tests/reporting/testreport.py @@ -204,6 +204,7 @@ def all_unique_screens(test_case_dirs: List[Path]) -> Path: 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: for test_case_dir in test_case_dirs: 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(): 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: """Creating an HTML page showing all the unique screens that got changed."""