การทดสอบการนำทางด้วยโฟกัสโดยอัตโนมัติจะช่วยให้มั่นใจได้ว่าแอปของคุณจะมอบประสบการณ์การใช้งานที่สอดคล้องกันและคาดเดาได้แก่ผู้ใช้ในคีย์บอร์ดฮาร์ดแวร์, D-pad และเครื่องมือเพื่อการช่วยเหลือพิเศษ Compose มี API การทดสอบในตัวเพื่อจำลองอินพุตคีย์ และยืนยันสถานะโฟกัส
ตั้งค่าการทดสอบโฟกัส
หากต้องการเขียนการทดสอบโฟกัส ให้ใช้ createComposeRule() จากไลบรารีการทดสอบ Compose
@RunWith(AndroidJUnit4::class) class FocusNavigationTest { @get:Rule val composeTestRule = createComposeRule()
ยืนยันเป้าหมายโฟกัส
คุณสามารถยืนยันว่าองค์ประกอบ UI รับโฟกัสได้หรือไม่โดยคลิกหรือ
ขอโฟกัส แล้วยืนยันสถานะโดยใช้ 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 เพื่อยืนยันว่าโฟกัสเลื่อนผ่าน UI
ตามลำดับที่ปรากฏ แนวทางปฏิบัติแนะนำ
คือให้ยืนยันทั้งการไปยังส่วนต่างๆ ไปข้างหน้า (Key.Tab) และการไปยังส่วนต่างๆ ย้อนกลับ
(Key.Tab โดยกด Key.ShiftLeft ค้างไว้) เพื่อให้มั่นใจว่าการข้ามแบบ 2 ทาง
จะสมบูรณ์
@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() }
ทดสอบการเคลื่อนที่แบบ 2 มิติ
จำลองปุ่มลูกศรหรือปุ่มทิศทางของ D-pad โดยใช้ 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() }
ทดสอบลักษณะการทำงานของโฟกัสช่องข้อความ
ตรวจสอบว่าช่องข้อความบรรทัดเดียวจะเลื่อนโฟกัสเมื่อกดแท็บ ส่วนช่องข้อความหลายบรรทัด จะคงโฟกัสไว้
@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 ปิดอยู่
- เป้าหมายโฟกัส
- ลำดับการส่งผ่านโฟกัส
- โฟกัสในช่องข้อความ
- โฟกัสเป้าหมายกลุ่ม