L'automatisation des tests de navigation par sélection garantit que votre application offre une expérience utilisateur cohérente et prévisible sur les claviers physiques, les pavés directionnels et les outils d'accessibilité. Compose fournit des API de test intégrées pour simuler la saisie de touches et vérifier les états de sélection.
Configurer des tests de focus
Pour écrire des tests de sélection, utilisez createComposeRule() de la bibliothèque de test Compose :
@RunWith(AndroidJUnit4::class) class FocusNavigationTest { @get:Rule val composeTestRule = createComposeRule()
Vérifier les cibles de sélection
Vous pouvez vérifier si un élément d'interface utilisateur peut recevoir le focus en effectuant un clic ou en demandant le focus, puis en confirmant son état à l'aide de assertIsFocused() et 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() }
Tester le balayage du curseur unidimensionnel
Simulez les pressions sur les touches Tabulation et Maj+Tabulation à l'aide de performKeyInput pour vérifier que la sélection avance dans l'UI dans l'ordre d'apparition. Nous vous recommandons de vérifier la navigation vers l'avant (Key.Tab) et vers l'arrière (Key.Tab en maintenant la touche Key.ShiftLeft enfoncée) pour vous assurer de l'intégrité de la navigation bidirectionnelle :
@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() }
Tester le parcours directionnel bidimensionnel
Simulez les touches fléchées ou les touches directionnelles du pavé directionnel à l'aide de Key.DirectionDown, Key.DirectionUp, Key.DirectionRight et 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() }
Tester le comportement de sélection du champ de texte
Vérifiez que les champs de texte d'une seule ligne déplacent le curseur lorsque vous appuyez sur Tabulation, tandis que les champs de texte multilignes conservent le curseur :
@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() }
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Cibles de sélection
- Ordre de balayage du focus
- Focus dans les champs de texte
- Grouper les cibles de focus