1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-05-05 16:39:08 +00:00

refactor(tests): split buttons module functionality into buttons and actions

This commit is contained in:
Lukas Bielesch 2025-03-07 12:43:16 +01:00 committed by Lukáš Bielesch
parent 4d52f7805f
commit a4cd4ddaa5
17 changed files with 555 additions and 439 deletions

View File

@ -6,167 +6,227 @@ from trezorlib.debuglink import LayoutType
Coords = Tuple[int, int] Coords = Tuple[int, int]
# display dimensions class ScreenButtons:
def display_height(layout_type): def __init__(self, layout_type: LayoutType):
if layout_type in (LayoutType.Bolt, LayoutType.Delizia): assert layout_type in (LayoutType.Bolt, LayoutType.Delizia)
self.layout_type = layout_type
def _width(self) -> int:
return 240 return 240
else:
raise ValueError("Wrong layout type")
def _height(self) -> int:
def display_width(layout_type):
if layout_type in (LayoutType.Bolt, LayoutType.Delizia):
return 240 return 240
else:
raise ValueError("Wrong layout type")
def _grid(self, dim: int, grid_cells: int, cell: int) -> int:
# grid coordinates assert cell < grid_cells
def grid(dim: int, grid_cells: int, cell: int) -> int:
step = dim // grid_cells step = dim // grid_cells
ofs = step // 2 ofs = step // 2
return cell * step + ofs 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)
def grid35(x: int, y: int, layout_type: LayoutType) -> Coords: # TODO: do not expose this
return grid(display_width(layout_type), 3, x), grid( # 3 columns, 3 rows, 1st row is input area
display_height(layout_type), 5, y def grid34(self, x: int, y: int) -> Coords:
) return self._grid(self._width(), 3, x), self._grid(self._height(), 4, y)
# Horizontal coordinates
def _left(self) -> int:
return self._grid(self._width(), 3, 0)
def grid34(x: int, y: int, layout_type: LayoutType) -> Coords: def _mid(self) -> int:
assert layout_type in (LayoutType.Bolt, LayoutType.Delizia) return self._grid(self._width(), 3, 1)
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)
def _grid34_from_index(idx: int, layout_type: LayoutType) -> Coords: # Vertical coordinates
grid_x = idx % 3 def _top(self) -> int:
grid_y = idx // 3 + 1 # first line is empty return self._grid(self._height(), 6, 0)
return grid34(grid_x, grid_y, layout_type)
def _bottom(self) -> int:
return self._grid(self._height(), 6, 5)
# Horizontal coordinates # Buttons
def left(layout_type: LayoutType):
return grid(display_width(layout_type), 3, 0)
# Right bottom
def ok(self) -> Coords:
return (self._right(), self._bottom())
def mid(layout_type: LayoutType): # Left bottom
return grid(display_width(layout_type), 3, 1) def cancel(self) -> Coords:
return (self._left(), self._bottom())
# Mid bottom
def info(self) -> Coords:
return (self._mid(), self._bottom())
def right(layout_type: LayoutType): # Menu/close menu button
return grid(display_width(layout_type), 3, 2) def menu(self) -> Coords:
if self.layout_type in (LayoutType.Bolt, LayoutType.Delizia):
# Vertical coordinates
def top(layout_type: LayoutType):
return grid(display_height(layout_type), 6, 0)
def bottom(layout_type: LayoutType):
return grid(display_height(layout_type), 6, 5)
# Buttons
def ok(layout_type: LayoutType) -> Coords:
return (right(layout_type), bottom(layout_type))
def cancel(layout_type: LayoutType) -> Coords:
return (left(layout_type), bottom(layout_type))
def info(layout_type: LayoutType) -> Coords:
return (mid(layout_type), bottom(layout_type))
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")
def corner_button(layout_type: LayoutType) -> Coords:
if layout_type in (LayoutType.Bolt, LayoutType.Delizia):
return (215, 25) return (215, 25)
else: else:
raise ValueError("Wrong layout type") raise ValueError("Wrong layout type")
# 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))
def confirm_word(layout_type: LayoutType) -> Coords: # Yes/No decision component
if layout_type in (LayoutType.Bolt, LayoutType.Delizia): def ui_yes(self) -> Coords:
return (mid(layout_type), top(layout_type)) assert self.layout_type is LayoutType.Delizia
return self.grid34(2, 2)
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: else:
raise ValueError("Wrong layout type") raise ValueError("Wrong layout type")
def number_input_plus(self) -> Coords:
# PIN/passphrase input if self.layout_type is LayoutType.Bolt:
def input(layout_type: LayoutType) -> Coords: return (self._right(), self._grid(self._height(), 5, 1))
return (mid(layout_type), top(layout_type)) elif self.layout_type is LayoutType.Delizia:
return (self._right(), self._grid(self._height(), 5, 3))
# 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: else:
raise ValueError("Wrong layout type") raise ValueError("Wrong layout type")
def word_count_all_word(self, word_count: int) -> Coords:
def reset_plus(layout_type: LayoutType) -> Coords: assert word_count in (12, 18, 20, 24, 33)
if layout_type is LayoutType.Bolt: if self.layout_type is LayoutType.Bolt:
return (right(layout_type), grid(display_height(layout_type), 5, 1)) coords_map = {
elif layout_type is LayoutType.Delizia: 12: self.grid34(0, 2),
return (right(layout_type), grid(display_height(layout_type), 5, 3)) 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: else:
raise ValueError("Wrong layout type") raise ValueError("Wrong layout type")
return coords_map[word_count]
# select word component buttons def word_count_all_cancel(self) -> Coords:
def reset_word_check(layout_type: LayoutType) -> Coords: if self.layout_type is LayoutType.Bolt:
if layout_type in (LayoutType.Bolt, LayoutType.Delizia): return self.grid34(0, 3)
elif self.layout_type is LayoutType.Delizia:
return self.grid34(0, 3)
else:
raise ValueError("Wrong 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 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)
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 [ return [
(mid(layout_type), grid(display_height(layout_type), 5, 2)), (self._mid(), self._grid(self._height(), 5, 2)),
(mid(layout_type), grid(display_height(layout_type), 5, 3)), (self._mid(), self._grid(self._height(), 5, 3)),
(mid(layout_type), grid(display_height(layout_type), 5, 4)), (self._mid(), self._grid(self._height(), 5, 4)),
] ]
else: else:
raise ValueError("Wrong layout type") raise ValueError("Wrong layout type")
# vertical menu buttons
def vertical_menu_items(self) -> "list[Coords]":
assert self.layout_type is LayoutType.Delizia
# vertical menu buttons
def vertical_menu(layout_type: LayoutType) -> Coords:
if layout_type in (LayoutType.Bolt, LayoutType.Delizia):
return [ return [
(mid(layout_type), grid(display_height(layout_type), 4, 1)), (self._mid(), self._grid(self._height(), 4, 1)),
(mid(layout_type), grid(display_height(layout_type), 4, 2)), (self._mid(), self._grid(self._height(), 4, 2)),
(mid(layout_type), grid(display_height(layout_type), 4, 3)), (self._mid(), self._grid(self._height(), 4, 3)),
] ]
# 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)
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 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: else:
raise ValueError("Wrong layout type") raise ValueError("Wrong layout type")
def pin_confirm(self) -> Coords:
return self.pin_passphrase_grid(2, 3)
def tap_to_confirm(layout_type: LayoutType) -> Coords: # Mnemonic keyboard
assert layout_type is LayoutType.Delizia def mnemonic_from_index(self, idx: int) -> Coords:
return vertical_menu(layout_type)[1] 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") BUTTON_LETTERS_BIP39 = ("abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "vwx", "yz")
@ -194,45 +254,34 @@ def get_passphrase_choices(char: str) -> tuple[str, ...]:
return PASSPHRASE_SPECIAL return PASSPHRASE_SPECIAL
def passphrase(char: str, layout_type: LayoutType) -> Tuple[Coords, int]: 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) choices = get_passphrase_choices(char)
idx = next(i for i, letters in enumerate(choices) if char in letters) idx = next(i for i, letters in enumerate(choices) if char in letters)
click_amount = choices[idx].index(char) + 1 click_amount = choices[idx].index(char) + 1
return pin_passphrase_index(idx, layout_type), click_amount return self.buttons.pin_passphrase_index(idx), click_amount
def type_word(self, word: str, is_slip39: bool = False) -> Iterator[Coords]:
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 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(
word: str, layout_type: LayoutType, is_slip39: bool = False
) -> Iterator[Coords]:
if is_slip39: if is_slip39:
yield from _type_word_slip39(word, layout_type) yield from self._type_word_slip39(word)
else: else:
yield from _type_word_bip39(word, layout_type) yield from self._type_word_bip39(word)
def _type_word_slip39(self, word: str) -> Iterator[Coords]:
def _type_word_slip39(word: str, layout_type: LayoutType) -> Iterator[Coords]:
for l in word: for l in word:
idx = next(i for i, letters in enumerate(BUTTON_LETTERS_SLIP39) if l in letters) idx = next(
yield _grid34_from_index(idx, layout_type) i for i, letters in enumerate(BUTTON_LETTERS_SLIP39) if l in letters
)
yield self.buttons.mnemonic_from_index(idx)
def _type_word_bip39(self, word: str) -> Iterator[Coords]:
def _type_word_bip39(word: str, layout_type: LayoutType) -> Iterator[Coords]:
coords_prev: Coords | None = None coords_prev: Coords | None = None
for letter in word: for letter in word:
time.sleep(0.1) # not being so quick to miss something time.sleep(0.1) # not being so quick to miss something
coords, amount = _letter_coords_and_amount(letter, layout_type) coords, amount = self._letter_coords_and_amount(letter)
# If the button is the same as for the previous letter, # If the button is the same as for the previous letter,
# waiting a second before pressing it again. # waiting a second before pressing it again.
if coords == coords_prev: if coords == coords_prev:
@ -241,10 +290,9 @@ def _type_word_bip39(word: str, layout_type: LayoutType) -> Iterator[Coords]:
for _ in range(amount): for _ in range(amount):
yield coords yield coords
def _letter_coords_and_amount(self, letter: str) -> Tuple[Coords, int]:
def _letter_coords_and_amount( idx = next(
letter: str, layout_type: LayoutType i for i, letters in enumerate(BUTTON_LETTERS_BIP39) if letter in letters
) -> 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 click_amount = BUTTON_LETTERS_BIP39[idx].index(letter) + 1
return _grid34_from_index(idx, layout_type), click_amount return self.buttons.mnemonic_from_index(idx), click_amount

View File

@ -49,7 +49,8 @@ def get_char_category(char: str) -> PassphraseCategory:
def go_next(debug: "DebugLink") -> LayoutContent: def go_next(debug: "DebugLink") -> LayoutContent:
if debug.layout_type is LayoutType.Bolt: 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: elif debug.layout_type is LayoutType.Caesar:
debug.press_right() debug.press_right()
elif debug.layout_type is LayoutType.Delizia: 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: def go_back(debug: "DebugLink", r_middle: bool = False) -> LayoutContent:
if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): 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: elif debug.layout_type is LayoutType.Caesar:
if r_middle: if r_middle:
debug.press_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: def unlock_gesture(debug: "DebugLink") -> LayoutContent:
if debug.layout_type is LayoutType.Bolt: 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: elif debug.layout_type is LayoutType.Caesar:
debug.press_right() debug.press_right()
elif debug.layout_type is LayoutType.Delizia: 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: else:
raise RuntimeError("Unknown model") raise RuntimeError("Unknown model")
return debug.read_layout() return debug.read_layout()

View File

@ -91,7 +91,8 @@ CLICKS_HELP = """\
Type 'y' or just press Enter to click the right button (usually "OK") Type 'y' or just press Enter to click the right button (usually "OK")
Type 'n' to click the left button (usually "Cancel") 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 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 '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 'u' or 'j' to swipe up, 'd' or 'k' to swipe down.
Type 'confirm' for hold-to-confirm (or a confirmation signal without clicking). Type 'confirm' for hold-to-confirm (or a confirmation signal without clicking).
@ -138,29 +139,37 @@ def send_clicks(dest):
input_str = key[2:] input_str = key[2:]
output = f"debug.input({input_str!r})" output = f"debug.input({input_str!r})"
DEBUGLINK.input(input_str) DEBUGLINK.input(input_str)
elif key.startswith("g"): elif key.startswith("m"):
x, y = [int(s) - 1 for s in key[1:].split(",")] x, y = [int(s) - 1 for s in key[1:].split(",")]
output = ( 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": elif key == "y":
output = "debug.click(buttons.ok(layout_type))" output = "debug.click(ScreenButtons(layout_type).ok())"
DEBUGLINK.click(buttons.ok(DEBUGLINK.layout_type)) DEBUGLINK.click(buttons.ScreenButtons(DEBUGLINK.layout_type).ok())
elif key == "n": elif key == "n":
output = "debug.click(buttons.cancel(layout_type))" output = "debug.click(ScreenButtons(layout_type).cancel())"
DEBUGLINK.click(buttons.cancel(DEBUGLINK.layout_type)) DEBUGLINK.click(buttons.ScreenButtons(DEBUGLINK.layout_type).cancel())
elif key in "0123456789": elif key in "0123456789":
if key == "0": index = int(key)
x, y = 1, 4 output = f"debug.click(ScreenButtons(layout_type).pin_passphrase_index({index}))"
else: DEBUGLINK.click(
i = int(key) - 1 buttons.ScreenButtons(DEBUGLINK.layout_type).pin_passphrase_index(
x = i % 3 index
y = 3 - (i // 3) # trust me )
output = (
f"debug.click(buttons.grid35({x}, {y}, {DEBUGLINK.layout_type}))"
) )
DEBUGLINK.click(buttons.grid35(x, y, DEBUGLINK.layout_type))
elif key == "stop": elif key == "stop":
return return
else: else:

View File

@ -17,15 +17,15 @@ def enter_word(
debug: "DebugLink", word: str, is_slip39: bool = False debug: "DebugLink", word: str, is_slip39: bool = False
) -> "LayoutContent": ) -> "LayoutContent":
if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): 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] typed_word = word[:4]
for coords in buttons.type_word( for coords in actions.type_word(typed_word, is_slip39=is_slip39):
typed_word, debug.layout_type, is_slip39=is_slip39
):
debug.click(coords) debug.click(coords)
if debug.layout_type is LayoutType.Delizia and not is_slip39 and len(word) > 4: 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 # 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(btns.mnemonic_confirm())
debug.click(buttons.input(debug.layout_type)) debug.click(btns.mnemonic_confirm())
return debug.read_layout() return debug.read_layout()
elif debug.layout_type is LayoutType.Caesar: elif debug.layout_type is LayoutType.Caesar:
letter_index = 0 letter_index = 0
@ -57,7 +57,8 @@ def confirm_recovery(debug: "DebugLink", title: str = "recovery__title") -> None
layout = debug.read_layout() layout = debug.read_layout()
assert TR.translate(title) == layout.title() assert TR.translate(title) == layout.title()
if debug.layout_type is LayoutType.Bolt: 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: elif debug.layout_type is LayoutType.Delizia:
debug.swipe_up() debug.swipe_up()
elif debug.layout_type is LayoutType.Caesar: elif debug.layout_type is LayoutType.Caesar:
@ -70,12 +71,13 @@ def cancel_select_number_of_words(
unlock_repeated_backup=False, unlock_repeated_backup=False,
) -> None: ) -> None:
if debug.layout_type is LayoutType.Bolt: if debug.layout_type is LayoutType.Bolt:
btns = buttons.ScreenButtons(debug.layout_type)
assert debug.read_layout().text_content() == TR.recovery__num_of_words assert debug.read_layout().text_content() == TR.recovery__num_of_words
# click the button from ValuePad # click the button from ValuePad
if unlock_repeated_backup: if unlock_repeated_backup:
coords = buttons.grid34(0, 2, debug.layout_type) coords = btns.word_count_repeated_cancel()
else: else:
coords = buttons.grid34(0, 3, debug.layout_type) coords = btns.word_count_all_cancel()
debug.click(coords) debug.click(coords)
elif debug.layout_type is LayoutType.Caesar: elif debug.layout_type is LayoutType.Caesar:
debug.press_right() debug.press_right()
@ -84,8 +86,13 @@ def cancel_select_number_of_words(
# navigate to the number and confirm it # navigate to the number and confirm it
debug.press_left() debug.press_left()
elif debug.layout_type is LayoutType.Delizia: elif debug.layout_type is LayoutType.Delizia:
btns = buttons.ScreenButtons(debug.layout_type)
# click the button from ValuePad # 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: else:
raise ValueError("Unknown model") raise ValueError("Unknown model")
@ -99,23 +106,13 @@ def select_number_of_words(
assert TR.recovery__num_of_words in layout.text_content() assert TR.recovery__num_of_words in layout.text_content()
def select_bolt() -> "LayoutContent": def select_bolt() -> "LayoutContent":
btns = buttons.ScreenButtons(debug.layout_type)
# click the button from ValuePad # click the button from ValuePad
if unlock_repeated_backup: if unlock_repeated_backup:
coords_map = { coords = btns.word_count_repeated_word(num_of_words)
20: buttons.grid34(1, 2, debug.layout_type),
33: buttons.grid34(2, 2, debug.layout_type),
}
else: else:
coords_map = { coords = btns.word_count_all_word(num_of_words)
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")
debug.click(coords) debug.click(coords)
return debug.read_layout() return debug.read_layout()
@ -129,23 +126,12 @@ def select_number_of_words(
return debug.read_layout() return debug.read_layout()
def select_delizia() -> "LayoutContent": def select_delizia() -> "LayoutContent":
btns = buttons.ScreenButtons(debug.layout_type)
# click the button from ValuePad # click the button from ValuePad
if unlock_repeated_backup: if unlock_repeated_backup:
coords_map = { coords = btns.word_count_repeated_word(num_of_words)
20: buttons.grid34(0, 1, debug.layout_type),
33: buttons.grid34(2, 1, debug.layout_type),
}
else: else:
coords_map = { coords = btns.word_count_all_word(num_of_words)
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")
debug.click(coords) debug.click(coords)
return debug.read_layout() return debug.read_layout()
@ -200,8 +186,9 @@ def enter_share(
debug.swipe_up() debug.swipe_up()
layout = debug.read_layout() layout = debug.read_layout()
else: else:
btns = buttons.ScreenButtons(debug.layout_type)
assert TR.translate(before_title) in debug.read_layout().title() 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() layout = debug.read_layout()
assert "MnemonicKeyboard" in layout.all_components() assert "MnemonicKeyboard" in layout.all_components()
@ -276,9 +263,10 @@ def enter_seed_previous_correct(
if go_back: if go_back:
go_back = False go_back = False
if debug.layout_type is LayoutType.Bolt: if debug.layout_type is LayoutType.Bolt:
btns = buttons.ScreenButtons(debug.layout_type)
debug.swipe_right() debug.swipe_right()
for _ in range(len(bad_word)): 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: elif debug.layout_type is LayoutType.Caesar:
layout = debug.read_layout() layout = debug.read_layout()
@ -295,9 +283,10 @@ def enter_seed_previous_correct(
debug.press_middle() debug.press_middle()
layout = debug.read_layout() layout = debug.read_layout()
elif debug.layout_type is LayoutType.Delizia: 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)): for _ in range(len(bad_word)):
debug.click(buttons.recovery_delete(debug.layout_type)) debug.click(btns.mnemonic_erase())
continue continue
if i in bad_indexes: if i in bad_indexes:
@ -322,7 +311,8 @@ def prepare_enter_seed(
or TR.translate(layout_text) in debug.read_layout().text_content() or TR.translate(layout_text) in debug.read_layout().text_content()
) )
if debug.layout_type is LayoutType.Bolt: 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: elif debug.layout_type is LayoutType.Delizia:
debug.swipe_up() debug.swipe_up()
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() assert title in layout.title()
if debug.layout_type is LayoutType.Bolt: 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() layout = debug.read_layout()
assert cancel_title in layout.title() assert cancel_title in layout.title()
debug.click(buttons.ok(debug.layout_type)) debug.click(btns.ok())
elif debug.layout_type is LayoutType.Caesar: elif debug.layout_type is LayoutType.Caesar:
debug.press_left() debug.press_left()
layout = debug.read_layout() 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()): for _ in range(layout.page_count()):
debug.press_right() debug.press_right()
elif debug.layout_type is LayoutType.Delizia: elif debug.layout_type is LayoutType.Delizia:
btns = buttons.ScreenButtons(debug.layout_type)
# go to menu # go to menu
debug.click(buttons.corner_button(debug.layout_type)) debug.click(btns.menu())
layout = debug.read_layout() layout = debug.read_layout()
assert ( assert (
TR.translate(f"recovery__cancel_{recovery_type}") in layout.text_content() 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: else:
raise ValueError("Unknown model") raise ValueError("Unknown model")

View File

@ -15,10 +15,12 @@ if TYPE_CHECKING:
def confirm_new_wallet(debug: "DebugLink") -> None: def confirm_new_wallet(debug: "DebugLink") -> None:
assert debug.read_layout().title() == TR.reset__title_create_wallet assert debug.read_layout().title() == TR.reset__title_create_wallet
if debug.layout_type is LayoutType.Bolt: 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: elif debug.layout_type is LayoutType.Delizia:
btns = buttons.ScreenButtons(debug.layout_type)
debug.swipe_up() 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: elif debug.layout_type is LayoutType.Caesar:
debug.press_right() debug.press_right()
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: def confirm_read(debug: "DebugLink", middle_r: bool = False) -> None:
if debug.layout_type is LayoutType.Bolt: 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: elif debug.layout_type is LayoutType.Delizia:
debug.swipe_up() debug.swipe_up()
elif debug.layout_type is LayoutType.Caesar: elif debug.layout_type is LayoutType.Caesar:
@ -50,14 +53,16 @@ def cancel_backup(
debug: "DebugLink", middle_r: bool = False, confirm: bool = False debug: "DebugLink", middle_r: bool = False, confirm: bool = False
) -> None: ) -> None:
if debug.layout_type is LayoutType.Bolt: if debug.layout_type is LayoutType.Bolt:
debug.click(buttons.cancel(debug.layout_type)) btns = buttons.ScreenButtons(debug.layout_type)
debug.click(buttons.cancel(debug.layout_type)) debug.click(btns.cancel())
debug.click(btns.cancel())
elif debug.layout_type is LayoutType.Delizia: elif debug.layout_type is LayoutType.Delizia:
debug.click(buttons.corner_button(debug.layout_type)) btns = buttons.ScreenButtons(debug.layout_type)
debug.click(buttons.vertical_menu(debug.layout_type)[0]) debug.click(btns.menu())
debug.click(btns.vertical_menu_items()[0])
if confirm: if confirm:
debug.swipe_up() 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: elif debug.layout_type is LayoutType.Caesar:
debug.press_left() debug.press_left()
debug.press_left() debug.press_left()
@ -65,19 +70,16 @@ def cancel_backup(
def set_selection(debug: "DebugLink", diff: int) -> None: def set_selection(debug: "DebugLink", diff: int) -> None:
if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia):
btns = buttons.ScreenButtons(debug.layout_type)
assert "NumberInputDialog" in debug.read_layout().all_components() assert "NumberInputDialog" in debug.read_layout().all_components()
button = ( button = btns.number_input_minus() if diff < 0 else btns.number_input_plus()
buttons.reset_minus(debug.layout_type)
if diff < 0
else buttons.reset_plus(debug.layout_type)
)
diff = abs(diff) diff = abs(diff)
for _ in range(diff): for _ in range(diff):
debug.click(button) debug.click(button)
if debug.layout_type is LayoutType.Bolt: if debug.layout_type is LayoutType.Bolt:
debug.click(buttons.ok(debug.layout_type)) debug.click(btns.ok())
else: else:
debug.swipe_up() debug.swipe_up()
elif debug.layout_type is LayoutType.Caesar: 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 # There is hold-to-confirm button
if do_htc: if do_htc:
if debug.layout_type is LayoutType.Bolt: 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: 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: elif debug.layout_type is LayoutType.Caesar:
debug.press_right(hold_ms=1200) debug.press_right(hold_ms=1200)
else: else:
@ -142,6 +146,7 @@ def confirm_words(debug: "DebugLink", words: list[str]) -> None:
layout = debug.read_layout() layout = debug.read_layout()
if debug.layout_type is LayoutType.Bolt: if debug.layout_type is LayoutType.Bolt:
btns = buttons.ScreenButtons(debug.layout_type)
assert TR.regexp("reset__select_word_x_of_y_template").match( assert TR.regexp("reset__select_word_x_of_y_template").match(
layout.text_content() layout.text_content()
) )
@ -157,9 +162,10 @@ def confirm_words(debug: "DebugLink", words: list[str]) -> None:
] ]
wanted_word = words[word_pos - 1].lower() wanted_word = words[word_pos - 1].lower()
button_pos = btn_texts.index(wanted_word) 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() layout = debug.read_layout()
elif debug.layout_type is LayoutType.Delizia: 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()) assert TR.regexp("reset__select_word_x_of_y_template").match(layout.subtitle())
for _ in range(3): for _ in range(3):
# "Select word 3 of 20" # "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() wanted_word = words[word_pos - 1].lower()
button_pos = btn_texts.index(wanted_word) 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() layout = debug.read_layout()
elif debug.layout_type is LayoutType.Caesar: elif debug.layout_type is LayoutType.Caesar:
assert TR.reset__select_correct_word in layout.text_content() assert TR.reset__select_correct_word in layout.text_content()

View File

@ -21,7 +21,7 @@ from typing import TYPE_CHECKING, Tuple
import pytest import pytest
from trezorlib import btc, device, exceptions, messages 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.protobuf import MessageType
from trezorlib.tools import parse_path from trezorlib.tools import parse_path
@ -33,7 +33,7 @@ from . import recovery
from .common import go_next, unlock_gesture from .common import go_next, unlock_gesture
if TYPE_CHECKING: if TYPE_CHECKING:
from trezorlib.debuglink import DebugLink, LayoutContent from trezorlib.debuglink import LayoutContent
from ..device_handler import BackgroundDeviceHandler from ..device_handler import BackgroundDeviceHandler
@ -53,8 +53,17 @@ TXHASH_d5f65e = bytes.fromhex(
PIN4 = "1234" PIN4 = "1234"
def _center_button(layout_type: LayoutType) -> Tuple[int, int]: def _passphrase_j(debug: DebugLink) -> Tuple[int, int]:
return buttons.grid35(1, 2, layout_type) 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): 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) layout = go_next(debug)
if debug.layout_type is LayoutType.Delizia: 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() layout = debug.read_layout()
assert layout.main_component() == "Homescreen" assert layout.main_component() == "Homescreen"
device_handler.result() device_handler.result()
@ -107,8 +117,9 @@ def test_autolock_interrupts_signing(device_handler: "BackgroundDeviceHandler"):
) )
if debug.layout_type is LayoutType.Bolt: if debug.layout_type is LayoutType.Bolt:
debug.click(buttons.ok(debug.layout_type)) btns = buttons.ScreenButtons(debug.layout_type)
debug.click(buttons.ok(debug.layout_type)) debug.click(btns.ok())
debug.click(btns.ok())
layout = debug.read_layout() layout = debug.read_layout()
assert TR.send__total_amount in layout.text_content() assert TR.send__total_amount in layout.text_content()
assert "0.0039 BTC" 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: if debug.layout_type is LayoutType.Bolt:
debug.click(buttons.ok(debug.layout_type)) btns = buttons.ScreenButtons(debug.layout_type)
debug.click(buttons.ok(debug.layout_type)) debug.click(btns.ok())
debug.click(btns.ok())
layout = debug.read_layout() layout = debug.read_layout()
assert TR.send__total_amount in layout.text_content() assert TR.send__total_amount in layout.text_content()
assert "0.0039 BTC" in layout.text_content() assert "0.0039 BTC" in layout.text_content()
elif debug.layout_type is LayoutType.Delizia: elif debug.layout_type is LayoutType.Delizia:
btns = buttons.ScreenButtons(debug.layout_type)
debug.swipe_up() debug.swipe_up()
debug.swipe_up() debug.swipe_up()
layout = debug.read_layout() 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) device_handler.client.set_filter(messages.TxAck, sleepy_filter)
# confirm transaction # confirm transaction
if debug.layout_type is LayoutType.Bolt: 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: 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: elif debug.layout_type is LayoutType.Caesar:
debug.press_middle() debug.press_middle()
@ -220,12 +233,9 @@ def test_autolock_passphrase_keyboard(device_handler: "BackgroundDeviceHandler")
# enter passphrase - slowly # enter passphrase - slowly
# keep clicking for long enough to trigger the autolock if it incorrectly ignored key presses # keep clicking for long enough to trigger the autolock if it incorrectly ignored key presses
for _ in range(math.ceil(11 / 1.5)): 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" # click at "j"
debug.click(_center_button(debug.layout_type)) debug.click(_passphrase_j(debug))
elif debug.layout_type is LayoutType.Delizia:
# click at "j"
debug.click((20, 120))
elif debug.layout_type is LayoutType.Caesar: elif debug.layout_type is LayoutType.Caesar:
# just go right # just go right
# NOTE: because of passphrase randomization it would be a pain to input # 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) time.sleep(1.5)
# Send the passphrase to the client (TT has it clicked already, TR needs to input it) # Send the passphrase to the client (TT has it clicked already, TR needs to input it)
if debug.layout_type is LayoutType.Bolt: if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia):
debug.click(buttons.ok(debug.layout_type)) btns = buttons.ScreenButtons(debug.layout_type)
elif debug.layout_type is LayoutType.Delizia: debug.click(btns.passphrase_confirm())
debug.click(buttons.corner_button(debug.layout_type))
elif debug.layout_type is LayoutType.Caesar: elif debug.layout_type is LayoutType.Caesar:
debug.input("j" * 8) 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 # autolock must activate even if we pressed some buttons
for _ in range(math.ceil(6 / 1.5)): for _ in range(math.ceil(6 / 1.5)):
if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): 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: elif debug.layout_type is LayoutType.Caesar:
debug.press_middle() debug.press_middle()
time.sleep(1.5) time.sleep(1.5)
@ -359,29 +368,33 @@ def test_dryrun_enter_word_slowly(device_handler: "BackgroundDeviceHandler"):
recovery.select_number_of_words(debug, 20) recovery.select_number_of_words(debug, 20)
if debug.layout_type is LayoutType.Bolt: 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() layout = debug.read_layout()
assert layout.main_component() == "MnemonicKeyboard" assert layout.main_component() == "MnemonicKeyboard"
# type the word OCEAN slowly # 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) time.sleep(9)
debug.click(coords) debug.click(coords)
debug.click(buttons.input(debug.layout_type)) debug.click(btns.mnemonic_confirm())
layout = debug.read_layout() layout = debug.read_layout()
# should not have locked, even though we took 9 seconds to type each letter # should not have locked, even though we took 9 seconds to type each letter
assert layout.main_component() == "MnemonicKeyboard" assert layout.main_component() == "MnemonicKeyboard"
elif debug.layout_type is LayoutType.Delizia: elif debug.layout_type is LayoutType.Delizia:
btns = buttons.ScreenButtons(debug.layout_type)
actions = buttons.ButtonActions(debug.layout_type)
debug.swipe_up() debug.swipe_up()
layout = debug.read_layout() layout = debug.read_layout()
assert layout.main_component() == "MnemonicKeyboard" assert layout.main_component() == "MnemonicKeyboard"
# type the word OCEAN slowly # 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) time.sleep(9)
debug.click(coords) debug.click(coords)
debug.click(buttons.input(debug.layout_type)) debug.click(btns.mnemonic_confirm())
layout = debug.read_layout() layout = debug.read_layout()
# should not have locked, even though we took 9 seconds to type each letter # should not have locked, even though we took 9 seconds to type each letter
assert layout.main_component() == "MnemonicKeyboard" assert layout.main_component() == "MnemonicKeyboard"

View File

@ -81,7 +81,8 @@ def test_hold_to_lock(device_handler: "BackgroundDeviceHandler"):
if debug.layout_type is LayoutType.Caesar: if debug.layout_type is LayoutType.Caesar:
debug.press_right() debug.press_right()
else: else:
debug.click(buttons.info(debug.layout_type)) btns = buttons.ScreenButtons(debug.layout_type)
debug.click(btns.info())
layout = debug.read_layout() layout = debug.read_layout()
assert "PinKeyboard" in layout.all_components() assert "PinKeyboard" in layout.all_components()
debug.input("1234") debug.input("1234")

View File

@ -117,7 +117,8 @@ def press_char(debug: "DebugLink", char: str) -> None:
go_to_category(debug, char_category) 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, # If the button is the same as for the previous char,
# waiting a second before pressing it again. # waiting a second before pressing it again.
# (not for a space) # (not for a space)
@ -141,13 +142,15 @@ def input_passphrase(debug: "DebugLink", passphrase: str, check: bool = True) ->
def enter_passphrase(debug: "DebugLink") -> None: def enter_passphrase(debug: "DebugLink") -> None:
"""Enter a passphrase""" """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) debug.click(coords)
def delete_char(debug: "DebugLink") -> None: def delete_char(debug: "DebugLink") -> None:
"""Deletes the last char""" """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) debug.click(coords)
@ -216,8 +219,8 @@ def test_passphrase_loop_all_characters(device_handler: "BackgroundDeviceHandler
go_to_category(debug, category) go_to_category(debug, category)
enter_passphrase(debug) enter_passphrase(debug)
coords = buttons.pin_passphrase_grid(11, debug.layout_type) btns = buttons.ScreenButtons(debug.layout_type)
debug.click(coords) debug.click(btns.passphrase_confirm())
@pytest.mark.setup_client(passphrase=True) @pytest.mark.setup_client(passphrase=True)
@ -225,7 +228,8 @@ def test_passphrase_click_same_button_many_times(
device_handler: "BackgroundDeviceHandler", device_handler: "BackgroundDeviceHandler",
): ):
with prepare_passphrase_dialogue(device_handler) as debug: 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): for _ in range(10):
debug.click(a_coords) debug.click(a_coords)

View File

@ -87,10 +87,11 @@ def get_passphrase_choices(char: str) -> tuple[str, ...]:
def passphrase(char: str, layout_type: LayoutType) -> Tuple[buttons.Coords, int]: def passphrase(char: str, layout_type: LayoutType) -> Tuple[buttons.Coords, int]:
btns = buttons.ScreenButtons(layout_type)
choices = get_passphrase_choices(char) choices = get_passphrase_choices(char)
idx = next(i for i, letters in enumerate(choices) if char in letters) idx = next(i for i, letters in enumerate(choices) if char in letters)
click_amount = choices[idx].index(char) + 1 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 @contextmanager
@ -171,16 +172,16 @@ def input_passphrase(debug: "DebugLink", passphrase: str, check: bool = True) ->
def enter_passphrase(debug: "DebugLink") -> None: def enter_passphrase(debug: "DebugLink") -> None:
"""Enter a passphrase""" """Enter a passphrase"""
is_empty: bool = len(debug.read_layout().passphrase()) == 0 is_empty: bool = len(debug.read_layout().passphrase()) == 0
coords = buttons.corner_button(debug.layout_type) # top-right corner btns = buttons.ScreenButtons(debug.layout_type)
debug.click(coords) debug.click(btns.passphrase_confirm())
if is_empty: if is_empty:
debug.click(buttons.ui_yes(debug.layout_type)) debug.click(btns.ui_yes())
def delete_char(debug: "DebugLink") -> None: def delete_char(debug: "DebugLink") -> None:
"""Deletes the last char""" """Deletes the last char"""
coords = buttons.pin_passphrase_grid(9, debug.layout_type) btns = buttons.ScreenButtons(debug.layout_type)
debug.click(coords) debug.click(btns.pin_passphrase_erase())
VECTORS = ( # passphrase, address VECTORS = ( # passphrase, address
@ -250,8 +251,8 @@ def test_passphrase_loop_all_characters(device_handler: "BackgroundDeviceHandler
debug.read_layout() debug.read_layout()
enter_passphrase(debug) enter_passphrase(debug)
coords = buttons.pin_passphrase_grid(11, debug.layout_type) btns = buttons.ScreenButtons(debug.layout_type)
debug.click(coords) debug.click(btns.passphrase_confirm())
@pytest.mark.setup_client(passphrase=True) @pytest.mark.setup_client(passphrase=True)
@ -259,7 +260,8 @@ def test_passphrase_click_same_button_many_times(
device_handler: "BackgroundDeviceHandler", device_handler: "BackgroundDeviceHandler",
): ):
with prepare_passphrase_dialogue(device_handler) as debug: 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): for _ in range(10):
debug.click(a_coords) debug.click(a_coords)

View File

@ -138,8 +138,9 @@ def prepare(
yield debug yield debug
if debug.layout_type is LayoutType.Delizia and tap: if debug.layout_type is LayoutType.Delizia and tap:
btns = buttons.ScreenButtons(debug.layout_type)
go_next(debug) go_next(debug)
debug.click(buttons.tap_to_confirm(debug.layout_type)) debug.click(btns.tap_to_confirm())
else: else:
go_next(debug) go_next(debug)
@ -154,12 +155,12 @@ def _input_pin(debug: "DebugLink", pin: str, check: bool = False) -> None:
"""Input the PIN""" """Input the PIN"""
if check: if check:
before = debug.read_layout().pin() before = debug.read_layout().pin()
if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia):
btns = buttons.ScreenButtons(debug.layout_type)
digits_order = debug.read_layout().tt_pin_digits_order() digits_order = debug.read_layout().tt_pin_digits_order()
for digit in pin: for digit in pin:
digit_index = digits_order.index(digit) 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) debug.click(coords)
elif debug.layout_type is LayoutType.Caesar: elif debug.layout_type is LayoutType.Caesar:
for digit in pin: 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: def _see_pin(debug: "DebugLink") -> None:
"""Navigate to "SHOW" and press it""" """Navigate to "SHOW" and press it"""
if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): 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: elif debug.layout_type is LayoutType.Caesar:
navigate_to_action_and_press(debug, SHOW, TR_PIN_ACTIONS) 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): for _ in range(digits_to_delete):
if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): 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: elif debug.layout_type is LayoutType.Caesar:
navigate_to_action_and_press(debug, DELETE, TR_PIN_ACTIONS) 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: def _delete_all(debug: "DebugLink", check: bool = True) -> None:
"""Navigate to "DELETE" and hold it until all digits are deleted""" """Navigate to "DELETE" and hold it until all digits are deleted"""
if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): 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: elif debug.layout_type is LayoutType.Caesar:
navigate_to_action_and_press(debug, DELETE, TR_PIN_ACTIONS, hold_ms=1000) 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: def _confirm_pin(debug: "DebugLink") -> None:
"""Navigate to "ENTER" and press it""" """Navigate to "ENTER" and press it"""
if debug.layout_type in (LayoutType.Bolt, LayoutType.Delizia): 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: elif debug.layout_type is LayoutType.Caesar:
navigate_to_action_and_press(debug, ENTER, TR_PIN_ACTIONS) navigate_to_action_and_press(debug, ENTER, TR_PIN_ACTIONS)

View File

@ -36,10 +36,11 @@ pytestmark = [
def test_tutorial_ignore_menu(device_handler: "BackgroundDeviceHandler"): def test_tutorial_ignore_menu(device_handler: "BackgroundDeviceHandler"):
debug = device_handler.debuglink() debug = device_handler.debuglink()
btns = buttons.ScreenButtons(debug.layout_type)
device_handler.run(device.show_device_tutorial) device_handler.run(device.show_device_tutorial)
assert debug.read_layout().title() == TR.tutorial__welcome_safe5 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 assert debug.read_layout().title() == TR.tutorial__title_lets_begin
debug.swipe_up() debug.swipe_up()
assert debug.read_layout().title() == TR.tutorial__title_easy_navigation 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 assert debug.read_layout().title() == TR.tutorial__title_handy_menu
debug.swipe_up() debug.swipe_up()
assert debug.read_layout().title() == TR.tutorial__title_hold 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 assert debug.read_layout().title() == TR.tutorial__title_well_done
debug.swipe_up() debug.swipe_up()
@ -56,24 +57,25 @@ def test_tutorial_ignore_menu(device_handler: "BackgroundDeviceHandler"):
def test_tutorial_menu_open_close(device_handler: "BackgroundDeviceHandler"): def test_tutorial_menu_open_close(device_handler: "BackgroundDeviceHandler"):
debug = device_handler.debuglink() debug = device_handler.debuglink()
btns = buttons.ScreenButtons(debug.layout_type)
device_handler.run(device.show_device_tutorial) device_handler.run(device.show_device_tutorial)
assert debug.read_layout().title() == TR.tutorial__welcome_safe5 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 assert debug.read_layout().title() == TR.tutorial__title_lets_begin
debug.swipe_up() debug.swipe_up()
assert debug.read_layout().title() == TR.tutorial__title_easy_navigation assert debug.read_layout().title() == TR.tutorial__title_easy_navigation
debug.swipe_up() debug.swipe_up()
assert debug.read_layout().title() == TR.tutorial__title_handy_menu 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() 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 assert debug.read_layout().title() == TR.tutorial__title_handy_menu
debug.swipe_up() debug.swipe_up()
assert debug.read_layout().title() == TR.tutorial__title_hold 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 assert debug.read_layout().title() == TR.tutorial__title_well_done
debug.swipe_up() debug.swipe_up()
@ -82,21 +84,22 @@ def test_tutorial_menu_open_close(device_handler: "BackgroundDeviceHandler"):
def test_tutorial_menu_exit(device_handler: "BackgroundDeviceHandler"): def test_tutorial_menu_exit(device_handler: "BackgroundDeviceHandler"):
debug = device_handler.debuglink() debug = device_handler.debuglink()
btns = buttons.ScreenButtons(debug.layout_type)
device_handler.run(device.show_device_tutorial) device_handler.run(device.show_device_tutorial)
assert debug.read_layout().title() == TR.tutorial__welcome_safe5 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 assert debug.read_layout().title() == TR.tutorial__title_lets_begin
debug.swipe_up() debug.swipe_up()
assert debug.read_layout().title() == TR.tutorial__title_easy_navigation assert debug.read_layout().title() == TR.tutorial__title_easy_navigation
debug.swipe_up() debug.swipe_up()
assert debug.read_layout().title() == TR.tutorial__title_handy_menu 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() 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() 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 assert debug.read_layout().title() == TR.tutorial__title_well_done
debug.swipe_up() debug.swipe_up()
@ -105,19 +108,20 @@ def test_tutorial_menu_exit(device_handler: "BackgroundDeviceHandler"):
def test_tutorial_menu_repeat(device_handler: "BackgroundDeviceHandler"): def test_tutorial_menu_repeat(device_handler: "BackgroundDeviceHandler"):
debug = device_handler.debuglink() debug = device_handler.debuglink()
btns = buttons.ScreenButtons(debug.layout_type)
device_handler.run(device.show_device_tutorial) device_handler.run(device.show_device_tutorial)
assert debug.read_layout().title() == TR.tutorial__welcome_safe5 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 assert debug.read_layout().title() == TR.tutorial__title_lets_begin
debug.swipe_up() debug.swipe_up()
assert debug.read_layout().title() == TR.tutorial__title_easy_navigation assert debug.read_layout().title() == TR.tutorial__title_easy_navigation
debug.swipe_up() debug.swipe_up()
assert debug.read_layout().title() == TR.tutorial__title_handy_menu 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() 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 assert debug.read_layout().title() == TR.tutorial__title_lets_begin
debug.swipe_up() 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 assert debug.read_layout().title() == TR.tutorial__title_handy_menu
debug.swipe_up() debug.swipe_up()
assert debug.read_layout().title() == TR.tutorial__title_hold 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 assert debug.read_layout().title() == TR.tutorial__title_well_done
debug.swipe_up() debug.swipe_up()
@ -135,31 +139,32 @@ def test_tutorial_menu_repeat(device_handler: "BackgroundDeviceHandler"):
def test_tutorial_menu_funfact(device_handler: "BackgroundDeviceHandler"): def test_tutorial_menu_funfact(device_handler: "BackgroundDeviceHandler"):
debug = device_handler.debuglink() debug = device_handler.debuglink()
btns = buttons.ScreenButtons(debug.layout_type)
device_handler.run(device.show_device_tutorial) device_handler.run(device.show_device_tutorial)
assert debug.read_layout().title() == TR.tutorial__welcome_safe5 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 assert debug.read_layout().title() == TR.tutorial__title_lets_begin
debug.swipe_up() debug.swipe_up()
assert debug.read_layout().title() == TR.tutorial__title_easy_navigation assert debug.read_layout().title() == TR.tutorial__title_easy_navigation
debug.swipe_up() debug.swipe_up()
assert debug.read_layout().title() == TR.tutorial__title_handy_menu 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() 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( assert debug.read_layout().text_content() in TR.tutorial__first_wallet.replace(
"\n", " " "\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() 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 assert debug.read_layout().title() == TR.tutorial__title_handy_menu
debug.swipe_up() debug.swipe_up()
assert debug.read_layout().title() == TR.tutorial__title_hold 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 assert debug.read_layout().title() == TR.tutorial__title_well_done
debug.swipe_up() debug.swipe_up()

View File

@ -323,12 +323,13 @@ def click_info_button_bolt(debug: "DebugLink") -> Generator[Any, Any, ButtonRequ
def click_info_button_delizia(debug: "DebugLink"): def click_info_button_delizia(debug: "DebugLink"):
"""Click Shamir backup info button and return back.""" """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() layout = debug.read_layout()
assert "VerticalMenu" in layout.all_components() assert "VerticalMenu" in layout.all_components()
debug.click(buttons.vertical_menu(debug.layout_type)[0]) debug.click(btns.vertical_menu_items()[0])
debug.click(buttons.corner_button(debug.layout_type)) debug.click(btns.menu())
debug.click(buttons.corner_button(debug.layout_type)) debug.click(btns.menu())
def check_pin_backoff_time(attempts: int, start: float) -> None: def check_pin_backoff_time(attempts: int, start: float) -> None:

View File

@ -41,9 +41,10 @@ def show_details_input_flow(client: Client):
# Caesar - right button for "Show all" # Caesar - right button for "Show all"
client.debug.press_yes() client.debug.press_yes()
elif client.layout_type is LayoutType.Delizia: elif client.layout_type is LayoutType.Delizia:
btns = buttons.ScreenButtons(client.layout_type)
# Delizia - "Show all" button from context menu # Delizia - "Show all" button from context menu
client.debug.click(buttons.corner_button(client.layout_type)) client.debug.click(btns.menu())
client.debug.click(buttons.vertical_menu(client.layout_type)[0]) client.debug.click(btns.vertical_menu_items()[0])
else: else:
raise NotImplementedError raise NotImplementedError
# reset ui flow to continue "automatically" # reset ui flow to continue "automatically"

View File

@ -187,17 +187,18 @@ def test_change_invalid_current(client: Client):
def test_pin_menu_cancel_setup(client: Client): def test_pin_menu_cancel_setup(client: Client):
def cancel_pin_setup_input_flow(): def cancel_pin_setup_input_flow():
yield yield
btns = buttons.ScreenButtons(client.layout_type)
# enter context menu # enter context menu
client.debug.click(buttons.corner_button(client.layout_type)) client.debug.click(btns.menu())
client.debug.synchronize_at("VerticalMenu") client.debug.synchronize_at("VerticalMenu")
# click "Cancel PIN setup" # 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") client.debug.synchronize_at("Paragraphs")
# swipe through info screen # swipe through info screen
client.debug.swipe_up() client.debug.swipe_up()
client.debug.synchronize_at("PromptScreen") client.debug.synchronize_at("PromptScreen")
# tap to confirm # 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): with client, pytest.raises(Cancelled):
client.set_input_flow(cancel_pin_setup_input_flow) client.set_input_flow(cancel_pin_setup_input_flow)

View File

@ -316,12 +316,13 @@ class InputFlowSignVerifyMessageLong(InputFlowBase):
layouts: list[LayoutContent] = [] layouts: list[LayoutContent] = []
br = yield # confirm address br = yield # confirm address
btns = buttons.ScreenButtons(self.client.layout_type)
self.debug.read_layout() self.debug.read_layout()
self.debug.press_yes() 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.synchronize_at("VerticalMenu")
self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) self.debug.click(btns.vertical_menu_items()[0])
br = yield br = yield
self.debug.read_layout() self.debug.read_layout()
@ -351,8 +352,9 @@ class InputFlowSignMessageInfo(InputFlowBase):
def input_flow_bolt(self) -> BRGeneratorType: def input_flow_bolt(self) -> BRGeneratorType:
yield yield
# signing address/message info # signing address/message info
self.debug.click(buttons.corner_button(self.client.layout_type)) btns = buttons.ScreenButtons(self.client.layout_type)
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
self.debug.click(btns.menu())
# signing address "x" # signing address "x"
self.debug.press_no() self.debug.press_no()
self.debug.synchronize_at("IconDialog") self.debug.synchronize_at("IconDialog")
@ -363,10 +365,11 @@ class InputFlowSignMessageInfo(InputFlowBase):
def input_flow_delizia(self) -> BRGeneratorType: def input_flow_delizia(self) -> BRGeneratorType:
yield yield
# show address/message info # show address/message info
self.debug.click(buttons.corner_button(self.client.layout_type)) btns = buttons.ScreenButtons(self.client.layout_type)
self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) self.debug.click(btns.menu())
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.vertical_menu_items()[0])
self.debug.click(buttons.vertical_menu(self.client.layout_type)[1]) self.debug.click(btns.menu())
self.debug.click(btns.vertical_menu_items()[1])
# address mismatch? yes! # address mismatch? yes!
self.debug.swipe_up() self.debug.swipe_up()
yield yield
@ -378,14 +381,15 @@ class InputFlowShowAddressQRCode(InputFlowBase):
def input_flow_bolt(self) -> BRGeneratorType: def input_flow_bolt(self) -> BRGeneratorType:
yield 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 # synchronize; TODO get rid of this once we have single-global-layout
self.debug.synchronize_at("SimplePage") self.debug.synchronize_at("SimplePage")
self.debug.swipe_left() self.debug.swipe_left()
self.debug.swipe_right() self.debug.swipe_right()
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.press_no() self.debug.press_no()
self.debug.press_no() self.debug.press_no()
self.debug.press_yes() self.debug.press_yes()
@ -413,26 +417,27 @@ class InputFlowShowAddressQRCode(InputFlowBase):
def input_flow_delizia(self) -> BRGeneratorType: def input_flow_delizia(self) -> BRGeneratorType:
yield 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 # synchronize; TODO get rid of this once we have single-global-layout
self.debug.synchronize_at("VerticalMenu") self.debug.synchronize_at("VerticalMenu")
# menu # 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") self.debug.synchronize_at("Qr")
# qr code # qr code
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
# menu # menu
self.debug.click(buttons.vertical_menu(self.client.layout_type)[1]) self.debug.click(btns.vertical_menu_items()[1])
# address details # address details
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
# menu # menu
self.debug.click(buttons.vertical_menu(self.client.layout_type)[2]) self.debug.click(btns.vertical_menu_items()[2])
# cancel # cancel
self.debug.swipe_up() self.debug.swipe_up()
# really cancel # really cancel
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
# menu # menu
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
layout = self.debug.read_layout() layout = self.debug.read_layout()
while "PromptScreen" not in layout.all_components(): while "PromptScreen" not in layout.all_components():
@ -440,7 +445,7 @@ class InputFlowShowAddressQRCode(InputFlowBase):
layout = self.debug.read_layout() layout = self.debug.read_layout()
self.debug.synchronize_at("PromptScreen") self.debug.synchronize_at("PromptScreen")
# tap to confirm # tap to confirm
self.debug.click(buttons.tap_to_confirm(self.client.layout_type)) self.debug.click(btns.tap_to_confirm())
class InputFlowShowAddressQRCodeCancel(InputFlowBase): class InputFlowShowAddressQRCodeCancel(InputFlowBase):
@ -449,12 +454,13 @@ class InputFlowShowAddressQRCodeCancel(InputFlowBase):
def input_flow_bolt(self) -> BRGeneratorType: def input_flow_bolt(self) -> BRGeneratorType:
yield 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 # synchronize; TODO get rid of this once we have single-global-layout
self.debug.synchronize_at("SimplePage") self.debug.synchronize_at("SimplePage")
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.press_no() self.debug.press_no()
self.debug.press_yes() self.debug.press_yes()
@ -475,25 +481,26 @@ class InputFlowShowAddressQRCodeCancel(InputFlowBase):
def input_flow_delizia(self) -> BRGeneratorType: def input_flow_delizia(self) -> BRGeneratorType:
yield 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 # synchronize; TODO get rid of this once we have single-global-layout
self.debug.synchronize_at("VerticalMenu") self.debug.synchronize_at("VerticalMenu")
# menu # 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") self.debug.synchronize_at("Qr")
# qr code # qr code
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
# menu # menu
self.debug.click(buttons.vertical_menu(self.client.layout_type)[1]) self.debug.click(btns.vertical_menu_items()[1])
# address details # address details
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
# menu # menu
self.debug.click(buttons.vertical_menu(self.client.layout_type)[2]) self.debug.click(btns.vertical_menu_items()[2])
# cancel # cancel
self.debug.swipe_up() self.debug.swipe_up()
self.debug.synchronize_at("PromptScreen") self.debug.synchronize_at("PromptScreen")
# really cancel # really cancel
self.debug.click(buttons.tap_to_confirm(self.client.layout_type)) self.debug.click(btns.tap_to_confirm())
class InputFlowShowMultisigXPUBs(InputFlowBase): class InputFlowShowMultisigXPUBs(InputFlowBase):
@ -513,6 +520,7 @@ class InputFlowShowMultisigXPUBs(InputFlowBase):
def input_flow_bolt(self) -> BRGeneratorType: def input_flow_bolt(self) -> BRGeneratorType:
yield # multisig address warning yield # multisig address warning
btns = buttons.ScreenButtons(self.client.layout_type)
self.debug.press_yes() self.debug.press_yes()
yield # show address yield # show address
@ -521,7 +529,7 @@ class InputFlowShowMultisigXPUBs(InputFlowBase):
assert "(MULTISIG)" in layout.title() assert "(MULTISIG)" in layout.title()
assert layout.text_content().replace(" ", "") == self.address 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() assert "Qr" in self.all_components()
self.debug.swipe_left() self.debug.swipe_left()
@ -538,7 +546,7 @@ class InputFlowShowMultisigXPUBs(InputFlowBase):
content = layout.text_content().replace(" ", "") content = layout.text_content().replace(" ", "")
assert self.xpubs[xpub_num] in content assert self.xpubs[xpub_num] in content
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
# show address # show address
self.debug.press_no() self.debug.press_no()
# address mismatch # address mismatch
@ -590,26 +598,27 @@ class InputFlowShowMultisigXPUBs(InputFlowBase):
def input_flow_delizia(self) -> BRGeneratorType: def input_flow_delizia(self) -> BRGeneratorType:
yield # multisig address warning 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.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 yield # show address
layout = self.debug.read_layout() layout = self.debug.read_layout()
assert TR.address__title_receive_address in layout.title() assert TR.address__title_receive_address in layout.title()
assert layout.text_content().replace(" ", "") == self.address 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() assert "VerticalMenu" in self.all_components()
# menu # 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") self.debug.synchronize_at("Qr")
# qr code # qr code
assert "Qr" in self.all_components() assert "Qr" in self.all_components()
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
# menu # menu
assert "VerticalMenu" in self.all_components() 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") layout = self.debug.synchronize_at("AddressDetails")
# address details # address details
assert "Multisig 2 of 3" in layout.screen_content() 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.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") self.debug.synchronize_at("VerticalMenu")
# menu # menu
self.debug.click(buttons.vertical_menu(self.client.layout_type)[2]) self.debug.click(btns.vertical_menu_items()[2])
# cancel # cancel
self.debug.swipe_up() self.debug.swipe_up()
# really cancel # really cancel
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
self.debug.synchronize_at("VerticalMenu") self.debug.synchronize_at("VerticalMenu")
# menu # menu
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
layout = self.debug.synchronize_at("Paragraphs") layout = self.debug.synchronize_at("Paragraphs")
# address # address
while "PromptScreen" not in layout.all_components(): while "PromptScreen" not in layout.all_components():
@ -647,6 +656,7 @@ class InputFlowShowXpubQRCode(InputFlowBase):
self.passphrase = passphrase self.passphrase = passphrase
def input_flow_bolt(self) -> BRGeneratorType: def input_flow_bolt(self) -> BRGeneratorType:
btns = buttons.ScreenButtons(self.client.layout_type)
if self.passphrase: if self.passphrase:
yield yield
self.debug.press_yes() self.debug.press_yes()
@ -659,14 +669,14 @@ class InputFlowShowXpubQRCode(InputFlowBase):
self.debug.press_yes() self.debug.press_yes()
br = yield 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 # synchronize; TODO get rid of this once we have single-global-layout
self.debug.synchronize_at("SimplePage") self.debug.synchronize_at("SimplePage")
self.debug.swipe_left() self.debug.swipe_left()
self.debug.swipe_right() self.debug.swipe_right()
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.press_no() self.debug.press_no()
self.debug.press_no() self.debug.press_no()
for _ in range(br.pages - 1): for _ in range(br.pages - 1):
@ -701,6 +711,7 @@ class InputFlowShowXpubQRCode(InputFlowBase):
self.debug.press_middle() self.debug.press_middle()
def input_flow_delizia(self) -> BRGeneratorType: def input_flow_delizia(self) -> BRGeneratorType:
btns = buttons.ScreenButtons(self.client.layout_type)
if self.passphrase: if self.passphrase:
yield yield
self.debug.press_yes() self.debug.press_yes()
@ -716,32 +727,32 @@ class InputFlowShowXpubQRCode(InputFlowBase):
assert layout.title() in (TR.address__public_key, "XPUB") 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() assert "VerticalMenu" in self.all_components()
# menu # 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") self.debug.synchronize_at("Qr")
# qr code # qr code
assert "Qr" in self.all_components() assert "Qr" in self.all_components()
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
# menu # menu
assert "VerticalMenu" in self.all_components() 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") layout = self.debug.synchronize_at("AddressDetails")
# address details # address details
assert TR.address_details__derivation_path in layout.screen_content() 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") layout = self.debug.synchronize_at("VerticalMenu")
# menu # menu
self.debug.click(buttons.vertical_menu(self.client.layout_type)[2]) self.debug.click(btns.vertical_menu_items()[2])
# cancel # cancel
self.debug.swipe_up() self.debug.swipe_up()
# really cancel # really cancel
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
layout = self.debug.synchronize_at("VerticalMenu") layout = self.debug.synchronize_at("VerticalMenu")
# menu # menu
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
layout = self.debug.synchronize_at("Paragraphs") layout = self.debug.synchronize_at("Paragraphs")
# address # address
while "PromptScreen" not in layout.all_components(): 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]: def sign_tx_go_to_info(client: Client) -> Generator[None, messages.ButtonRequest, str]:
btns = buttons.ScreenButtons(client.layout_type)
yield # confirm output yield # confirm output
client.debug.read_layout() client.debug.read_layout()
client.debug.press_yes() 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() layout = client.debug.read_layout()
content = layout.text_content() content = layout.text_content()
client.debug.click(buttons.corner_button(client.layout_type)) client.debug.click(btns.menu())
return content 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( def sign_tx_go_to_info_t3t1(
client: Client, multi_account: bool = False client: Client, multi_account: bool = False
) -> Generator[None, messages.ButtonRequest, str]: ) -> Generator[None, messages.ButtonRequest, str]:
btns = buttons.ScreenButtons(client.layout_type)
yield # confirm output yield # confirm output
client.debug.read_layout() client.debug.read_layout()
client.debug.swipe_up() client.debug.swipe_up()
@ -890,22 +903,22 @@ def sign_tx_go_to_info_t3t1(
yield # confirm transaction yield # confirm transaction
client.debug.read_layout() 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.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() layout = client.debug.read_layout()
content = layout.text_content() 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.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() layout = client.debug.read_layout()
content += " " + layout.text_content() content += " " + layout.text_content()
client.debug.click(buttons.corner_button(client.layout_type)) client.debug.click(btns.menu())
client.debug.click(buttons.corner_button(client.layout_type)) client.debug.click(btns.menu())
return content return content
@ -1018,11 +1031,12 @@ class InputFlowSignTxInformationCancel(InputFlowBase):
self.debug.press_left() self.debug.press_left()
def input_flow_delizia(self) -> BRGeneratorType: def input_flow_delizia(self) -> BRGeneratorType:
btns = buttons.ScreenButtons(self.client.layout_type)
yield from sign_tx_go_to_info_t3t1(self.client) yield from sign_tx_go_to_info_t3t1(self.client)
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
self.debug.click(buttons.vertical_menu(self.client.layout_type)[2]) self.debug.click(btns.vertical_menu_items()[2])
self.debug.synchronize_at("PromptScreen") 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): class InputFlowSignTxInformationReplacement(InputFlowBase):
@ -1030,6 +1044,7 @@ class InputFlowSignTxInformationReplacement(InputFlowBase):
super().__init__(client) super().__init__(client)
def input_flow_bolt(self) -> BRGeneratorType: def input_flow_bolt(self) -> BRGeneratorType:
btns = buttons.ScreenButtons(self.client.layout_type)
yield # confirm txid yield # confirm txid
self.debug.press_yes() self.debug.press_yes()
yield # confirm address yield # confirm address
@ -1043,8 +1058,8 @@ class InputFlowSignTxInformationReplacement(InputFlowBase):
self.debug.press_yes() self.debug.press_yes()
yield # transaction summary, press info yield # transaction summary, press info
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
self.debug.press_yes() self.debug.press_yes()
def input_flow_caesar(self) -> BRGeneratorType: def input_flow_caesar(self) -> BRGeneratorType:
@ -2326,17 +2341,18 @@ class InputFlowResetSkipBackup(InputFlowBase):
self.debug.press_no() self.debug.press_no()
def input_flow_delizia(self) -> BRGeneratorType: def input_flow_delizia(self) -> BRGeneratorType:
btns = buttons.ScreenButtons(self.client.layout_type)
yield from self.BAK.confirm_new_wallet() yield from self.BAK.confirm_new_wallet()
yield # Skip Backup yield # Skip Backup
assert TR.backup__new_wallet_created in self.text_content() assert TR.backup__new_wallet_created in self.text_content()
self.debug.swipe_up() self.debug.swipe_up()
yield yield
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
self.debug.synchronize_at("VerticalMenu") 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.swipe_up()
self.debug.synchronize_at("PromptScreen") 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): class InputFlowConfirmAllWarnings(InputFlowBase):
@ -2355,6 +2371,7 @@ class InputFlowConfirmAllWarnings(InputFlowBase):
return self.input_flow_bolt() return self.input_flow_bolt()
def input_flow_delizia(self) -> BRGeneratorType: def input_flow_delizia(self) -> BRGeneratorType:
btns = buttons.ScreenButtons(self.client.layout_type)
br = yield br = yield
while True: while True:
# wait for homescreen to go away # wait for homescreen to go away
@ -2372,9 +2389,9 @@ class InputFlowConfirmAllWarnings(InputFlowBase):
TR.send__cancel_sign, TR.send__cancel_sign,
) )
if any(needle.lower() in text for needle in hi_prio): 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.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(): elif "PromptScreen" in layout.all_components():
self.debug.press_yes() self.debug.press_yes()
elif "SwipeContent" in layout.all_components(): elif "SwipeContent" in layout.all_components():
@ -2398,7 +2415,8 @@ class InputFlowFidoConfirm(InputFlowBase):
yield from self.input_flow_bolt() yield from self.input_flow_bolt()
def input_flow_delizia(self) -> BRGeneratorType: def input_flow_delizia(self) -> BRGeneratorType:
btns = buttons.ScreenButtons(self.client.layout_type)
while True: while True:
yield yield
self.debug.swipe_up() self.debug.swipe_up()
self.debug.click(buttons.tap_to_confirm(self.client.layout_type)) self.debug.click(btns.tap_to_confirm())

View File

@ -143,13 +143,14 @@ class RecoveryFlow:
else: else:
self.debug.press_no() self.debug.press_no()
elif self.client.layout_type is LayoutType.Delizia: 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() 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") self.debug.synchronize_at("VerticalMenu")
if confirm: if confirm:
self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) self.debug.click(btns.vertical_menu_items()[0])
else: else:
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
else: else:
assert TR.recovery__enter_any_share in self._text_content() assert TR.recovery__enter_any_share in self._text_content()
self.debug.press_no() self.debug.press_no()
@ -175,14 +176,15 @@ class RecoveryFlow:
assert TR.regexp("recovery__x_of_y_entered_template").search( assert TR.regexp("recovery__x_of_y_entered_template").search(
self._text_content() 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.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" assert (yield).name == "abort_recovery"
self.debug.swipe_up() self.debug.swipe_up()
layout = self.debug.read_layout() layout = self.debug.read_layout()
assert layout.title() == TR.recovery__title_cancel_recovery 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: else:
assert TR.regexp("recovery__x_of_y_entered_template").search( assert TR.regexp("recovery__x_of_y_entered_template").search(
self._text_content() self._text_content()
@ -337,16 +339,17 @@ class RecoveryFlow:
self.debug.press_yes() self.debug.press_yes()
def click_info_delizia(self) -> BRGeneratorType: def click_info_delizia(self) -> BRGeneratorType:
btns = buttons.ScreenButtons(self.client.layout_type)
# Moving through the menu into the show_shares screen # 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.synchronize_at("VerticalMenu")
self.debug.click(buttons.vertical_menu(self.client.layout_type)[0]) self.debug.click(btns.vertical_menu_items()[0])
br = yield br = yield
assert br.name == "show_shares" assert br.name == "show_shares"
assert br.code == B.Other assert br.code == B.Other
# Getting back to the homepage # Getting back to the homepage
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
class EthereumFlow: class EthereumFlow:
@ -461,6 +464,7 @@ class EthereumFlow:
def _confirm_tx_delizia( def _confirm_tx_delizia(
self, cancel: bool, info: bool, go_back_from_summary: bool self, cancel: bool, info: bool, go_back_from_summary: bool
) -> BRGeneratorType: ) -> BRGeneratorType:
btns = buttons.ScreenButtons(self.client.layout_type)
assert (yield).name == "confirm_output" assert (yield).name == "confirm_output"
title = self.debug.read_layout().title() title = self.debug.read_layout().title()
assert TR.words__address in title assert TR.words__address in title
@ -481,17 +485,17 @@ class EthereumFlow:
self.debug.press_yes() self.debug.press_yes()
assert (yield).name == "confirm_ethereum_tx" assert (yield).name == "confirm_ethereum_tx"
if info: if info:
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
self.debug.synchronize_at("VerticalMenu") 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() text = self.debug.read_layout().text_content()
assert TR.ethereum__gas_limit in text assert TR.ethereum__gas_limit in text
assert TR.ethereum__gas_price in text assert TR.ethereum__gas_price in text
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
self.debug.swipe_up() self.debug.swipe_up()
self.debug.read_layout() 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" assert (yield).name == "confirm_ethereum_tx"
def confirm_tx( def confirm_tx(
@ -527,10 +531,11 @@ class EthereumFlow:
TR.ethereum__staking_claim_intro, TR.ethereum__staking_claim_intro,
) )
if self.client.layout_type is LayoutType.Bolt: if self.client.layout_type is LayoutType.Bolt:
btns = buttons.ScreenButtons(self.client.layout_type)
# confirm intro # confirm intro
if info: if info:
self.debug.click( self.debug.click(
buttons.corner_button(self.client.layout_type), btns.menu(),
) )
assert self.debug.read_layout().title() in ( assert self.debug.read_layout().title() in (
TR.ethereum__staking_stake_address, TR.ethereum__staking_stake_address,
@ -552,17 +557,18 @@ class EthereumFlow:
self.debug.press_yes() self.debug.press_yes()
elif self.client.layout_type is LayoutType.Delizia: elif self.client.layout_type is LayoutType.Delizia:
btns = buttons.ScreenButtons(self.client.layout_type)
# confirm intro # confirm intro
if info: if info:
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
self.debug.synchronize_at("VerticalMenu") 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 ( assert self.debug.read_layout().title() in (
TR.ethereum__staking_stake_address, TR.ethereum__staking_stake_address,
TR.ethereum__staking_claim_address, TR.ethereum__staking_claim_address,
) )
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
self.debug.swipe_up() self.debug.swipe_up()
br = yield br = yield
@ -571,13 +577,13 @@ class EthereumFlow:
# confirm summary # confirm summary
if info: if info:
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
self.debug.synchronize_at("VerticalMenu") 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_limit in self.debug.read_layout().text_content()
assert TR.ethereum__gas_price 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(btns.menu())
self.debug.click(buttons.corner_button(self.client.layout_type)) self.debug.click(btns.menu())
self.debug.swipe_up() self.debug.swipe_up()
# br = yield # FIXME: no BR on sign transaction # br = yield # FIXME: no BR on sign transaction

View File

@ -10,48 +10,45 @@ def _enter_word(
debug: "DebugLink", word: str, is_slip39: bool = False debug: "DebugLink", word: str, is_slip39: bool = False
) -> "LayoutContent": ) -> "LayoutContent":
typed_word = word[:4] 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.click(coords)
debug.read_layout(wait=False) debug.read_layout(wait=False)
debug.click(buttons.input(debug.layout_type)) debug.click(btns.mnemonic_confirm())
return debug.read_layout(wait=True) return debug.read_layout(wait=True)
def confirm_recovery(debug: "DebugLink") -> None: 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) debug.read_layout(wait=True)
def select_number_of_words( def select_number_of_words(
debug: "DebugLink", tag_version: tuple | None, num_of_words: int = 20 debug: "DebugLink", tag_version: tuple | None, num_of_words: int = 20
) -> None: ) -> None:
btns = buttons.ScreenButtons(debug.layout_type)
if "SelectWordCount" not in debug.read_layout().all_components(): 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) debug.read_layout(wait=True)
if tag_version is None or tag_version > (2, 8, 8): if tag_version is None or tag_version > (2, 8, 8):
# layout changed after adding the cancel button # layout changed after adding the cancel button
coords_map = { coords = btns.word_count_all_word(num_of_words)
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)
else: else:
word_option_offset = 6 word_option_offset = 6
word_options = (12, 18, 20, 24, 33) word_options = (12, 18, 20, 24, 33)
index = word_option_offset + word_options.index( index = word_option_offset + word_options.index(
num_of_words num_of_words
) # raises if num of words is invalid ) # 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.click(coords)
debug.read_layout(wait=True) debug.read_layout(wait=True)
def enter_share(debug: "DebugLink", share: str) -> "LayoutContent": 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(" "): for word in share.split(" "):
_enter_word(debug, word, is_slip39=True) _enter_word(debug, word, is_slip39=True)