diff --git a/tests/buttons.py b/tests/buttons.py index ee759d23ef..cacb3b5eb8 100644 --- a/tests/buttons.py +++ b/tests/buttons.py @@ -6,167 +6,227 @@ from trezorlib.debuglink import LayoutType Coords = Tuple[int, int] -# display dimensions -def display_height(layout_type): - if layout_type in (LayoutType.Bolt, LayoutType.Delizia): +class ScreenButtons: + def __init__(self, layout_type: LayoutType): + assert layout_type in (LayoutType.Bolt, LayoutType.Delizia) + self.layout_type = layout_type + + def _width(self) -> int: return 240 - else: - raise ValueError("Wrong layout type") - -def display_width(layout_type): - if layout_type in (LayoutType.Bolt, LayoutType.Delizia): + def _height(self) -> int: return 240 - else: - raise ValueError("Wrong layout type") + def _grid(self, dim: int, grid_cells: int, cell: int) -> int: + assert cell < grid_cells + step = dim // grid_cells + ofs = step // 2 + return cell * step + ofs -# grid coordinates -def grid(dim: int, grid_cells: int, cell: int) -> int: - step = dim // grid_cells - ofs = step // 2 - return cell * step + ofs + # 3 columns, 4 rows, 1st row is input area + def _grid35(self, x: int, y: int) -> Coords: + return self._grid(self._width(), 3, x), self._grid(self._height(), 5, y) + # TODO: do not expose this + # 3 columns, 3 rows, 1st row is input area + def grid34(self, x: int, y: int) -> Coords: + return self._grid(self._width(), 3, x), self._grid(self._height(), 4, y) -def grid35(x: int, y: int, layout_type: LayoutType) -> Coords: - return grid(display_width(layout_type), 3, x), grid( - display_height(layout_type), 5, y - ) + # Horizontal coordinates + def _left(self) -> int: + return self._grid(self._width(), 3, 0) + def _mid(self) -> int: + return self._grid(self._width(), 3, 1) -def grid34(x: int, y: int, layout_type: LayoutType) -> Coords: - assert layout_type in (LayoutType.Bolt, LayoutType.Delizia) - return grid(display_width(layout_type), 3, x), grid( - display_height(layout_type), 4, y - ) + def _right(self) -> int: + return self._grid(self._width(), 3, 2) + # Vertical coordinates + def _top(self) -> int: + return self._grid(self._height(), 6, 0) -def _grid34_from_index(idx: int, layout_type: LayoutType) -> Coords: - grid_x = idx % 3 - grid_y = idx // 3 + 1 # first line is empty - return grid34(grid_x, grid_y, layout_type) + def _bottom(self) -> int: + return self._grid(self._height(), 6, 5) + # Buttons -# Horizontal coordinates -def left(layout_type: LayoutType): - return grid(display_width(layout_type), 3, 0) + # Right bottom + def ok(self) -> Coords: + return (self._right(), self._bottom()) + # Left bottom + def cancel(self) -> Coords: + return (self._left(), self._bottom()) -def mid(layout_type: LayoutType): - return grid(display_width(layout_type), 3, 1) + # Mid bottom + def info(self) -> Coords: + return (self._mid(), self._bottom()) + # Menu/close menu button + def menu(self) -> Coords: + if self.layout_type in (LayoutType.Bolt, LayoutType.Delizia): + return (215, 25) + else: + raise ValueError("Wrong layout type") -def right(layout_type: LayoutType): - return grid(display_width(layout_type), 3, 2) + # Center of the screen + def tap_to_confirm(self) -> Coords: + assert self.layout_type is LayoutType.Delizia + return (self._grid(self._width(), 1, 0), self._grid(self._width(), 1, 0)) + # Yes/No decision component + def ui_yes(self) -> Coords: + assert self.layout_type is LayoutType.Delizia + return self.grid34(2, 2) -# Vertical coordinates -def top(layout_type: LayoutType): - return grid(display_height(layout_type), 6, 0) + def ui_no(self) -> Coords: + assert self.layout_type is LayoutType.Delizia + return self.grid34(0, 2) + # +/- buttons in number input component + def number_input_minus(self) -> Coords: + if self.layout_type is LayoutType.Bolt: + return (self._left(), self._grid(self._height(), 5, 1)) + elif self.layout_type is LayoutType.Delizia: + return (self._left(), self._grid(self._height(), 5, 3)) + else: + raise ValueError("Wrong layout type") -def bottom(layout_type: LayoutType): - return grid(display_height(layout_type), 6, 5) + def number_input_plus(self) -> Coords: + if self.layout_type is LayoutType.Bolt: + return (self._right(), self._grid(self._height(), 5, 1)) + elif self.layout_type is LayoutType.Delizia: + return (self._right(), self._grid(self._height(), 5, 3)) + else: + raise ValueError("Wrong layout type") + def word_count_all_word(self, word_count: int) -> Coords: + assert word_count in (12, 18, 20, 24, 33) + if self.layout_type is LayoutType.Bolt: + coords_map = { + 12: self.grid34(0, 2), + 18: self.grid34(1, 2), + 20: self.grid34(2, 2), + 24: self.grid34(1, 3), + 33: self.grid34(2, 3), + } + elif self.layout_type is LayoutType.Delizia: + coords_map = { + 12: self.grid34(0, 1), + 18: self.grid34(2, 1), + 20: self.grid34(0, 2), + 24: self.grid34(2, 2), + 33: self.grid34(2, 3), + } + else: + raise ValueError("Wrong layout type") -# Buttons + return coords_map[word_count] + def word_count_all_cancel(self) -> Coords: + if self.layout_type is LayoutType.Bolt: + return self.grid34(0, 3) -def ok(layout_type: LayoutType) -> Coords: - return (right(layout_type), bottom(layout_type)) + elif self.layout_type is LayoutType.Delizia: + return self.grid34(0, 3) + else: + raise ValueError("Wrong layout type") -def cancel(layout_type: LayoutType) -> Coords: - return (left(layout_type), bottom(layout_type)) + def word_count_repeated_word(self, word_count: int) -> Coords: + assert word_count in (20, 33) + if self.layout_type is LayoutType.Bolt: + coords_map = { + 20: self.grid34(1, 2), + 33: self.grid34(2, 2), + } + elif self.layout_type is LayoutType.Delizia: + coords_map = { + 20: self.grid34(0, 1), + 33: self.grid34(2, 1), + } + else: + raise ValueError("Wrong layout type") + return coords_map[word_count] -def info(layout_type: LayoutType) -> Coords: - return (mid(layout_type), bottom(layout_type)) + def word_count_repeated_cancel(self) -> Coords: + if self.layout_type is LayoutType.Bolt: + return self.grid34(0, 2) + elif self.layout_type is LayoutType.Delizia: + return self.grid34(0, 3) -def recovery_delete(layout_type: LayoutType) -> Coords: - if layout_type in (LayoutType.Bolt, LayoutType.Delizia): - return (left(layout_type), top(layout_type)) - else: - raise ValueError("Wrong layout type") + else: + raise ValueError("Wrong layout type") + # select word component buttons + def word_check_words(self) -> "list[Coords]": + if self.layout_type in (LayoutType.Bolt, LayoutType.Delizia): + return [ + (self._mid(), self._grid(self._height(), 5, 2)), + (self._mid(), self._grid(self._height(), 5, 3)), + (self._mid(), self._grid(self._height(), 5, 4)), + ] + else: + raise ValueError("Wrong layout type") -def corner_button(layout_type: LayoutType) -> Coords: - if layout_type in (LayoutType.Bolt, LayoutType.Delizia): - return (215, 25) - else: - raise ValueError("Wrong layout type") + # vertical menu buttons + def vertical_menu_items(self) -> "list[Coords]": + assert self.layout_type is LayoutType.Delizia - -def confirm_word(layout_type: LayoutType) -> Coords: - if layout_type in (LayoutType.Bolt, LayoutType.Delizia): - return (mid(layout_type), top(layout_type)) - else: - raise ValueError("Wrong layout type") - - -# PIN/passphrase input -def input(layout_type: LayoutType) -> Coords: - return (mid(layout_type), top(layout_type)) - - -# Yes/No decision component -def ui_yes(layout_type: LayoutType) -> Coords: - assert layout_type is LayoutType.Delizia - return grid34(2, 2, layout_type) - - -def ui_no(layout_type: LayoutType) -> Coords: - assert layout_type is LayoutType.Delizia - return grid34(0, 2, layout_type) - - -# +/- buttons in number input component -def reset_minus(layout_type: LayoutType) -> Coords: - if layout_type is LayoutType.Bolt: - return (left(layout_type), grid(display_height(layout_type), 5, 1)) - elif layout_type is LayoutType.Delizia: - return (left(layout_type), grid(display_height(layout_type), 5, 3)) - else: - raise ValueError("Wrong layout type") - - -def reset_plus(layout_type: LayoutType) -> Coords: - if layout_type is LayoutType.Bolt: - return (right(layout_type), grid(display_height(layout_type), 5, 1)) - elif layout_type is LayoutType.Delizia: - return (right(layout_type), grid(display_height(layout_type), 5, 3)) - else: - raise ValueError("Wrong layout type") - - -# select word component buttons -def reset_word_check(layout_type: LayoutType) -> Coords: - if layout_type in (LayoutType.Bolt, LayoutType.Delizia): return [ - (mid(layout_type), grid(display_height(layout_type), 5, 2)), - (mid(layout_type), grid(display_height(layout_type), 5, 3)), - (mid(layout_type), grid(display_height(layout_type), 5, 4)), + (self._mid(), self._grid(self._height(), 4, 1)), + (self._mid(), self._grid(self._height(), 4, 2)), + (self._mid(), self._grid(self._height(), 4, 3)), ] - else: - raise ValueError("Wrong layout type") + # Pin/passphrase keyboards + def pin_passphrase_index(self, idx: int) -> Coords: + assert idx < 10 + if idx == 9: + idx = 10 # last digit is in the middle + return self.pin_passphrase_grid(idx % 3, idx // 3) -# vertical menu buttons -def vertical_menu(layout_type: LayoutType) -> Coords: - if layout_type in (LayoutType.Bolt, LayoutType.Delizia): - return [ - (mid(layout_type), grid(display_height(layout_type), 4, 1)), - (mid(layout_type), grid(display_height(layout_type), 4, 2)), - (mid(layout_type), grid(display_height(layout_type), 4, 3)), - ] - else: - raise ValueError("Wrong layout type") + def pin_passphrase_grid(self, x: int, y: int) -> Coords: + assert x < 3, y < 4 + y += 1 # first line is empty + return self._grid35(x, y) + # PIN/passphrase input + def pin_passphrase_input(self) -> Coords: + return (self._mid(), self._top()) -def tap_to_confirm(layout_type: LayoutType) -> Coords: - assert layout_type is LayoutType.Delizia - return vertical_menu(layout_type)[1] + def pin_passphrase_erase(self) -> Coords: + return self.pin_passphrase_grid(0, 3) + + def passphrase_confirm(self) -> Coords: + if self.layout_type is LayoutType.Bolt: + return self.pin_passphrase_grid(2, 3) + elif self.layout_type is LayoutType.Delizia: + return (215, 25) + else: + raise ValueError("Wrong layout type") + + def pin_confirm(self) -> Coords: + return self.pin_passphrase_grid(2, 3) + + # Mnemonic keyboard + def mnemonic_from_index(self, idx: int) -> Coords: + return self.mnemonic_grid(idx) + + def mnemonic_grid(self, idx: int) -> Coords: + assert idx < 9 + grid_x = idx % 3 + grid_y = idx // 3 + 1 # first line is empty + return self.grid34(grid_x, grid_y) + + def mnemonic_erase(self) -> Coords: + return (self._left(), self._top()) + + def mnemonic_confirm(self) -> Coords: + return (self._mid(), self._top()) BUTTON_LETTERS_BIP39 = ("abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "vwx", "yz") @@ -194,57 +254,45 @@ def get_passphrase_choices(char: str) -> tuple[str, ...]: return PASSPHRASE_SPECIAL -def passphrase(char: str, layout_type: LayoutType) -> Tuple[Coords, int]: - choices = get_passphrase_choices(char) - idx = next(i for i, letters in enumerate(choices) if char in letters) - click_amount = choices[idx].index(char) + 1 - return pin_passphrase_index(idx, layout_type), click_amount +class ButtonActions: + def __init__(self, layout_type: LayoutType): + self.buttons = ScreenButtons(layout_type) + def passphrase(self, char: str) -> Tuple[Coords, int]: + choices = get_passphrase_choices(char) + idx = next(i for i, letters in enumerate(choices) if char in letters) + click_amount = choices[idx].index(char) + 1 + return self.buttons.pin_passphrase_index(idx), click_amount -def pin_passphrase_index(idx: int, layout_type: LayoutType) -> Coords: - if idx == 9: - idx = 10 # last digit is in the middle - return pin_passphrase_grid(idx, layout_type) + def type_word(self, word: str, is_slip39: bool = False) -> Iterator[Coords]: + if is_slip39: + yield from self._type_word_slip39(word) + else: + yield from self._type_word_bip39(word) + def _type_word_slip39(self, word: str) -> Iterator[Coords]: + for l in word: + idx = next( + i for i, letters in enumerate(BUTTON_LETTERS_SLIP39) if l in letters + ) + yield self.buttons.mnemonic_from_index(idx) -def pin_passphrase_grid(idx: int, layout_type: LayoutType) -> Coords: - grid_x = idx % 3 - grid_y = idx // 3 + 1 # first line is empty - return grid35(grid_x, grid_y, layout_type) + def _type_word_bip39(self, word: str) -> Iterator[Coords]: + coords_prev: Coords | None = None + for letter in word: + time.sleep(0.1) # not being so quick to miss something + coords, amount = self._letter_coords_and_amount(letter) + # If the button is the same as for the previous letter, + # waiting a second before pressing it again. + if coords == coords_prev: + time.sleep(1.1) + coords_prev = coords + for _ in range(amount): + yield coords - -def type_word( - word: str, layout_type: LayoutType, is_slip39: bool = False -) -> Iterator[Coords]: - if is_slip39: - yield from _type_word_slip39(word, layout_type) - else: - yield from _type_word_bip39(word, layout_type) - - -def _type_word_slip39(word: str, layout_type: LayoutType) -> Iterator[Coords]: - for l in word: - idx = next(i for i, letters in enumerate(BUTTON_LETTERS_SLIP39) if l in letters) - yield _grid34_from_index(idx, layout_type) - - -def _type_word_bip39(word: str, layout_type: LayoutType) -> Iterator[Coords]: - coords_prev: Coords | None = None - for letter in word: - time.sleep(0.1) # not being so quick to miss something - coords, amount = _letter_coords_and_amount(letter, layout_type) - # If the button is the same as for the previous letter, - # waiting a second before pressing it again. - if coords == coords_prev: - time.sleep(1.1) - coords_prev = coords - for _ in range(amount): - yield coords - - -def _letter_coords_and_amount( - letter: str, layout_type: LayoutType -) -> Tuple[Coords, int]: - idx = next(i for i, letters in enumerate(BUTTON_LETTERS_BIP39) if letter in letters) - click_amount = BUTTON_LETTERS_BIP39[idx].index(letter) + 1 - return _grid34_from_index(idx, layout_type), click_amount + def _letter_coords_and_amount(self, letter: str) -> Tuple[Coords, int]: + idx = next( + i for i, letters in enumerate(BUTTON_LETTERS_BIP39) if letter in letters + ) + click_amount = BUTTON_LETTERS_BIP39[idx].index(letter) + 1 + return self.buttons.mnemonic_from_index(idx), click_amount diff --git a/tests/click_tests/common.py b/tests/click_tests/common.py index 9e51910c2f..30ff151b54 100644 --- a/tests/click_tests/common.py +++ b/tests/click_tests/common.py @@ -49,7 +49,8 @@ def get_char_category(char: str) -> PassphraseCategory: def go_next(debug: "DebugLink") -> LayoutContent: if debug.layout_type is LayoutType.Bolt: - debug.click(buttons.ok(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.ok()) elif debug.layout_type is LayoutType.Caesar: debug.press_right() elif debug.layout_type is LayoutType.Delizia: @@ -61,7 +62,8 @@ def go_next(debug: "DebugLink") -> LayoutContent: def go_back(debug: "DebugLink", r_middle: bool = False) -> LayoutContent: if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): - debug.click(buttons.cancel(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.cancel()) elif debug.layout_type is LayoutType.Caesar: if r_middle: debug.press_middle() @@ -116,11 +118,13 @@ def _carousel_steps(current_index: int, wanted_index: int, length: int) -> int: def unlock_gesture(debug: "DebugLink") -> LayoutContent: if debug.layout_type is LayoutType.Bolt: - debug.click(buttons.ok(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.ok()) elif debug.layout_type is LayoutType.Caesar: debug.press_right() elif debug.layout_type is LayoutType.Delizia: - debug.click(buttons.tap_to_confirm(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.tap_to_confirm()) else: raise RuntimeError("Unknown model") return debug.read_layout() diff --git a/tests/click_tests/record_layout.py b/tests/click_tests/record_layout.py index b7b454ef06..a640efb421 100644 --- a/tests/click_tests/record_layout.py +++ b/tests/click_tests/record_layout.py @@ -91,7 +91,8 @@ CLICKS_HELP = """\ Type 'y' or just press Enter to click the right button (usually "OK") Type 'n' to click the left button (usually "Cancel") Type a digit (0-9) to click the appropriate button as if on a numpad. -Type 'g1,2' to click button in column 1 and row 2 of 3x5 grid (letter A on mnemonic keyboard). +Type 'm1,2' to click button in column 1 and row 2 of mnemonic keyboard (letter J). +Type 'p2,1' to click button in column 2 and row 1 of pin/passphrase keyboard (letter D). Type 'i 1234' to send text "1234" without clicking (useful for PIN, passphrase, etc.) Type 'u' or 'j' to swipe up, 'd' or 'k' to swipe down. Type 'confirm' for hold-to-confirm (or a confirmation signal without clicking). @@ -138,29 +139,37 @@ def send_clicks(dest): input_str = key[2:] output = f"debug.input({input_str!r})" DEBUGLINK.input(input_str) - elif key.startswith("g"): + elif key.startswith("m"): x, y = [int(s) - 1 for s in key[1:].split(",")] output = ( - f"debug.click(buttons.grid35({x}, {y}, {DEBUGLINK.layout_type}))" + f"debug.click(ScreenButtons(layout_type).mnemonic_grid({x}, {y}))" + ) + DEBUGLINK.click( + buttons.ScreenButtons(DEBUGLINK.layout_type).mnemonic_grid(x, y) + ) + + elif key.startswith("p"): + x, y = [int(s) - 1 for s in key[1:].split(",")] + output = f"debug.click(ScreenButtons(layout_type).pin_passphrase_grid({x}, {y}))" + DEBUGLINK.click( + buttons.ScreenButtons(DEBUGLINK.layout_type).pin_passphrase_grid( + x, y + ) ) - DEBUGLINK.click(buttons.grid35(x, y, DEBUGLINK.layout_type)) elif key == "y": - output = "debug.click(buttons.ok(layout_type))" - DEBUGLINK.click(buttons.ok(DEBUGLINK.layout_type)) + output = "debug.click(ScreenButtons(layout_type).ok())" + DEBUGLINK.click(buttons.ScreenButtons(DEBUGLINK.layout_type).ok()) elif key == "n": - output = "debug.click(buttons.cancel(layout_type))" - DEBUGLINK.click(buttons.cancel(DEBUGLINK.layout_type)) + output = "debug.click(ScreenButtons(layout_type).cancel())" + DEBUGLINK.click(buttons.ScreenButtons(DEBUGLINK.layout_type).cancel()) elif key in "0123456789": - if key == "0": - x, y = 1, 4 - else: - i = int(key) - 1 - x = i % 3 - y = 3 - (i // 3) # trust me - output = ( - f"debug.click(buttons.grid35({x}, {y}, {DEBUGLINK.layout_type}))" + index = int(key) + output = f"debug.click(ScreenButtons(layout_type).pin_passphrase_index({index}))" + DEBUGLINK.click( + buttons.ScreenButtons(DEBUGLINK.layout_type).pin_passphrase_index( + index + ) ) - DEBUGLINK.click(buttons.grid35(x, y, DEBUGLINK.layout_type)) elif key == "stop": return else: diff --git a/tests/click_tests/recovery.py b/tests/click_tests/recovery.py index 09990fd642..e264a61e4f 100644 --- a/tests/click_tests/recovery.py +++ b/tests/click_tests/recovery.py @@ -17,15 +17,15 @@ def enter_word( debug: "DebugLink", word: str, is_slip39: bool = False ) -> "LayoutContent": if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): + btns = buttons.ScreenButtons(debug.layout_type) + actions = buttons.ButtonActions(debug.layout_type) typed_word = word[:4] - for coords in buttons.type_word( - typed_word, debug.layout_type, is_slip39=is_slip39 - ): + for coords in actions.type_word(typed_word, is_slip39=is_slip39): debug.click(coords) if debug.layout_type is LayoutType.Delizia and not is_slip39 and len(word) > 4: # T3T1 (delizia) BIP39 keyboard allows to "confirm" only if the word is fully written, you need to click the word to auto-complete - debug.click(buttons.input(debug.layout_type)) - debug.click(buttons.input(debug.layout_type)) + debug.click(btns.mnemonic_confirm()) + debug.click(btns.mnemonic_confirm()) return debug.read_layout() elif debug.layout_type is LayoutType.Caesar: letter_index = 0 @@ -57,7 +57,8 @@ def confirm_recovery(debug: "DebugLink", title: str = "recovery__title") -> None layout = debug.read_layout() assert TR.translate(title) == layout.title() if debug.layout_type is LayoutType.Bolt: - debug.click(buttons.ok(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.ok()) elif debug.layout_type is LayoutType.Delizia: debug.swipe_up() elif debug.layout_type is LayoutType.Caesar: @@ -70,12 +71,13 @@ def cancel_select_number_of_words( unlock_repeated_backup=False, ) -> None: if debug.layout_type is LayoutType.Bolt: + btns = buttons.ScreenButtons(debug.layout_type) assert debug.read_layout().text_content() == TR.recovery__num_of_words # click the button from ValuePad if unlock_repeated_backup: - coords = buttons.grid34(0, 2, debug.layout_type) + coords = btns.word_count_repeated_cancel() else: - coords = buttons.grid34(0, 3, debug.layout_type) + coords = btns.word_count_all_cancel() debug.click(coords) elif debug.layout_type is LayoutType.Caesar: debug.press_right() @@ -84,8 +86,13 @@ def cancel_select_number_of_words( # navigate to the number and confirm it debug.press_left() elif debug.layout_type is LayoutType.Delizia: + btns = buttons.ScreenButtons(debug.layout_type) # click the button from ValuePad - debug.click(buttons.grid34(0, 3, debug.layout_type)) + if unlock_repeated_backup: + coords = btns.word_count_repeated_cancel() + else: + coords = btns.word_count_all_cancel() + debug.click(coords) else: raise ValueError("Unknown model") @@ -99,23 +106,13 @@ def select_number_of_words( assert TR.recovery__num_of_words in layout.text_content() def select_bolt() -> "LayoutContent": + btns = buttons.ScreenButtons(debug.layout_type) # click the button from ValuePad if unlock_repeated_backup: - coords_map = { - 20: buttons.grid34(1, 2, debug.layout_type), - 33: buttons.grid34(2, 2, debug.layout_type), - } + coords = btns.word_count_repeated_word(num_of_words) else: - coords_map = { - 12: buttons.grid34(0, 2, debug.layout_type), - 18: buttons.grid34(1, 2, debug.layout_type), - 20: buttons.grid34(2, 2, debug.layout_type), - 24: buttons.grid34(1, 3, debug.layout_type), - 33: buttons.grid34(2, 3, debug.layout_type), - } - coords = coords_map.get(num_of_words) - if coords is None: - raise ValueError("Invalid num_of_words") + coords = btns.word_count_all_word(num_of_words) + debug.click(coords) return debug.read_layout() @@ -129,23 +126,12 @@ def select_number_of_words( return debug.read_layout() def select_delizia() -> "LayoutContent": + btns = buttons.ScreenButtons(debug.layout_type) # click the button from ValuePad if unlock_repeated_backup: - coords_map = { - 20: buttons.grid34(0, 1, debug.layout_type), - 33: buttons.grid34(2, 1, debug.layout_type), - } + coords = btns.word_count_repeated_word(num_of_words) else: - coords_map = { - 12: buttons.grid34(0, 1, debug.layout_type), - 18: buttons.grid34(2, 1, debug.layout_type), - 20: buttons.grid34(0, 2, debug.layout_type), - 24: buttons.grid34(2, 2, debug.layout_type), - 33: buttons.grid34(2, 3, debug.layout_type), - } - coords = coords_map.get(num_of_words) - if coords is None: - raise ValueError("Invalid num_of_words") + coords = btns.word_count_all_word(num_of_words) debug.click(coords) return debug.read_layout() @@ -200,8 +186,9 @@ def enter_share( debug.swipe_up() layout = debug.read_layout() else: + btns = buttons.ScreenButtons(debug.layout_type) assert TR.translate(before_title) in debug.read_layout().title() - debug.click(buttons.ok(debug.layout_type)) + debug.click(btns.ok()) layout = debug.read_layout() assert "MnemonicKeyboard" in layout.all_components() @@ -276,9 +263,10 @@ def enter_seed_previous_correct( if go_back: go_back = False if debug.layout_type is LayoutType.Bolt: + btns = buttons.ScreenButtons(debug.layout_type) debug.swipe_right() for _ in range(len(bad_word)): - debug.click(buttons.recovery_delete(debug.layout_type)) + debug.click(btns.mnemonic_erase()) elif debug.layout_type is LayoutType.Caesar: layout = debug.read_layout() @@ -295,9 +283,10 @@ def enter_seed_previous_correct( debug.press_middle() layout = debug.read_layout() elif debug.layout_type is LayoutType.Delizia: - debug.click(buttons.recovery_delete(debug.layout_type)) # Top-left + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.mnemonic_erase()) # Top-left for _ in range(len(bad_word)): - debug.click(buttons.recovery_delete(debug.layout_type)) + debug.click(btns.mnemonic_erase()) continue if i in bad_indexes: @@ -322,7 +311,8 @@ def prepare_enter_seed( or TR.translate(layout_text) in debug.read_layout().text_content() ) if debug.layout_type is LayoutType.Bolt: - debug.click(buttons.ok(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.ok()) elif debug.layout_type is LayoutType.Delizia: debug.swipe_up() debug.swipe_up() @@ -348,10 +338,11 @@ def cancel_recovery(debug: "DebugLink", recovery_type: str = "dry_run") -> None: assert title in layout.title() if debug.layout_type is LayoutType.Bolt: - debug.click(buttons.cancel(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.cancel()) layout = debug.read_layout() assert cancel_title in layout.title() - debug.click(buttons.ok(debug.layout_type)) + debug.click(btns.ok()) elif debug.layout_type is LayoutType.Caesar: debug.press_left() layout = debug.read_layout() @@ -359,13 +350,14 @@ def cancel_recovery(debug: "DebugLink", recovery_type: str = "dry_run") -> None: for _ in range(layout.page_count()): debug.press_right() elif debug.layout_type is LayoutType.Delizia: + btns = buttons.ScreenButtons(debug.layout_type) # go to menu - debug.click(buttons.corner_button(debug.layout_type)) + debug.click(btns.menu()) layout = debug.read_layout() assert ( TR.translate(f"recovery__cancel_{recovery_type}") in layout.text_content() ) - debug.click(buttons.vertical_menu(debug.layout_type)[0]) + debug.click(btns.vertical_menu_items()[0]) else: raise ValueError("Unknown model") diff --git a/tests/click_tests/reset.py b/tests/click_tests/reset.py index 6b2aec7b54..446792fb7f 100644 --- a/tests/click_tests/reset.py +++ b/tests/click_tests/reset.py @@ -15,10 +15,12 @@ if TYPE_CHECKING: def confirm_new_wallet(debug: "DebugLink") -> None: assert debug.read_layout().title() == TR.reset__title_create_wallet if debug.layout_type is LayoutType.Bolt: - debug.click(buttons.ok(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.ok()) elif debug.layout_type is LayoutType.Delizia: + btns = buttons.ScreenButtons(debug.layout_type) debug.swipe_up() - debug.click(buttons.tap_to_confirm(debug.layout_type)) + debug.click(btns.tap_to_confirm()) elif debug.layout_type is LayoutType.Caesar: debug.press_right() debug.press_right() @@ -32,7 +34,8 @@ def confirm_new_wallet(debug: "DebugLink") -> None: def confirm_read(debug: "DebugLink", middle_r: bool = False) -> None: if debug.layout_type is LayoutType.Bolt: - debug.click(buttons.ok(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.ok()) elif debug.layout_type is LayoutType.Delizia: debug.swipe_up() elif debug.layout_type is LayoutType.Caesar: @@ -50,14 +53,16 @@ def cancel_backup( debug: "DebugLink", middle_r: bool = False, confirm: bool = False ) -> None: if debug.layout_type is LayoutType.Bolt: - debug.click(buttons.cancel(debug.layout_type)) - debug.click(buttons.cancel(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.cancel()) + debug.click(btns.cancel()) elif debug.layout_type is LayoutType.Delizia: - debug.click(buttons.corner_button(debug.layout_type)) - debug.click(buttons.vertical_menu(debug.layout_type)[0]) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.menu()) + debug.click(btns.vertical_menu_items()[0]) if confirm: debug.swipe_up() - debug.click(buttons.tap_to_confirm(debug.layout_type)) + debug.click(btns.tap_to_confirm()) elif debug.layout_type is LayoutType.Caesar: debug.press_left() debug.press_left() @@ -65,19 +70,16 @@ def cancel_backup( def set_selection(debug: "DebugLink", diff: int) -> None: if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): + btns = buttons.ScreenButtons(debug.layout_type) assert "NumberInputDialog" in debug.read_layout().all_components() - button = ( - buttons.reset_minus(debug.layout_type) - if diff < 0 - else buttons.reset_plus(debug.layout_type) - ) + button = btns.number_input_minus() if diff < 0 else btns.number_input_plus() diff = abs(diff) for _ in range(diff): debug.click(button) if debug.layout_type is LayoutType.Bolt: - debug.click(buttons.ok(debug.layout_type)) + debug.click(btns.ok()) else: debug.swipe_up() elif debug.layout_type is LayoutType.Caesar: @@ -123,9 +125,11 @@ def read_words(debug: "DebugLink", do_htc: bool = True) -> list[str]: # There is hold-to-confirm button if do_htc: if debug.layout_type is LayoutType.Bolt: - debug.click(buttons.ok(debug.layout_type), hold_ms=1500) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.ok(), hold_ms=1500) elif debug.layout_type is LayoutType.Delizia: - debug.click(buttons.tap_to_confirm(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.tap_to_confirm()) elif debug.layout_type is LayoutType.Caesar: debug.press_right(hold_ms=1200) else: @@ -142,6 +146,7 @@ def confirm_words(debug: "DebugLink", words: list[str]) -> None: layout = debug.read_layout() if debug.layout_type is LayoutType.Bolt: + btns = buttons.ScreenButtons(debug.layout_type) assert TR.regexp("reset__select_word_x_of_y_template").match( layout.text_content() ) @@ -157,9 +162,10 @@ def confirm_words(debug: "DebugLink", words: list[str]) -> None: ] wanted_word = words[word_pos - 1].lower() button_pos = btn_texts.index(wanted_word) - debug.click(buttons.reset_word_check(debug.layout_type)[button_pos]) + debug.click(btns.word_check_words()[button_pos]) layout = debug.read_layout() elif debug.layout_type is LayoutType.Delizia: + btns = buttons.ScreenButtons(debug.layout_type) assert TR.regexp("reset__select_word_x_of_y_template").match(layout.subtitle()) for _ in range(3): # "Select word 3 of 20" @@ -173,7 +179,7 @@ def confirm_words(debug: "DebugLink", words: list[str]) -> None: ] wanted_word = words[word_pos - 1].lower() button_pos = btn_texts.index(wanted_word) - debug.click(buttons.vertical_menu(debug.layout_type)[button_pos]) + debug.click(btns.vertical_menu_items()[button_pos]) layout = debug.read_layout() elif debug.layout_type is LayoutType.Caesar: assert TR.reset__select_correct_word in layout.text_content() diff --git a/tests/click_tests/test_autolock.py b/tests/click_tests/test_autolock.py index d251562ac9..db1ac31465 100644 --- a/tests/click_tests/test_autolock.py +++ b/tests/click_tests/test_autolock.py @@ -21,7 +21,7 @@ from typing import TYPE_CHECKING, Tuple import pytest from trezorlib import btc, device, exceptions, messages -from trezorlib.debuglink import LayoutType +from trezorlib.debuglink import DebugLink, LayoutType from trezorlib.protobuf import MessageType from trezorlib.tools import parse_path @@ -33,7 +33,7 @@ from . import recovery from .common import go_next, unlock_gesture if TYPE_CHECKING: - from trezorlib.debuglink import DebugLink, LayoutContent + from trezorlib.debuglink import LayoutContent from ..device_handler import BackgroundDeviceHandler @@ -53,8 +53,17 @@ TXHASH_d5f65e = bytes.fromhex( PIN4 = "1234" -def _center_button(layout_type: LayoutType) -> Tuple[int, int]: - return buttons.grid35(1, 2, layout_type) +def _passphrase_j(debug: DebugLink) -> Tuple[int, int]: + btns = buttons.ScreenButtons(debug.layout_type) + if debug.layout_type is LayoutType.Bolt: + return btns.pin_passphrase_grid(1, 1) + else: + return btns.pin_passphrase_grid(0, 1) + + +def _center_button(debug: DebugLink) -> Tuple[int, int]: + btns = buttons.ScreenButtons(debug.layout_type) + return btns.pin_passphrase_grid(1, 1) def set_autolock_delay(device_handler: "BackgroundDeviceHandler", delay_ms: int): @@ -72,7 +81,8 @@ def set_autolock_delay(device_handler: "BackgroundDeviceHandler", delay_ms: int) layout = go_next(debug) if debug.layout_type is LayoutType.Delizia: - debug.click(buttons.tap_to_confirm(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.tap_to_confirm()) layout = debug.read_layout() assert layout.main_component() == "Homescreen" device_handler.result() @@ -107,8 +117,9 @@ def test_autolock_interrupts_signing(device_handler: "BackgroundDeviceHandler"): ) if debug.layout_type is LayoutType.Bolt: - debug.click(buttons.ok(debug.layout_type)) - debug.click(buttons.ok(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.ok()) + debug.click(btns.ok()) layout = debug.read_layout() assert TR.send__total_amount in layout.text_content() assert "0.0039 BTC" in layout.text_content() @@ -162,12 +173,14 @@ def test_autolock_does_not_interrupt_signing(device_handler: "BackgroundDeviceHa ) if debug.layout_type is LayoutType.Bolt: - debug.click(buttons.ok(debug.layout_type)) - debug.click(buttons.ok(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.ok()) + debug.click(btns.ok()) layout = debug.read_layout() assert TR.send__total_amount in layout.text_content() assert "0.0039 BTC" in layout.text_content() elif debug.layout_type is LayoutType.Delizia: + btns = buttons.ScreenButtons(debug.layout_type) debug.swipe_up() debug.swipe_up() layout = debug.read_layout() @@ -190,9 +203,9 @@ def test_autolock_does_not_interrupt_signing(device_handler: "BackgroundDeviceHa device_handler.client.set_filter(messages.TxAck, sleepy_filter) # confirm transaction if debug.layout_type is LayoutType.Bolt: - debug.click(buttons.ok(debug.layout_type)) + debug.click(btns.ok()) elif debug.layout_type is LayoutType.Delizia: - debug.click(buttons.tap_to_confirm(debug.layout_type)) + debug.click(btns.tap_to_confirm()) elif debug.layout_type is LayoutType.Caesar: debug.press_middle() @@ -220,12 +233,9 @@ def test_autolock_passphrase_keyboard(device_handler: "BackgroundDeviceHandler") # enter passphrase - slowly # keep clicking for long enough to trigger the autolock if it incorrectly ignored key presses for _ in range(math.ceil(11 / 1.5)): - if debug.layout_type is LayoutType.Bolt: + if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): # click at "j" - debug.click(_center_button(debug.layout_type)) - elif debug.layout_type is LayoutType.Delizia: - # click at "j" - debug.click((20, 120)) + debug.click(_passphrase_j(debug)) elif debug.layout_type is LayoutType.Caesar: # just go right # NOTE: because of passphrase randomization it would be a pain to input @@ -234,10 +244,9 @@ def test_autolock_passphrase_keyboard(device_handler: "BackgroundDeviceHandler") time.sleep(1.5) # Send the passphrase to the client (TT has it clicked already, TR needs to input it) - if debug.layout_type is LayoutType.Bolt: - debug.click(buttons.ok(debug.layout_type)) - elif debug.layout_type is LayoutType.Delizia: - debug.click(buttons.corner_button(debug.layout_type)) + if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.passphrase_confirm()) elif debug.layout_type is LayoutType.Caesar: debug.input("j" * 8) @@ -263,7 +272,7 @@ def test_autolock_interrupts_passphrase(device_handler: "BackgroundDeviceHandler # autolock must activate even if we pressed some buttons for _ in range(math.ceil(6 / 1.5)): if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): - debug.click(_center_button(debug.layout_type)) + debug.click(_center_button(debug)) elif debug.layout_type is LayoutType.Caesar: debug.press_middle() time.sleep(1.5) @@ -359,29 +368,33 @@ def test_dryrun_enter_word_slowly(device_handler: "BackgroundDeviceHandler"): recovery.select_number_of_words(debug, 20) if debug.layout_type is LayoutType.Bolt: - debug.click(buttons.ok(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + actions = buttons.ButtonActions(debug.layout_type) + debug.click(btns.ok()) layout = debug.read_layout() assert layout.main_component() == "MnemonicKeyboard" # type the word OCEAN slowly - for coords in buttons.type_word("ocea", debug.layout_type, is_slip39=True): + for coords in actions.type_word("ocea", is_slip39=True): time.sleep(9) debug.click(coords) - debug.click(buttons.input(debug.layout_type)) + debug.click(btns.mnemonic_confirm()) layout = debug.read_layout() # should not have locked, even though we took 9 seconds to type each letter assert layout.main_component() == "MnemonicKeyboard" elif debug.layout_type is LayoutType.Delizia: + btns = buttons.ScreenButtons(debug.layout_type) + actions = buttons.ButtonActions(debug.layout_type) debug.swipe_up() layout = debug.read_layout() assert layout.main_component() == "MnemonicKeyboard" # type the word OCEAN slowly - for coords in buttons.type_word("ocea", debug.layout_type, is_slip39=True): + for coords in actions.type_word("ocea", is_slip39=True): time.sleep(9) debug.click(coords) - debug.click(buttons.input(debug.layout_type)) + debug.click(btns.mnemonic_confirm()) layout = debug.read_layout() # should not have locked, even though we took 9 seconds to type each letter assert layout.main_component() == "MnemonicKeyboard" diff --git a/tests/click_tests/test_lock.py b/tests/click_tests/test_lock.py index aee2f08196..8d07b64c94 100644 --- a/tests/click_tests/test_lock.py +++ b/tests/click_tests/test_lock.py @@ -81,7 +81,8 @@ def test_hold_to_lock(device_handler: "BackgroundDeviceHandler"): if debug.layout_type is LayoutType.Caesar: debug.press_right() else: - debug.click(buttons.info(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.info()) layout = debug.read_layout() assert "PinKeyboard" in layout.all_components() debug.input("1234") diff --git a/tests/click_tests/test_passphrase_bolt.py b/tests/click_tests/test_passphrase_bolt.py index c4d5b4adc2..ce12c3c40c 100644 --- a/tests/click_tests/test_passphrase_bolt.py +++ b/tests/click_tests/test_passphrase_bolt.py @@ -117,7 +117,8 @@ def press_char(debug: "DebugLink", char: str) -> None: go_to_category(debug, char_category) - coords, amount = buttons.passphrase(char, debug.layout_type) + actions = buttons.ButtonActions(debug.layout_type) + coords, amount = actions.passphrase(char) # If the button is the same as for the previous char, # waiting a second before pressing it again. # (not for a space) @@ -141,13 +142,15 @@ def input_passphrase(debug: "DebugLink", passphrase: str, check: bool = True) -> def enter_passphrase(debug: "DebugLink") -> None: """Enter a passphrase""" - coords = buttons.pin_passphrase_grid(11, debug.layout_type) + btns = buttons.ScreenButtons(debug.layout_type) + coords = btns.passphrase_confirm() debug.click(coords) def delete_char(debug: "DebugLink") -> None: """Deletes the last char""" - coords = buttons.pin_passphrase_grid(9, debug.layout_type) + btns = buttons.ScreenButtons(debug.layout_type) + coords = btns.pin_passphrase_erase() debug.click(coords) @@ -216,8 +219,8 @@ def test_passphrase_loop_all_characters(device_handler: "BackgroundDeviceHandler go_to_category(debug, category) enter_passphrase(debug) - coords = buttons.pin_passphrase_grid(11, debug.layout_type) - debug.click(coords) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.passphrase_confirm()) @pytest.mark.setup_client(passphrase=True) @@ -225,7 +228,8 @@ def test_passphrase_click_same_button_many_times( device_handler: "BackgroundDeviceHandler", ): with prepare_passphrase_dialogue(device_handler) as debug: - a_coords, _ = buttons.passphrase("a", debug.layout_type) + actions = buttons.ButtonActions(debug.layout_type) + a_coords, _ = actions.passphrase("a") for _ in range(10): debug.click(a_coords) diff --git a/tests/click_tests/test_passphrase_delizia.py b/tests/click_tests/test_passphrase_delizia.py index 99e8451f5c..62cf7fe2e2 100644 --- a/tests/click_tests/test_passphrase_delizia.py +++ b/tests/click_tests/test_passphrase_delizia.py @@ -87,10 +87,11 @@ def get_passphrase_choices(char: str) -> tuple[str, ...]: def passphrase(char: str, layout_type: LayoutType) -> Tuple[buttons.Coords, int]: + btns = buttons.ScreenButtons(layout_type) choices = get_passphrase_choices(char) idx = next(i for i, letters in enumerate(choices) if char in letters) click_amount = choices[idx].index(char) + 1 - return buttons.pin_passphrase_index(idx, layout_type), click_amount + return btns.pin_passphrase_index(idx), click_amount @contextmanager @@ -171,16 +172,16 @@ def input_passphrase(debug: "DebugLink", passphrase: str, check: bool = True) -> def enter_passphrase(debug: "DebugLink") -> None: """Enter a passphrase""" is_empty: bool = len(debug.read_layout().passphrase()) == 0 - coords = buttons.corner_button(debug.layout_type) # top-right corner - debug.click(coords) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.passphrase_confirm()) if is_empty: - debug.click(buttons.ui_yes(debug.layout_type)) + debug.click(btns.ui_yes()) def delete_char(debug: "DebugLink") -> None: """Deletes the last char""" - coords = buttons.pin_passphrase_grid(9, debug.layout_type) - debug.click(coords) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.pin_passphrase_erase()) VECTORS = ( # passphrase, address @@ -250,8 +251,8 @@ def test_passphrase_loop_all_characters(device_handler: "BackgroundDeviceHandler debug.read_layout() enter_passphrase(debug) - coords = buttons.pin_passphrase_grid(11, debug.layout_type) - debug.click(coords) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.passphrase_confirm()) @pytest.mark.setup_client(passphrase=True) @@ -259,7 +260,8 @@ def test_passphrase_click_same_button_many_times( device_handler: "BackgroundDeviceHandler", ): with prepare_passphrase_dialogue(device_handler) as debug: - a_coords, _ = buttons.passphrase("a", debug.layout_type) + actions = buttons.ButtonActions(debug.layout_type) + a_coords, _ = actions.passphrase("a") for _ in range(10): debug.click(a_coords) diff --git a/tests/click_tests/test_pin.py b/tests/click_tests/test_pin.py index b795d80bb2..f8971d8745 100644 --- a/tests/click_tests/test_pin.py +++ b/tests/click_tests/test_pin.py @@ -138,8 +138,9 @@ def prepare( yield debug if debug.layout_type is LayoutType.Delizia and tap: + btns = buttons.ScreenButtons(debug.layout_type) go_next(debug) - debug.click(buttons.tap_to_confirm(debug.layout_type)) + debug.click(btns.tap_to_confirm()) else: go_next(debug) @@ -154,12 +155,12 @@ def _input_pin(debug: "DebugLink", pin: str, check: bool = False) -> None: """Input the PIN""" if check: before = debug.read_layout().pin() - if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): + btns = buttons.ScreenButtons(debug.layout_type) digits_order = debug.read_layout().tt_pin_digits_order() for digit in pin: digit_index = digits_order.index(digit) - coords = buttons.pin_passphrase_index(digit_index, debug.layout_type) + coords = btns.pin_passphrase_index(digit_index) debug.click(coords) elif debug.layout_type is LayoutType.Caesar: for digit in pin: @@ -173,7 +174,8 @@ def _input_pin(debug: "DebugLink", pin: str, check: bool = False) -> None: def _see_pin(debug: "DebugLink") -> None: """Navigate to "SHOW" and press it""" if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): - debug.click(buttons.input(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.pin_passphrase_input()) elif debug.layout_type is LayoutType.Caesar: navigate_to_action_and_press(debug, SHOW, TR_PIN_ACTIONS) @@ -185,7 +187,8 @@ def _delete_pin(debug: "DebugLink", digits_to_delete: int, check: bool = True) - for _ in range(digits_to_delete): if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): - debug.click(buttons.pin_passphrase_grid(9, debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.pin_passphrase_erase()) elif debug.layout_type is LayoutType.Caesar: navigate_to_action_and_press(debug, DELETE, TR_PIN_ACTIONS) @@ -197,7 +200,11 @@ def _delete_pin(debug: "DebugLink", digits_to_delete: int, check: bool = True) - def _delete_all(debug: "DebugLink", check: bool = True) -> None: """Navigate to "DELETE" and hold it until all digits are deleted""" if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): - debug.click(buttons.pin_passphrase_grid(9, debug.layout_type), hold_ms=1500) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click( + btns.pin_passphrase_erase(), + hold_ms=1500, + ) elif debug.layout_type is LayoutType.Caesar: navigate_to_action_and_press(debug, DELETE, TR_PIN_ACTIONS, hold_ms=1000) @@ -221,7 +228,8 @@ def _cancel_pin(debug: "DebugLink") -> None: def _confirm_pin(debug: "DebugLink") -> None: """Navigate to "ENTER" and press it""" if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): - debug.click(buttons.pin_passphrase_grid(11, debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.pin_confirm()) elif debug.layout_type is LayoutType.Caesar: navigate_to_action_and_press(debug, ENTER, TR_PIN_ACTIONS) diff --git a/tests/click_tests/test_tutorial_delizia.py b/tests/click_tests/test_tutorial_delizia.py index 2460806f28..a463ed5de2 100644 --- a/tests/click_tests/test_tutorial_delizia.py +++ b/tests/click_tests/test_tutorial_delizia.py @@ -36,10 +36,11 @@ pytestmark = [ def test_tutorial_ignore_menu(device_handler: "BackgroundDeviceHandler"): debug = device_handler.debuglink() + btns = buttons.ScreenButtons(debug.layout_type) device_handler.run(device.show_device_tutorial) assert debug.read_layout().title() == TR.tutorial__welcome_safe5 - debug.click(buttons.tap_to_confirm(debug.layout_type)) + debug.click(btns.tap_to_confirm()) assert debug.read_layout().title() == TR.tutorial__title_lets_begin debug.swipe_up() assert debug.read_layout().title() == TR.tutorial__title_easy_navigation @@ -47,7 +48,7 @@ def test_tutorial_ignore_menu(device_handler: "BackgroundDeviceHandler"): assert debug.read_layout().title() == TR.tutorial__title_handy_menu debug.swipe_up() assert debug.read_layout().title() == TR.tutorial__title_hold - debug.click(buttons.tap_to_confirm(debug.layout_type)) + debug.click(btns.tap_to_confirm()) assert debug.read_layout().title() == TR.tutorial__title_well_done debug.swipe_up() @@ -56,24 +57,25 @@ def test_tutorial_ignore_menu(device_handler: "BackgroundDeviceHandler"): def test_tutorial_menu_open_close(device_handler: "BackgroundDeviceHandler"): debug = device_handler.debuglink() + btns = buttons.ScreenButtons(debug.layout_type) device_handler.run(device.show_device_tutorial) assert debug.read_layout().title() == TR.tutorial__welcome_safe5 - debug.click(buttons.tap_to_confirm(debug.layout_type)) + debug.click(btns.tap_to_confirm()) assert debug.read_layout().title() == TR.tutorial__title_lets_begin debug.swipe_up() assert debug.read_layout().title() == TR.tutorial__title_easy_navigation debug.swipe_up() assert debug.read_layout().title() == TR.tutorial__title_handy_menu - debug.click(buttons.corner_button(debug.layout_type)) + debug.click(btns.menu()) assert TR.tutorial__did_you_know in debug.read_layout().text_content() - debug.click(buttons.corner_button(debug.layout_type)) + debug.click(btns.menu()) assert debug.read_layout().title() == TR.tutorial__title_handy_menu debug.swipe_up() assert debug.read_layout().title() == TR.tutorial__title_hold - debug.click(buttons.tap_to_confirm(debug.layout_type)) + debug.click(btns.tap_to_confirm()) assert debug.read_layout().title() == TR.tutorial__title_well_done debug.swipe_up() @@ -82,21 +84,22 @@ def test_tutorial_menu_open_close(device_handler: "BackgroundDeviceHandler"): def test_tutorial_menu_exit(device_handler: "BackgroundDeviceHandler"): debug = device_handler.debuglink() + btns = buttons.ScreenButtons(debug.layout_type) device_handler.run(device.show_device_tutorial) assert debug.read_layout().title() == TR.tutorial__welcome_safe5 - debug.click(buttons.tap_to_confirm(debug.layout_type)) + debug.click(btns.tap_to_confirm()) assert debug.read_layout().title() == TR.tutorial__title_lets_begin debug.swipe_up() assert debug.read_layout().title() == TR.tutorial__title_easy_navigation debug.swipe_up() assert debug.read_layout().title() == TR.tutorial__title_handy_menu - debug.click(buttons.corner_button(debug.layout_type)) + debug.click(btns.menu()) assert TR.tutorial__did_you_know in debug.read_layout().text_content() - debug.click(buttons.vertical_menu(debug.layout_type)[2]) + debug.click(btns.vertical_menu_items()[2]) assert TR.instructions__hold_to_exit_tutorial in debug.read_layout().footer() - debug.click(buttons.tap_to_confirm(debug.layout_type)) + debug.click(btns.tap_to_confirm()) assert debug.read_layout().title() == TR.tutorial__title_well_done debug.swipe_up() @@ -105,19 +108,20 @@ def test_tutorial_menu_exit(device_handler: "BackgroundDeviceHandler"): def test_tutorial_menu_repeat(device_handler: "BackgroundDeviceHandler"): debug = device_handler.debuglink() + btns = buttons.ScreenButtons(debug.layout_type) device_handler.run(device.show_device_tutorial) assert debug.read_layout().title() == TR.tutorial__welcome_safe5 - debug.click(buttons.tap_to_confirm(debug.layout_type)) + debug.click(btns.tap_to_confirm()) assert debug.read_layout().title() == TR.tutorial__title_lets_begin debug.swipe_up() assert debug.read_layout().title() == TR.tutorial__title_easy_navigation debug.swipe_up() assert debug.read_layout().title() == TR.tutorial__title_handy_menu - debug.click(buttons.corner_button(debug.layout_type)) + debug.click(btns.menu()) assert TR.tutorial__did_you_know in debug.read_layout().text_content() - debug.click(buttons.vertical_menu(debug.layout_type)[1]) + debug.click(btns.vertical_menu_items()[1]) assert debug.read_layout().title() == TR.tutorial__title_lets_begin debug.swipe_up() @@ -126,7 +130,7 @@ def test_tutorial_menu_repeat(device_handler: "BackgroundDeviceHandler"): assert debug.read_layout().title() == TR.tutorial__title_handy_menu debug.swipe_up() assert debug.read_layout().title() == TR.tutorial__title_hold - debug.click(buttons.tap_to_confirm(debug.layout_type)) + debug.click(btns.tap_to_confirm()) assert debug.read_layout().title() == TR.tutorial__title_well_done debug.swipe_up() @@ -135,31 +139,32 @@ def test_tutorial_menu_repeat(device_handler: "BackgroundDeviceHandler"): def test_tutorial_menu_funfact(device_handler: "BackgroundDeviceHandler"): debug = device_handler.debuglink() + btns = buttons.ScreenButtons(debug.layout_type) device_handler.run(device.show_device_tutorial) assert debug.read_layout().title() == TR.tutorial__welcome_safe5 - debug.click(buttons.tap_to_confirm(debug.layout_type)) + debug.click(btns.tap_to_confirm()) assert debug.read_layout().title() == TR.tutorial__title_lets_begin debug.swipe_up() assert debug.read_layout().title() == TR.tutorial__title_easy_navigation debug.swipe_up() assert debug.read_layout().title() == TR.tutorial__title_handy_menu - debug.click(buttons.corner_button(debug.layout_type)) + debug.click(btns.menu()) assert TR.tutorial__did_you_know in debug.read_layout().text_content() - debug.click(buttons.vertical_menu(debug.layout_type)[0]) + debug.click(btns.vertical_menu_items()[0]) assert debug.read_layout().text_content() in TR.tutorial__first_wallet.replace( "\n", " " ) - debug.click(buttons.corner_button(debug.layout_type)) + debug.click(btns.menu()) assert TR.tutorial__did_you_know in debug.read_layout().text_content() - debug.click(buttons.corner_button(debug.layout_type)) + debug.click(btns.menu()) assert debug.read_layout().title() == TR.tutorial__title_handy_menu debug.swipe_up() assert debug.read_layout().title() == TR.tutorial__title_hold - debug.click(buttons.tap_to_confirm(debug.layout_type)) + debug.click(btns.tap_to_confirm()) assert debug.read_layout().title() == TR.tutorial__title_well_done debug.swipe_up() diff --git a/tests/common.py b/tests/common.py index b7edc7fbc8..c82b25f444 100644 --- a/tests/common.py +++ b/tests/common.py @@ -323,12 +323,13 @@ def click_info_button_bolt(debug: "DebugLink") -> Generator[Any, Any, ButtonRequ def click_info_button_delizia(debug: "DebugLink"): """Click Shamir backup info button and return back.""" - debug.click(buttons.corner_button(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.menu()) layout = debug.read_layout() assert "VerticalMenu" in layout.all_components() - debug.click(buttons.vertical_menu(debug.layout_type)[0]) - debug.click(buttons.corner_button(debug.layout_type)) - debug.click(buttons.corner_button(debug.layout_type)) + debug.click(btns.vertical_menu_items()[0]) + debug.click(btns.menu()) + debug.click(btns.menu()) def check_pin_backoff_time(attempts: int, start: float) -> None: diff --git a/tests/device_tests/cardano/test_sign_tx.py b/tests/device_tests/cardano/test_sign_tx.py index d03cef4d28..8131928477 100644 --- a/tests/device_tests/cardano/test_sign_tx.py +++ b/tests/device_tests/cardano/test_sign_tx.py @@ -41,9 +41,10 @@ def show_details_input_flow(client: Client): # Caesar - right button for "Show all" client.debug.press_yes() elif client.layout_type is LayoutType.Delizia: + btns = buttons.ScreenButtons(client.layout_type) # Delizia - "Show all" button from context menu - client.debug.click(buttons.corner_button(client.layout_type)) - client.debug.click(buttons.vertical_menu(client.layout_type)[0]) + client.debug.click(btns.menu()) + client.debug.click(btns.vertical_menu_items()[0]) else: raise NotImplementedError # reset ui flow to continue "automatically" diff --git a/tests/device_tests/test_msg_changepin_t2.py b/tests/device_tests/test_msg_changepin_t2.py index 4c2a3ad032..3f0e7d56d6 100644 --- a/tests/device_tests/test_msg_changepin_t2.py +++ b/tests/device_tests/test_msg_changepin_t2.py @@ -187,17 +187,18 @@ def test_change_invalid_current(client: Client): def test_pin_menu_cancel_setup(client: Client): def cancel_pin_setup_input_flow(): yield + btns = buttons.ScreenButtons(client.layout_type) # enter context menu - client.debug.click(buttons.corner_button(client.layout_type)) + client.debug.click(btns.menu()) client.debug.synchronize_at("VerticalMenu") # click "Cancel PIN setup" - client.debug.click(buttons.vertical_menu(client.layout_type)[0]) + client.debug.click(btns.vertical_menu_items()[0]) client.debug.synchronize_at("Paragraphs") # swipe through info screen client.debug.swipe_up() client.debug.synchronize_at("PromptScreen") # tap to confirm - client.debug.click(buttons.tap_to_confirm(client.layout_type)) + client.debug.click(btns.tap_to_confirm()) with client, pytest.raises(Cancelled): client.set_input_flow(cancel_pin_setup_input_flow) diff --git a/tests/input_flows.py b/tests/input_flows.py index d0ca21b0f8..8102dd84e5 100644 --- a/tests/input_flows.py +++ b/tests/input_flows.py @@ -316,12 +316,13 @@ class InputFlowSignVerifyMessageLong(InputFlowBase): layouts: list[LayoutContent] = [] br = yield # confirm address + btns = buttons.ScreenButtons(self.client.layout_type) self.debug.read_layout() self.debug.press_yes() - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) self.debug.synchronize_at("VerticalMenu") - self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) + self.debug.click(btns.vertical_menu_items()[0]) br = yield self.debug.read_layout() @@ -351,8 +352,9 @@ class InputFlowSignMessageInfo(InputFlowBase): def input_flow_bolt(self) -> BRGeneratorType: yield # signing address/message info - self.debug.click(buttons.corner_button(self.client.layout_type)) - self.debug.click(buttons.corner_button(self.client.layout_type)) + btns = buttons.ScreenButtons(self.client.layout_type) + self.debug.click(btns.menu()) + self.debug.click(btns.menu()) # signing address "x" self.debug.press_no() self.debug.synchronize_at("IconDialog") @@ -363,10 +365,11 @@ class InputFlowSignMessageInfo(InputFlowBase): def input_flow_delizia(self) -> BRGeneratorType: yield # show address/message info - self.debug.click(buttons.corner_button(self.client.layout_type)) - self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) - self.debug.click(buttons.corner_button(self.client.layout_type)) - self.debug.click(buttons.vertical_menu(self.client.layout_type)[1]) + btns = buttons.ScreenButtons(self.client.layout_type) + self.debug.click(btns.menu()) + self.debug.click(btns.vertical_menu_items()[0]) + self.debug.click(btns.menu()) + self.debug.click(btns.vertical_menu_items()[1]) # address mismatch? yes! self.debug.swipe_up() yield @@ -378,14 +381,15 @@ class InputFlowShowAddressQRCode(InputFlowBase): def input_flow_bolt(self) -> BRGeneratorType: yield - self.debug.click(buttons.corner_button(self.client.layout_type)) + btns = buttons.ScreenButtons(self.client.layout_type) + self.debug.click(btns.menu()) # synchronize; TODO get rid of this once we have single-global-layout self.debug.synchronize_at("SimplePage") self.debug.swipe_left() self.debug.swipe_right() self.debug.swipe_left() - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) self.debug.press_no() self.debug.press_no() self.debug.press_yes() @@ -413,26 +417,27 @@ class InputFlowShowAddressQRCode(InputFlowBase): def input_flow_delizia(self) -> BRGeneratorType: yield - self.debug.click(buttons.corner_button(self.client.layout_type)) + btns = buttons.ScreenButtons(self.client.layout_type) + self.debug.click(btns.menu()) # synchronize; TODO get rid of this once we have single-global-layout self.debug.synchronize_at("VerticalMenu") # menu - self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) + self.debug.click(btns.vertical_menu_items()[0]) self.debug.synchronize_at("Qr") # qr code - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) # menu - self.debug.click(buttons.vertical_menu(self.client.layout_type)[1]) + self.debug.click(btns.vertical_menu_items()[1]) # address details - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) # menu - self.debug.click(buttons.vertical_menu(self.client.layout_type)[2]) + self.debug.click(btns.vertical_menu_items()[2]) # cancel self.debug.swipe_up() # really cancel - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) # menu - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) layout = self.debug.read_layout() while "PromptScreen" not in layout.all_components(): @@ -440,7 +445,7 @@ class InputFlowShowAddressQRCode(InputFlowBase): layout = self.debug.read_layout() self.debug.synchronize_at("PromptScreen") # tap to confirm - self.debug.click(buttons.tap_to_confirm(self.client.layout_type)) + self.debug.click(btns.tap_to_confirm()) class InputFlowShowAddressQRCodeCancel(InputFlowBase): @@ -449,12 +454,13 @@ class InputFlowShowAddressQRCodeCancel(InputFlowBase): def input_flow_bolt(self) -> BRGeneratorType: yield - self.debug.click(buttons.corner_button(self.client.layout_type)) + btns = buttons.ScreenButtons(self.client.layout_type) + self.debug.click(btns.menu()) # synchronize; TODO get rid of this once we have single-global-layout self.debug.synchronize_at("SimplePage") self.debug.swipe_left() - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) self.debug.press_no() self.debug.press_yes() @@ -475,25 +481,26 @@ class InputFlowShowAddressQRCodeCancel(InputFlowBase): def input_flow_delizia(self) -> BRGeneratorType: yield - self.debug.click(buttons.corner_button(self.client.layout_type)) + btns = buttons.ScreenButtons(self.client.layout_type) + self.debug.click(btns.menu()) # synchronize; TODO get rid of this once we have single-global-layout self.debug.synchronize_at("VerticalMenu") # menu - self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) + self.debug.click(btns.vertical_menu_items()[0]) self.debug.synchronize_at("Qr") # qr code - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) # menu - self.debug.click(buttons.vertical_menu(self.client.layout_type)[1]) + self.debug.click(btns.vertical_menu_items()[1]) # address details - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) # menu - self.debug.click(buttons.vertical_menu(self.client.layout_type)[2]) + self.debug.click(btns.vertical_menu_items()[2]) # cancel self.debug.swipe_up() self.debug.synchronize_at("PromptScreen") # really cancel - self.debug.click(buttons.tap_to_confirm(self.client.layout_type)) + self.debug.click(btns.tap_to_confirm()) class InputFlowShowMultisigXPUBs(InputFlowBase): @@ -513,6 +520,7 @@ class InputFlowShowMultisigXPUBs(InputFlowBase): def input_flow_bolt(self) -> BRGeneratorType: yield # multisig address warning + btns = buttons.ScreenButtons(self.client.layout_type) self.debug.press_yes() yield # show address @@ -521,7 +529,7 @@ class InputFlowShowMultisigXPUBs(InputFlowBase): assert "(MULTISIG)" in layout.title() assert layout.text_content().replace(" ", "") == self.address - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) assert "Qr" in self.all_components() self.debug.swipe_left() @@ -538,7 +546,7 @@ class InputFlowShowMultisigXPUBs(InputFlowBase): content = layout.text_content().replace(" ", "") assert self.xpubs[xpub_num] in content - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) # show address self.debug.press_no() # address mismatch @@ -590,26 +598,27 @@ class InputFlowShowMultisigXPUBs(InputFlowBase): def input_flow_delizia(self) -> BRGeneratorType: yield # multisig address warning - self.debug.click(buttons.corner_button(self.client.layout_type)) + btns = buttons.ScreenButtons(self.client.layout_type) + self.debug.click(btns.menu()) self.debug.synchronize_at("VerticalMenu") - self.debug.click(buttons.vertical_menu(self.client.layout_type)[1]) + self.debug.click(btns.vertical_menu_items()[1]) yield # show address layout = self.debug.read_layout() assert TR.address__title_receive_address in layout.title() assert layout.text_content().replace(" ", "") == self.address - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) assert "VerticalMenu" in self.all_components() # menu - self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) + self.debug.click(btns.vertical_menu_items()[0]) self.debug.synchronize_at("Qr") # qr code assert "Qr" in self.all_components() - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) # menu assert "VerticalMenu" in self.all_components() - self.debug.click(buttons.vertical_menu(self.client.layout_type)[1]) + self.debug.click(btns.vertical_menu_items()[1]) layout = self.debug.synchronize_at("AddressDetails") # address details assert "Multisig 2 of 3" in layout.screen_content() @@ -620,17 +629,17 @@ class InputFlowShowMultisigXPUBs(InputFlowBase): self.debug.swipe_left() self.debug.swipe_left() - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) self.debug.synchronize_at("VerticalMenu") # menu - self.debug.click(buttons.vertical_menu(self.client.layout_type)[2]) + self.debug.click(btns.vertical_menu_items()[2]) # cancel self.debug.swipe_up() # really cancel - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) self.debug.synchronize_at("VerticalMenu") # menu - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) layout = self.debug.synchronize_at("Paragraphs") # address while "PromptScreen" not in layout.all_components(): @@ -647,6 +656,7 @@ class InputFlowShowXpubQRCode(InputFlowBase): self.passphrase = passphrase def input_flow_bolt(self) -> BRGeneratorType: + btns = buttons.ScreenButtons(self.client.layout_type) if self.passphrase: yield self.debug.press_yes() @@ -659,14 +669,14 @@ class InputFlowShowXpubQRCode(InputFlowBase): self.debug.press_yes() br = yield - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) # synchronize; TODO get rid of this once we have single-global-layout self.debug.synchronize_at("SimplePage") self.debug.swipe_left() self.debug.swipe_right() self.debug.swipe_left() - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) self.debug.press_no() self.debug.press_no() for _ in range(br.pages - 1): @@ -701,6 +711,7 @@ class InputFlowShowXpubQRCode(InputFlowBase): self.debug.press_middle() def input_flow_delizia(self) -> BRGeneratorType: + btns = buttons.ScreenButtons(self.client.layout_type) if self.passphrase: yield self.debug.press_yes() @@ -716,32 +727,32 @@ class InputFlowShowXpubQRCode(InputFlowBase): assert layout.title() in (TR.address__public_key, "XPUB") - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) assert "VerticalMenu" in self.all_components() # menu - self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) + self.debug.click(btns.vertical_menu_items()[0]) self.debug.synchronize_at("Qr") # qr code assert "Qr" in self.all_components() - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) # menu assert "VerticalMenu" in self.all_components() - self.debug.click(buttons.vertical_menu(self.client.layout_type)[1]) + self.debug.click(btns.vertical_menu_items()[1]) layout = self.debug.synchronize_at("AddressDetails") # address details assert TR.address_details__derivation_path in layout.screen_content() - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) layout = self.debug.synchronize_at("VerticalMenu") # menu - self.debug.click(buttons.vertical_menu(self.client.layout_type)[2]) + self.debug.click(btns.vertical_menu_items()[2]) # cancel self.debug.swipe_up() # really cancel - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) layout = self.debug.synchronize_at("VerticalMenu") # menu - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) layout = self.debug.synchronize_at("Paragraphs") # address while "PromptScreen" not in layout.all_components(): @@ -854,6 +865,7 @@ class InputFlowSignTxHighFee(InputFlowBase): def sign_tx_go_to_info(client: Client) -> Generator[None, messages.ButtonRequest, str]: + btns = buttons.ScreenButtons(client.layout_type) yield # confirm output client.debug.read_layout() client.debug.press_yes() @@ -868,7 +880,7 @@ def sign_tx_go_to_info(client: Client) -> Generator[None, messages.ButtonRequest layout = client.debug.read_layout() content = layout.text_content() - client.debug.click(buttons.corner_button(client.layout_type)) + client.debug.click(btns.menu()) return content @@ -876,6 +888,7 @@ def sign_tx_go_to_info(client: Client) -> Generator[None, messages.ButtonRequest def sign_tx_go_to_info_t3t1( client: Client, multi_account: bool = False ) -> Generator[None, messages.ButtonRequest, str]: + btns = buttons.ScreenButtons(client.layout_type) yield # confirm output client.debug.read_layout() client.debug.swipe_up() @@ -890,22 +903,22 @@ def sign_tx_go_to_info_t3t1( yield # confirm transaction client.debug.read_layout() - client.debug.click(buttons.corner_button(client.layout_type)) + client.debug.click(btns.menu()) client.debug.synchronize_at("VerticalMenu") - client.debug.click(buttons.vertical_menu(client.layout_type)[0]) + client.debug.click(btns.vertical_menu_items()[0]) layout = client.debug.read_layout() content = layout.text_content() - client.debug.click(buttons.corner_button(client.layout_type)) + client.debug.click(btns.menu()) client.debug.synchronize_at("VerticalMenu") - client.debug.click(buttons.vertical_menu(client.layout_type)[1]) + client.debug.click(btns.vertical_menu_items()[1]) layout = client.debug.read_layout() content += " " + layout.text_content() - client.debug.click(buttons.corner_button(client.layout_type)) - client.debug.click(buttons.corner_button(client.layout_type)) + client.debug.click(btns.menu()) + client.debug.click(btns.menu()) return content @@ -1018,11 +1031,12 @@ class InputFlowSignTxInformationCancel(InputFlowBase): self.debug.press_left() def input_flow_delizia(self) -> BRGeneratorType: + btns = buttons.ScreenButtons(self.client.layout_type) yield from sign_tx_go_to_info_t3t1(self.client) - self.debug.click(buttons.corner_button(self.client.layout_type)) - self.debug.click(buttons.vertical_menu(self.client.layout_type)[2]) + self.debug.click(btns.menu()) + self.debug.click(btns.vertical_menu_items()[2]) self.debug.synchronize_at("PromptScreen") - self.debug.click(buttons.tap_to_confirm(self.client.layout_type)) + self.debug.click(btns.tap_to_confirm()) class InputFlowSignTxInformationReplacement(InputFlowBase): @@ -1030,6 +1044,7 @@ class InputFlowSignTxInformationReplacement(InputFlowBase): super().__init__(client) def input_flow_bolt(self) -> BRGeneratorType: + btns = buttons.ScreenButtons(self.client.layout_type) yield # confirm txid self.debug.press_yes() yield # confirm address @@ -1043,8 +1058,8 @@ class InputFlowSignTxInformationReplacement(InputFlowBase): self.debug.press_yes() yield # transaction summary, press info - self.debug.click(buttons.corner_button(self.client.layout_type)) - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) + self.debug.click(btns.menu()) self.debug.press_yes() def input_flow_caesar(self) -> BRGeneratorType: @@ -2326,17 +2341,18 @@ class InputFlowResetSkipBackup(InputFlowBase): self.debug.press_no() def input_flow_delizia(self) -> BRGeneratorType: + btns = buttons.ScreenButtons(self.client.layout_type) yield from self.BAK.confirm_new_wallet() yield # Skip Backup assert TR.backup__new_wallet_created in self.text_content() self.debug.swipe_up() yield - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) self.debug.synchronize_at("VerticalMenu") - self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) + self.debug.click(btns.vertical_menu_items()[0]) self.debug.swipe_up() self.debug.synchronize_at("PromptScreen") - self.debug.click(buttons.tap_to_confirm(self.client.layout_type)) + self.debug.click(btns.tap_to_confirm()) class InputFlowConfirmAllWarnings(InputFlowBase): @@ -2355,6 +2371,7 @@ class InputFlowConfirmAllWarnings(InputFlowBase): return self.input_flow_bolt() def input_flow_delizia(self) -> BRGeneratorType: + btns = buttons.ScreenButtons(self.client.layout_type) br = yield while True: # wait for homescreen to go away @@ -2372,9 +2389,9 @@ class InputFlowConfirmAllWarnings(InputFlowBase): TR.send__cancel_sign, ) if any(needle.lower() in text for needle in hi_prio): - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) self.debug.synchronize_at("VerticalMenu") - self.debug.click(buttons.vertical_menu(self.client.layout_type)[1]) + self.debug.click(btns.vertical_menu_items()[1]) elif "PromptScreen" in layout.all_components(): self.debug.press_yes() elif "SwipeContent" in layout.all_components(): @@ -2398,7 +2415,8 @@ class InputFlowFidoConfirm(InputFlowBase): yield from self.input_flow_bolt() def input_flow_delizia(self) -> BRGeneratorType: + btns = buttons.ScreenButtons(self.client.layout_type) while True: yield self.debug.swipe_up() - self.debug.click(buttons.tap_to_confirm(self.client.layout_type)) + self.debug.click(btns.tap_to_confirm()) diff --git a/tests/input_flows_helpers.py b/tests/input_flows_helpers.py index 41d6d1612b..dd0d5ae368 100644 --- a/tests/input_flows_helpers.py +++ b/tests/input_flows_helpers.py @@ -143,13 +143,14 @@ class RecoveryFlow: else: self.debug.press_no() elif self.client.layout_type is LayoutType.Delizia: + btns = buttons.ScreenButtons(self.client.layout_type) assert TR.recovery__enter_each_word in self._text_content() - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) self.debug.synchronize_at("VerticalMenu") if confirm: - self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) + self.debug.click(btns.vertical_menu_items()[0]) else: - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) else: assert TR.recovery__enter_any_share in self._text_content() self.debug.press_no() @@ -175,14 +176,15 @@ class RecoveryFlow: assert TR.regexp("recovery__x_of_y_entered_template").search( self._text_content() ) - self.debug.click(buttons.corner_button(self.client.layout_type)) + btns = buttons.ScreenButtons(self.client.layout_type) + self.debug.click(btns.menu()) self.debug.synchronize_at("VerticalMenu") - self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) + self.debug.click(btns.vertical_menu_items()[0]) assert (yield).name == "abort_recovery" self.debug.swipe_up() layout = self.debug.read_layout() assert layout.title() == TR.recovery__title_cancel_recovery - self.debug.click(buttons.tap_to_confirm(self.client.layout_type)) + self.debug.click(btns.tap_to_confirm()) else: assert TR.regexp("recovery__x_of_y_entered_template").search( self._text_content() @@ -337,16 +339,17 @@ class RecoveryFlow: self.debug.press_yes() def click_info_delizia(self) -> BRGeneratorType: + btns = buttons.ScreenButtons(self.client.layout_type) # Moving through the menu into the show_shares screen - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) self.debug.synchronize_at("VerticalMenu") - self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) + self.debug.click(btns.vertical_menu_items()[0]) br = yield assert br.name == "show_shares" assert br.code == B.Other # Getting back to the homepage - self.debug.click(buttons.corner_button(self.client.layout_type)) - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) + self.debug.click(btns.menu()) class EthereumFlow: @@ -461,6 +464,7 @@ class EthereumFlow: def _confirm_tx_delizia( self, cancel: bool, info: bool, go_back_from_summary: bool ) -> BRGeneratorType: + btns = buttons.ScreenButtons(self.client.layout_type) assert (yield).name == "confirm_output" title = self.debug.read_layout().title() assert TR.words__address in title @@ -481,17 +485,17 @@ class EthereumFlow: self.debug.press_yes() assert (yield).name == "confirm_ethereum_tx" if info: - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) self.debug.synchronize_at("VerticalMenu") - self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) + self.debug.click(btns.vertical_menu_items()[0]) text = self.debug.read_layout().text_content() assert TR.ethereum__gas_limit in text assert TR.ethereum__gas_price in text - self.debug.click(buttons.corner_button(self.client.layout_type)) - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) + self.debug.click(btns.menu()) self.debug.swipe_up() self.debug.read_layout() - self.debug.click(buttons.tap_to_confirm(self.client.layout_type)) + self.debug.click(btns.tap_to_confirm()) assert (yield).name == "confirm_ethereum_tx" def confirm_tx( @@ -527,10 +531,11 @@ class EthereumFlow: TR.ethereum__staking_claim_intro, ) if self.client.layout_type is LayoutType.Bolt: + btns = buttons.ScreenButtons(self.client.layout_type) # confirm intro if info: self.debug.click( - buttons.corner_button(self.client.layout_type), + btns.menu(), ) assert self.debug.read_layout().title() in ( TR.ethereum__staking_stake_address, @@ -552,17 +557,18 @@ class EthereumFlow: self.debug.press_yes() elif self.client.layout_type is LayoutType.Delizia: + btns = buttons.ScreenButtons(self.client.layout_type) # confirm intro if info: - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) self.debug.synchronize_at("VerticalMenu") - self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) + self.debug.click(btns.vertical_menu_items()[0]) assert self.debug.read_layout().title() in ( TR.ethereum__staking_stake_address, TR.ethereum__staking_claim_address, ) - self.debug.click(buttons.corner_button(self.client.layout_type)) - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) + self.debug.click(btns.menu()) self.debug.swipe_up() br = yield @@ -571,13 +577,13 @@ class EthereumFlow: # confirm summary if info: - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) self.debug.synchronize_at("VerticalMenu") - self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) + self.debug.click(btns.vertical_menu_items()[0]) assert TR.ethereum__gas_limit in self.debug.read_layout().text_content() assert TR.ethereum__gas_price in self.debug.read_layout().text_content() - self.debug.click(buttons.corner_button(self.client.layout_type)) - self.debug.click(buttons.corner_button(self.client.layout_type)) + self.debug.click(btns.menu()) + self.debug.click(btns.menu()) self.debug.swipe_up() # br = yield # FIXME: no BR on sign transaction diff --git a/tests/upgrade_tests/recovery_old.py b/tests/upgrade_tests/recovery_old.py index f44634ef8d..338525f201 100644 --- a/tests/upgrade_tests/recovery_old.py +++ b/tests/upgrade_tests/recovery_old.py @@ -10,48 +10,45 @@ def _enter_word( debug: "DebugLink", word: str, is_slip39: bool = False ) -> "LayoutContent": typed_word = word[:4] - for coords in buttons.type_word(typed_word, debug.layout_type, is_slip39=is_slip39): + actions = buttons.ButtonActions(debug.layout_type) + btns = buttons.ScreenButtons(debug.layout_type) + for coords in actions.type_word(typed_word, is_slip39=is_slip39): debug.click(coords) debug.read_layout(wait=False) - debug.click(buttons.input(debug.layout_type)) + debug.click(btns.mnemonic_confirm()) return debug.read_layout(wait=True) def confirm_recovery(debug: "DebugLink") -> None: - debug.click(buttons.ok(debug.layout_type)) + btns = buttons.ScreenButtons(debug.layout_type) + debug.click(btns.ok()) debug.read_layout(wait=True) def select_number_of_words( debug: "DebugLink", tag_version: tuple | None, num_of_words: int = 20 ) -> None: + btns = buttons.ScreenButtons(debug.layout_type) if "SelectWordCount" not in debug.read_layout().all_components(): - debug.click(buttons.ok(debug.layout_type)) + debug.click(btns.ok()) debug.read_layout(wait=True) if tag_version is None or tag_version > (2, 8, 8): # layout changed after adding the cancel button - coords_map = { - 12: buttons.grid34(0, 2, debug.layout_type), - 18: buttons.grid34(1, 2, debug.layout_type), - 20: buttons.grid34(2, 2, debug.layout_type), - 24: buttons.grid34(1, 3, debug.layout_type), - 33: buttons.grid34(2, 3, debug.layout_type), - } - coords = coords_map.get(num_of_words) + coords = btns.word_count_all_word(num_of_words) else: word_option_offset = 6 word_options = (12, 18, 20, 24, 33) index = word_option_offset + word_options.index( num_of_words ) # raises if num of words is invalid - coords = buttons.grid34(index % 3, index // 3, debug.layout_type) + coords = btns.grid34(index % 3, index // 3) debug.click(coords) debug.read_layout(wait=True) def enter_share(debug: "DebugLink", share: str) -> "LayoutContent": - debug.click(buttons.ok(debug.layout_type)) + debug.click(buttons.ScreenButtons(debug.layout_type).ok()) for word in share.split(" "): _enter_word(debug, word, is_slip39=True)