Việc tự động hoá các kiểm thử điều hướng tiêu điểm đảm bảo ứng dụng của bạn mang lại trải nghiệm người dùng nhất quán và dễ đoán trên bàn phím phần cứng, D-pad và các công cụ hỗ trợ tiếp cận. Compose cung cấp các API kiểm thử tích hợp để mô phỏng thao tác nhập bằng phím và xác minh trạng thái tiêu điểm.
Thiết lập kiểm thử trọng tâm
Để viết các bài kiểm thử tiêu điểm, hãy sử dụng createComposeRule() trong thư viện kiểm thử Compose:
@RunWith(AndroidJUnit4::class) class FocusNavigationTest { @get:Rule val composeTestRule = createComposeRule()
Xác minh mục tiêu lấy tiêu điểm
Bạn có thể xác minh xem một phần tử trên giao diện người dùng có thể nhận tiêu điểm hay không bằng cách thực hiện một thao tác nhấp hoặc yêu cầu tiêu điểm, rồi xác nhận trạng thái của phần tử đó bằng cách sử dụng assertIsFocused() và 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() }
Kiểm thử thao tác duyệt qua tiêu điểm theo một chiều
Mô phỏng các lần nhấn phím Tab và Shift+Tab bằng cách sử dụng performKeyInput để xác minh rằng tiêu điểm chuyển qua giao diện người dùng theo thứ tự xuất hiện. Theo phương pháp hay nhất, hãy xác minh cả thao tác điều hướng tiến (Key.Tab) và điều hướng ngược (Key.Tab khi giữ Key.ShiftLeft) để đảm bảo tính toàn vẹn của thao tác di chuyển hai chiều:
@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() }
Kiểm thử quá trình duyệt qua theo hướng hai chiều
Mô phỏng các phím mũi tên hoặc phím định hướng trên D-pad bằng cách dùng Key.DirectionDown, Key.DirectionUp, Key.DirectionRight và 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() }
Kiểm thử hành vi tiêu điểm của trường văn bản
Xác minh rằng các trường văn bản một dòng sẽ chuyển tiêu điểm khi nhấn phím Tab, trong khi các trường văn bản nhiều dòng sẽ giữ tiêu điểm:
@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() }
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Mục tiêu lấy tiêu điểm
- Thứ tự duyệt qua tiêu điểm
- Tiêu điểm trong trường văn bản
- Nhóm mục tiêu lấy tiêu điểm