LoginSignup
9
4

Jetpack Composeのテストで出てくるmerged tree、unmerged treeとは何か

Posted at

かなり基本的なことなんですが、よく分かっていない方も多いのではと思い書いています。
Jetpack Composeで開発していて以下のようなエラーに遭遇しました。

Composeのコード

NavigationBarItem(
    selected = selected,
    onClick = {
        ...
    },
    icon = {
        Icon(
            imageVector = tab.icon,
            contentDescription = "Hoge",
        )
    },
)

テスト

composeTestRule
  .onNodeWithContentDescription("Hoge")
  .performClick()

エラー

java.lang.AssertionError: Failed to inject touch input.
Reason: Expected exactly '1' node but could not find any node that satisfies: (ContentDescription = 'Hoge' (ignoreCase: false))
However, the unmerged tree contains '1' node that matches. Are you missing `useUnmergedNode = true` in your finder?

訳: Hoge = ContentDescriptionを持つノードが見つからなかったよ。
でも、unmerged treeには見つかったから、useUnmergedNode = true 忘れていませんか?

さてさて、useUnmergedNode = trueにしたらいいのかな?

ドキュメントを見る

Using the unmerged tree というドキュメントが普通に分かりやすいです。

ボタンとかいくつかのコンポーネントは子のコンポーネントをテストからデフォルトで見える木では勝手にマージしちゃうようです。

MyButton {
    Text("Hello")
    Text("World")
}

が以下のようになります。

Node #1 at (...)px
 |-Node #2 at (...)px
   Role = 'Button'
   // **2つあったテキストが一個になってまとまっている**
   Text = '[Hello, World]'
   Actions = [OnClick, GetTextLayoutResult]
   MergeDescendants = 'true'

useUnmergedNode = trueを使うと以下のようになります。 (ドキュメントに書いてあるとおりですが。)

Node #1 at (...)px
 |-Node #2 at (...)px
   OnClick = '...'
   // ここにMergeDescendants = 'true'がある
   MergeDescendants = 'true'
    |-Node #3 at (...)px
    // ちゃんとTextが分かれている
    | Text = '[Hello]'
    |-Node #5 at (83.0, 86.0, 191.0, 135.0)px
      Text = '[World]'

useUnmergedNode = trueを使うとwithTextなどで"Hello"などが探せる。というわけです。

なぜこのまとめる現象が起こるのか

Modifierに.semantics()という関数が生えています。これに引数をsemantics(mergeDescendants = true)のように渡すことで子孫がテストでマージされます。
これをButtonの中で使っています。
正確にはButtonの中でModifier.clickable()を使っていて、これを使うと this.semantics(mergeDescendants = true)が使われます。

つまりクリックできる要素があるとだいたいmergeDescendants = trueされて、その子孫がまとめられる。 ということなので、テストを書くときに意識したほうが良さそうです。

で、結論としてuseUnmergedNode = true使う?

多分今回に関してはuseUnmergedNode = trueにしてクリックするのでも動くんですが、クリックする要素などにTestTagなどをつけて、それをテストで使うほうがクリックしたいものとテストを関連付けする意図では良さそうに見えました。

参考

9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4