Repository: android/nowinandroid
File: app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt (Kotlin)

Code before:
            onNodeWithText(interests).performClick()

            // Verify the topic is still shown
            onNodeWithTag("topic:${topic.id}").assertExists()
        }
    }

    @Test
    fun navigatingToTopicFromForYou_showsTopicDetails() {
        composeTestRule.apply {
            // Get the first news resource
            val newsResource = runBlocking {
                newsRepository.getNewsResources().first().first()
            }

            // Get its first topic and follow it
            val topic = newsResource.topics.first()
            onNodeWithText(topic.name).performClick()

            // Get the news feed and scroll to the news resource
            // Note: Possible flakiness. If the content of the news resource is long then the topic
            // tag might not be visible meaning it cannot be clicked
            onNodeWithTag("forYou:feed")
                .performScrollToNode(
                    hasTestTag("newsResourceCard:${newsResource.id}"),
                )

            // Click the first topic tag
            onAllNodesWithTag("topicTag:${topic.id}", useUnmergedTree = true)
                .onFirst()
                .performClick()

            // Verify that we're on the correct topic details screen
            onNodeWithTag("topic:${topic.id}").assertExists()
        }
    }
}


Review comment (suggestion):
Slightly terrible workaround for the scrolling issue: once we scroll such that the correct card is aligned with the top of the viewport, if we scroll an additional amount based on the height of the card so that the bottom of the card is within the viewport, the topic tags should be visible:

```suggestion
                .fetchSemanticsNode()
                .apply {
                    val newsResourceCardNode = onNodeWithTag("newsResourceCard:${newsResource.id}")
                        .fetchSemanticsNode()
                    config[ScrollBy].action?.invoke(
                        0f,
                        // to ensure the bottom of the card is visible,
                        // manually scroll the difference between the height of
                        // the scrolling node and the height of the card
                        (newsResourceCardNode.size.height - size.height).coerceAtLeast(0).toFloat()
                    )
                }
```

Code after:
            // Come back to Interests
            onNodeWithText(interests).performClick()

            // Verify the topic is still shown
            onNodeWithTag("topic:${topic.id}").assertExists()
        }
    }

    @Test
    fun navigatingToTopicFromForYou_showsTopicDetails() {
        composeTestRule.apply {
            // Get the first news resource
            val newsResource = runBlocking {
                newsRepository.getNewsResources().first().first()
            }

            // Get its first topic and follow it
            val topic = newsResource.topics.first()
            onNodeWithText(topic.name).performClick()

            // Get the news feed and scroll to the news resource
            // Note: Possible flakiness. If the content of the news resource is long then the topic
            // tag might not be visible meaning it cannot be clicked
            onNodeWithTag("forYou:feed")
                .performScrollToNode(hasTestTag("newsResourceCard:${newsResource.id}"))
                .fetchSemanticsNode()
                .apply {
                    val newsResourceCardNode = onNodeWithTag("newsResourceCard:${newsResource.id}")
                        .fetchSemanticsNode()
                    config[ScrollBy].action?.invoke(
                        0f,
                        // to ensure the bottom of the card is visible,
                        // manually scroll the difference between the height of
                        // the scrolling node and the height of the card
                        (newsResourceCardNode.size.height - size.height).coerceAtLeast(0).toFloat(),
                    )
                }

            // Click the first topic tag
            onAllNodesWithTag("topicTag:${topic.id}", useUnmergedTree = true)
                .onFirst()
                .performClick()

            // Verify that we're on the correct topic details screen
            onNodeWithTag("topic:${topic.id}").assertExists()
        }
    }
}