אוטומציה של בדיקות הניווט באמצעות מקשי החיצים מבטיחה שהאפליקציה תספק חוויית משתמש עקבית וצפויה במקלדות חומרה, במקשי החיצים ובכלי נגישות. 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 באמצעות 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 מושבת
- יעדי התמקדות
- סדר מעבר בין רכיבים
- התמקדות בשדות טקסט
- קיבוץ יעדים להתמקדות