diff --git a/python/src/trezorlib/debuglink.py b/python/src/trezorlib/debuglink.py index 470dc6257a..218f2c1cb8 100644 --- a/python/src/trezorlib/debuglink.py +++ b/python/src/trezorlib/debuglink.py @@ -197,6 +197,14 @@ class DebugLink: self.t1_screenshot_directory: Optional[Path] = None self.t1_screenshot_counter = 0 + # Optional debug screen saver + self.debug_screen_file: Optional[Path] = None + self.last_screen_content = "" + + def set_debug_screen_file(self, file_path: Path) -> None: + Path(file_path).write_bytes(b"") + self.debug_screen_file = file_path + def open(self) -> None: self.transport.begin_session() @@ -304,10 +312,33 @@ class DebugLink: ) ret = self._call(decision, nowait=not wait) if ret is not None: + if self.debug_screen_file is not None: + self.save_debug_screen(ret.lines) return LayoutContent(ret.lines) + if self.debug_screen_file is not None: + layout = self.read_layout() + self.save_debug_screen(layout.lines) + return None + def save_debug_screen(self, lines: List[str]) -> None: + if self.debug_screen_file is not None: + if not self.debug_screen_file.exists(): + self.debug_screen_file.write_bytes(b"") + + content = "\n".join(lines) + + # Not writing the same screen twice + if content == self.last_screen_content: + return + + self.last_screen_content = content + + with open(self.debug_screen_file, "a") as f: + f.write(content) + f.write("\n" + 80 * "/" + "\n") + # Type overloads make sure that when we supply `wait=True` into `click()`, # it will always return `LayoutContent` and we do not need to assert `is not None`. diff --git a/tests/ui_tests/.gitignore b/tests/ui_tests/.gitignore index 3f2756cebe..c50d2d2aa9 100644 --- a/tests/ui_tests/.gitignore +++ b/tests/ui_tests/.gitignore @@ -1,5 +1,6 @@ *.png *.html *.zip +*.txt fixtures.suggestion.json fixtures.json.diff diff --git a/tests/ui_tests/__init__.py b/tests/ui_tests/__init__.py index eed6927291..d8a026f617 100644 --- a/tests/ui_tests/__init__.py +++ b/tests/ui_tests/__init__.py @@ -149,6 +149,10 @@ def screen_recording( shutil.rmtree(screen_path, ignore_errors=True) screen_path.mkdir() + # Start saving debugging trace into a file + debug_screen_file = screens_test_path / "screens.txt" + client.debug.set_debug_screen_file(debug_screen_file) + try: client.debug.start_recording(str(screen_path)) yield diff --git a/tests/ui_tests/reporting/testreport.py b/tests/ui_tests/reporting/testreport.py index 4c496a011f..a6d8fa5633 100644 --- a/tests/ui_tests/reporting/testreport.py +++ b/tests/ui_tests/reporting/testreport.py @@ -16,6 +16,7 @@ from . import download, html HERE = Path(__file__).resolve().parent REPORTS_PATH = HERE / "reports" / "test" RECORDED_SCREENS_PATH = Path(__file__).resolve().parent.parent / "screens" +SCREEN_TEXT_FILE = REPORTS_PATH / "screen_text.txt" STYLE = (HERE / "testreport.css").read_text() SCRIPT = (HERE / "testreport.js").read_text() @@ -201,6 +202,18 @@ def all_unique_screens(test_case_dirs: List[Path]) -> Path: return html.write(REPORTS_PATH, doc, ALL_UNIQUE_SCREENS) +def screen_text_report(test_case_dirs: List[Path]) -> None: + with open(SCREEN_TEXT_FILE, "w") as f2: + for test_case_dir in test_case_dirs: + screen_file = test_case_dir / "screens.txt" + if not screen_file.exists(): + continue + f2.write(f"\n{test_case_dir.name}\n") + with open(screen_file, "r") as f: + for line in f.readlines(): + f2.write(f"\t{line}") + + def generate_reports() -> None: """Generate HTML reports for the test.""" index() @@ -210,6 +223,7 @@ def generate_reports() -> None: current_testcases = _get_testcases_dirs() all_screens(current_testcases) all_unique_screens(current_testcases) + screen_text_report(current_testcases) def _img_hash(img: Path) -> str: