L'automazione dei test di navigazione dello stato attivo garantisce che la tua app offra un'esperienza utente coerente e prevedibile su tastiere hardware, D-pad e strumenti di accessibilità. Compose fornisce API di test integrate per simulare l'input da tastiera e verificare gli stati di attivazione.
Configura i test mirati
Per scrivere test di stato attivo, utilizza createComposeRule() della libreria di test di Compose:
@RunWith(AndroidJUnit4::class) class FocusNavigationTest { @get:Rule val composeTestRule = createComposeRule()
Verifica i target di messa a fuoco
Puoi verificare se un elemento UI può ricevere lo stato attivo eseguendo un clic o richiedendo lo stato attivo, quindi confermando il suo stato utilizzando assertIsFocused() e 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() }
Testa l'attraversamento del focus monodimensionale
Simula la pressione dei tasti Tab e Maiusc+Tab utilizzando performKeyInput per verificare che lo stato attivo avanzi nell'interfaccia utente in ordine di visualizzazione. Come best practice, verifica sia la navigazione in avanti (Key.Tab) sia quella indietro (Key.Tab con Key.ShiftLeft premuto) per garantire l'integrità dell'attraversamento bidirezionale:
@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() }
Testa l'esplorazione direzionale bidimensionale
Simula i tasti Freccia o i tasti direzionali del D-pad utilizzando Key.DirectionDown,
Key.DirectionUp, Key.DirectionRight e 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() }
Testa il comportamento dello stato attivo del campo di testo
Verifica che i campi di testo a riga singola spostino lo stato attivo su Tab, mentre i campi di testo multilinea mantengono lo stato attivo:
@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() }
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Target di messa a fuoco
- Ordine di spostamento dello stato attivo
- Spostamento dello stato attivo nei campi di testo
- Target di interesse del gruppo