Автоматизация тестов навигации по фокусу гарантирует, что ваше приложение обеспечивает единообразный и предсказуемый пользовательский интерфейс для аппаратных клавиатур, D-pad и инструментов специальных возможностей. Compose предоставляет встроенные API-интерфейсы тестирования для имитации ввода с клавиатуры и проверки состояний фокуса.
Как настроить фокус-тестирование
Чтобы написать тесты фокуса, используйте createComposeRule() из библиотеки тестирования Compose:
@RunWith(AndroidJUnit4::class) class FocusNavigationTest { @get:Rule val composeTestRule = createComposeRule()
Проверьте цели фокусировки
Чтобы проверить, может ли элемент интерфейса получить фокус, нажмите на него или запросите фокус, а затем подтвердите его состояние с помощью assertIsFocused() и assertIsNotFocused().
@Test fun interactiveElement_isFocusTarget() { composeTestRule.setContent { AppTheme { CardListScreen() } } val firstCard = composeTestRule.onNodeWithTag("card_1") val secondCard = composeTestRule.onNodeWithTag("card_2") // Focus the first element firstCard.performClick() firstCard.assertIsFocused() secondCard.assertIsNotFocused() }
Протестируйте одномерный переход фокуса
Имитируйте нажатие клавиш Tab и Shift + Tab с помощью performKeyInput, чтобы убедиться, что фокус перемещается по интерфейсу в порядке появления элементов. Рекомендуем проверить навигацию как вперед (Key.Tab), так и назад (Key.Tab с зажатой клавишей Key.ShiftLeft), чтобы убедиться, что она работает в обоих направлениях.
@Test fun tabKey_navigatesInAppearanceOrder() { composeTestRule.setContent { AppTheme { CardListScreen() } } val firstCard = composeTestRule.onNodeWithTag("card_1") val secondCard = composeTestRule.onNodeWithTag("card_2") val thirdCard = composeTestRule.onNodeWithTag("card_3") firstCard.performClick() firstCard.assertIsFocused() // Press Tab -> Moves to second card firstCard.performKeyInput { pressKey(Key.Tab) } secondCard.assertIsFocused() firstCard.assertIsNotFocused() // Press Tab -> Moves to third card secondCard.performKeyInput { pressKey(Key.Tab) } thirdCard.assertIsFocused() // Press Shift + Tab -> Moves backward to second card thirdCard.performKeyInput { withKeyDown(Key.ShiftLeft) { pressKey(Key.Tab) } } secondCard.assertIsFocused() }
Протестируйте двумерную направленную навигацию
Имитируйте клавиши со стрелками или клавиши направления на d-pad с помощью Key.DirectionDown, Key.DirectionUp, Key.DirectionRight и Key.DirectionLeft.
@Test fun arrowKeys_moveFocusTwoDimensionallyWithoutWrap() { composeTestRule.setContent { AppTheme { GridLayoutScreen() } } val topLeftButton = composeTestRule.onNodeWithTag("btn_top_left") val bottomLeftButton = composeTestRule.onNodeWithTag("btn_bottom_left") topLeftButton.performClick() topLeftButton.assertIsFocused() // Down arrow moves focus downward to bottom-left button topLeftButton.performKeyInput { pressKey(Key.DirectionDown) } bottomLeftButton.assertIsFocused() // Directional keys do not wrap around: pressing Down on bottom element stays focused bottomLeftButton.performKeyInput { pressKey(Key.DirectionDown) } bottomLeftButton.assertIsFocused() }
Проверьте, как работает фокус в текстовом поле
Убедитесь, что при нажатии клавиши Tab фокус перемещается с однострочных текстовых полей, но остается на многострочных.
@Test fun textField_handlesTabAccordingToLineLimits() { composeTestRule.setContent { AppTheme { FormScreen() } } val singleLineNode = composeTestRule.onNodeWithTag("single_line_field") val multiLineNode = composeTestRule.onNodeWithTag("multi_line_field") val submitButtonNode = composeTestRule.onNodeWithTag("submit_button") // Single-line field advances focus on Tab singleLineNode.performClick() singleLineNode.assertIsFocused() singleLineNode.performKeyInput { pressKey(Key.Tab) } multiLineNode.assertIsFocused() // Multi-line field keeps focus and inserts '\t' multiLineNode.performKeyInput { pressKey(Key.Tab) } multiLineNode.assertIsFocused() submitButtonNode.assertIsNotFocused() // Shift + Tab escapes multi-line field to previous target multiLineNode.performKeyInput { withKeyDown(Key.ShiftLeft) { pressKey(Key.Tab) } } singleLineNode.assertIsFocused() }
Рекомендуем
- Примечание. Текст ссылки показывается, когда JavaScript отключен.
- Цели фокусировки
- Порядок обхода фокуса
- Как перейти к текстовому полю
- Цели по группам