Automatizar las pruebas de navegación con enfoque garantiza que tu app ofrezca una experiencia del usuario coherente y predecible en teclados físicos, pads direccionales y herramientas de accesibilidad. Compose proporciona APIs de prueba integradas para simular la entrada de teclas y verificar los estados de enfoque.
Configura pruebas de enfoque
Para escribir pruebas de enfoque, usa createComposeRule() de la biblioteca de pruebas de Compose:
@RunWith(AndroidJUnit4::class) class FocusNavigationTest { @get:Rule val composeTestRule = createComposeRule()
Verifica los objetivos de enfoque
Para verificar si un elemento de la IU puede recibir el enfoque, haz clic en él o solicítalo y, luego, confirma su estado con assertIsFocused() y 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() }
Prueba el recorrido del enfoque unidimensional
Simula las pulsaciones de las teclas Tab y Mayúsculas + Tab con performKeyInput para verificar que el enfoque avance por la IU en orden de aparición. Como práctica recomendada,
verifica la navegación hacia adelante (Key.Tab) y hacia atrás
(Key.Tab con Key.ShiftLeft presionado) para garantizar la integridad del recorrido
en ambos sentidos:
@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() }
Prueba el recorrido direccional bidimensional
Simula las teclas de flecha o las teclas de dirección del pad direccional con Key.DirectionDown, Key.DirectionUp, Key.DirectionRight y 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() }
Prueba el comportamiento del enfoque del campo de texto
Verifica que los campos de texto de una sola línea avancen el enfoque con Tab, mientras que los campos de texto de varias líneas lo retengan:
@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() }
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Objetivos de enfoque
- Orden de recorrido del enfoque
- Cómo enfocar los campos de texto
- Agrupa los destinos de enfoque