Как создать объектную модель страницы/экрана в Jetpack Compose Testing

Для базового тестирования, если я создам тестовый класс, как показано ниже, он отлично работает.

      class MyComposeTest {

    @get:Rule
    val composeTestRule = createAndroidComposeRule<MainActivity>()

    @Test
    fun myTest() {

        composeTestRule.onNodeWithText("Login").performClick()

        composeTestRule.onNodeWithText("Home").assertIsDisplayed()
    }
}

Но что, если я хочу абстрагировать некоторые из них в отдельные классы для сквозного теста?

например, я хочу создать класс страницы входа со всеми локаторами для входа и аналогично для домашней страницы и упростить мой тест как

      @Test
fun myTest() {
   val login = LoginPage() 
   val home = HomePage()

   login.loginBtn.performClick() 
   home.homeTxt.assertIsDisplayed()
}

Я не уверен, как должны выглядеть мои классы страниц (с локаторами), чтобы это стало возможным.

2 ответа

Вы должны передать composeTestRule в конструкторе страницы. Код будет выглядеть так:

      class BaseTestSuite {
    @get:Rule
    val composeTestRule = createAndroidComposeRule<MainActivity>()
}
      class LoginPage(composeTestRule: ComposeContentTestRule) {
    val loginBtn = onNodeWithText("Login")

    fun tapLoginButton() {
        loginBtn.performClick() 
    }
}
      class MyTestSuite() : BaseTestSuite {
    val loginPage = LoginPage(composeTestRule) 

    @Test
    fun myTest() {
        loginPage.tapLoginButton()
    
        // rest of the code
    
    }
}

Вкратце, давайте посмотрим, как выглядит Kakao Compose DSL:

      // Screen class
class ComposeMainScreen(semanticsProvider: SemanticsNodeInteractionsProvider) :
      ComposeScreen<ComposeMainScreen>(
          semanticsProvider = semanticsProvider,
          // Screen in Kakao Compose can be a Node too due to 'viewBuilderAction' param.
          // 'viewBuilderAction' param is nullable.
          viewBuilderAction = { hasTestTag("ComposeMainScreen") }
 ) {
    
    // You can set clear parent-child relationship due to 'child' extension
     // Here, 'simpleFlakyButton' is a child of 'ComposeMainScreen' (that is Node too)
     val simpleFlakyButton: KNode = child {
         hasTestTag("main_screen_simple_flaky_button")
     }
}
    
// This annotation is here to make the test is appropriate for JVM environment (with Robolectric)
@RunWith(AndroidJUnit4::class)
    // Test class declaration
class ComposeSimpleFlakyTest : TestCase(
      kaspressoBuilder = Kaspresso.Builder.withComposeSupport()
) {
    
      // Special rule for Compose tests
      @get:Rule
      val composeTestRule = createAndroidComposeRule<JetpackComposeActivity>()
    
        // Test DSL. It's so similar to Kakao or Kautomator DSL
      @Test
      fun test() = run {
          step("Open Flaky screen") {
              onComposeScreen<ComposeMainScreen>(composeTestRule) {
                  simpleFlakyButton {
                      assertIsDisplayed()
                      performClick()
                  }
              }
          }
    
          step("Click on the First button") {
              onComposeScreen<ComposeSimpleFlakyScreen>(composeTestRule) {
                  firstButton {
                        assertIsDisplayed()
                      performClick()
                  }
              }
          }
    
            // ...
      }
}

Он работает так же, как шаблон Page Object с использованием Espresso. Узнать больше