From e631ac904e4ff86d75912ddac97d2e4fdaa34a0a Mon Sep 17 00:00:00 2001 From: takahirom Date: Tue, 25 Jun 2024 11:51:50 +0900 Subject: [PATCH 1/8] Add describe based Robolectric test --- ...RobolectricDescribeSpecParameterBuilder.kt | 150 ++++++++++++++++ .../confsched/sessions/TimetableScreenTest.kt | 160 +++++++----------- 2 files changed, 214 insertions(+), 96 deletions(-) create mode 100644 core/testing/src/main/java/io/github/droidkaigi/confsched/testing/RobolectricDescribeSpecParameterBuilder.kt diff --git a/core/testing/src/main/java/io/github/droidkaigi/confsched/testing/RobolectricDescribeSpecParameterBuilder.kt b/core/testing/src/main/java/io/github/droidkaigi/confsched/testing/RobolectricDescribeSpecParameterBuilder.kt new file mode 100644 index 000000000..a089b3645 --- /dev/null +++ b/core/testing/src/main/java/io/github/droidkaigi/confsched/testing/RobolectricDescribeSpecParameterBuilder.kt @@ -0,0 +1,150 @@ +package io.github.droidkaigi.confsched.testing + +inline fun describeTests(block: TestCaseTreeBuilder.() -> Unit): List> { + val builder = TestCaseTreeBuilder() + builder.block() + val root = builder.build() + return generateTestCases(root) +} + +fun DescribedTestCase.execute(robot: T) { + for ((index, step) in steps.withIndex()) { + println("Executing step: $index ($description)") + when (step) { + is TestNode.Run -> step.action(robot) + is TestNode.Check -> { + if (step.description == targetCheckDescription) { + step.action(robot) + } + } + + is TestNode.Describe -> {} + } + println("Step executed: $index") + } +} + +sealed class TestNode { + data class Describe(val description: String, val children: List>) : TestNode() + data class Run(val action: (T) -> Unit) : TestNode() + data class Check(val description: String, val action: (T) -> Unit) : TestNode() +} + +data class DescribedTestCase( + val description: String, + val steps: List>, + val targetCheckDescription: String, +) { + override fun toString(): String = description +} + +data class AncestryNode( + val node: TestNode, + val childIndex: Int, +) + +data class CheckNode( + val description: String, + val fullDescription: String, + val node: TestNode.Check, + val ancestry: List>, +) + +class TestCaseTreeBuilder { + private val children = mutableListOf>() + + fun describe(description: String, block: TestCaseTreeBuilder.() -> Unit) { + val builder = TestCaseTreeBuilder() + builder.block() + children.add(TestNode.Describe(description, builder.children)) + } + + fun run(action: (T) -> Unit) { + children.add(TestNode.Run { robot -> action(robot as T) }) + } + + fun check(description: String, action: (T) -> Unit) { + children.add(TestNode.Check(description) { robot -> action(robot as T) }) + } + + fun build(): TestNode.Describe = TestNode.Describe("", children) +} + +fun generateTestCases(root: TestNode.Describe): List> { + val checkNodes = collectCheckNodes(root) + return checkNodes.map { createTestCase(it) } +} + +/** + * Collect all check nodes from the test tree + * it will be O(N) + */ +private fun collectCheckNodes(root: TestNode.Describe): List> { + val checkNodes = mutableListOf>() + + fun traverse(node: TestNode, parentDescription: String, ancestry: List>) { + when (node) { + is TestNode.Describe -> { + val currentDescription = + if (parentDescription.isEmpty()) node.description else "$parentDescription - ${node.description}" + node.children.forEachIndexed { index, child -> + val currentAncestry = ancestry + AncestryNode(node, index) + traverse(child, currentDescription, currentAncestry) + } + } + + is TestNode.Check -> { + val fullDescription = if (parentDescription.isNotBlank()) { + "$parentDescription-${node.description}" + } else { + node.description + } + checkNodes.add(CheckNode(node.description, fullDescription, node, ancestry)) + } + + is TestNode.Run -> {} + } + } + + traverse(root, "", emptyList()) + return checkNodes +} + +/** + * Create a test case from a check node + * We only run the steps that are necessary to reach the check node + * so the time complexity might be O(logN) + */ +private fun createTestCase(checkNode: CheckNode): DescribedTestCase { + val steps = mutableListOf>() + + fun processNode(node: TestNode, ancestry: List>, depth: Int) { + when (node) { + is TestNode.Describe -> { + for (child in node.children) { + if (depth + 1 < checkNode.ancestry.size && child == checkNode.ancestry[depth + 1].node) { + processNode(child, ancestry + node, depth + 1) + } else if (child is TestNode.Run) { + steps.add(child) + } else if (child == checkNode.node) { + steps.add(child) + } + } + } + + is TestNode.Run -> { + steps.add(node) + } + + is TestNode.Check -> { + if (node == checkNode.node) { + steps.add(node) + } + } + } + } + + processNode(checkNode.ancestry.first().node, emptyList(), 0) + + return DescribedTestCase(checkNode.fullDescription, steps, checkNode.description) +} diff --git a/feature/sessions/src/androidUnitTest/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreenTest.kt b/feature/sessions/src/androidUnitTest/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreenTest.kt index ec959ebea..d88dd1685 100644 --- a/feature/sessions/src/androidUnitTest/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreenTest.kt +++ b/feature/sessions/src/androidUnitTest/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreenTest.kt @@ -1,22 +1,23 @@ package io.github.droidkaigi.confsched.sessions -import androidx.test.ext.junit.runners.AndroidJUnit4 import dagger.hilt.android.testing.BindValue import dagger.hilt.android.testing.HiltAndroidTest +import io.github.droidkaigi.confsched.testing.DescribedTestCase import io.github.droidkaigi.confsched.testing.RobotTestRule import io.github.droidkaigi.confsched.testing.TimetableServerRobot.ServerStatus +import io.github.droidkaigi.confsched.testing.describeTests +import io.github.droidkaigi.confsched.testing.execute import io.github.droidkaigi.confsched.testing.robot.TimetableScreenRobot import io.github.droidkaigi.confsched.testing.runRobot -import io.github.droidkaigi.confsched.testing.todoChecks import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import org.robolectric.annotation.Config +import org.robolectric.ParameterizedRobolectricTestRunner import javax.inject.Inject -@RunWith(AndroidJUnit4::class) +@RunWith(ParameterizedRobolectricTestRunner::class) @HiltAndroidTest -class TimetableScreenTest { +class TimetableScreenTest(private val testCase: DescribedTestCase) { @get:Rule @BindValue val robotTestRule: RobotTestRule = RobotTestRule(this) @@ -25,101 +26,68 @@ class TimetableScreenTest { lateinit var timetableScreenRobot: TimetableScreenRobot @Test - fun checkLaunchShot() { + fun runTest() { runRobot(timetableScreenRobot) { - setupTimetableScreenContent() - captureScreenWithChecks(checks = todoChecks("TODO: Please add some checks!")) + testCase.execute(timetableScreenRobot) } } - @Test - fun checkLaunchServerErrorShot() { - runRobot(timetableScreenRobot) { - setupTimetableServer(ServerStatus.Error) - setupTimetableScreenContent() - captureScreenWithChecks(checks = todoChecks("TODO: Please add some checks!")) - } - } - - @Test - fun checkLaunch() { - runRobot(timetableScreenRobot) { - setupTimetableScreenContent() - checkTimetableItemsDisplayed() - } - } - - @Test - fun checkLaunchAccessibilityShot() { - runRobot(timetableScreenRobot) { - setupTimetableScreenContent() - checkAccessibilityCapture() - } - } - - @Test - fun checkBookmarkToggleShot() { - runRobot(timetableScreenRobot) { - setupTimetableScreenContent() - clickFirstSessionBookmark() - captureScreenWithChecks() - clickFirstSessionBookmark() - captureScreenWithChecks() - } - } - - @Test - fun checkScrollShot() { - runRobot(timetableScreenRobot) { - setupTimetableScreenContent() - scrollTimetable() - captureScreenWithChecks() - } - } - - @Test - fun checkGridShot() { - runRobot(timetableScreenRobot) { - setupTimetableScreenContent() - clickTimetableUiTypeChangeButton() - captureScreenWithChecks() - } - } - - @Test - fun checkGridScrollShot() { - runRobot(timetableScreenRobot) { - setupTimetableScreenContent() - clickTimetableUiTypeChangeButton() - scrollTimetable() - captureScreenWithChecks() - } - } - - @Test - @Config(fontScale = 0.5f) - fun checkSmallFontScaleShot() { - runRobot(timetableScreenRobot) { - setupTimetableScreenContent() - captureScreenWithChecks(checks = todoChecks("TODO: Please add some checks!")) - } - } - - @Test - @Config(fontScale = 1.5f) - fun checkLargeFontScaleShot() { - runRobot(timetableScreenRobot) { - setupTimetableScreenContent() - captureScreenWithChecks(checks = todoChecks("TODO: Please add some checks!")) - } - } - - @Test - @Config(fontScale = 2.0f) - fun checkHugeFontScaleShot() { - runRobot(timetableScreenRobot) { - setupTimetableScreenContent() - captureScreenWithChecks(checks = todoChecks("TODO: Please add some checks!")) + companion object { + @JvmStatic + @ParameterizedRobolectricTestRunner.Parameters(name = "{0}") + fun tests(): List> { + return describeTests { + describe("TimetableScreenTest") { + describe("when server is operational") { + run { robot -> + robot.setupTimetableServer(ServerStatus.Operational) + robot.setupTimetableScreenContent() + } + check("should show timetable items") { robot -> + robot.captureScreenWithChecks(checks = { + robot.checkTimetableItemsDisplayed() + }) + } + describe("click first session bookmark") { + run { robot -> + robot.clickFirstSessionBookmark() + } + check("should show bookmarked session") { robot -> + // FIXME: Add check for bookmarked session + robot.captureScreenWithChecks() + } + } + describe("click first session") { + run { robot -> + robot.clickFirstSession() + } + check("should show session detail") { robot -> + // FIXME: Add check for navigation to session detail + robot.captureScreenWithChecks() + } + } + describe("click timetable ui type change button") { + run { robot -> + robot.clickTimetableUiTypeChangeButton() + } + check("should change timetable ui type") { robot -> + // FIXME: Add check for timetable ui type change + robot.captureScreenWithChecks() + } + } + } + describe("when server is down") { + run { robot -> + robot.setupTimetableServer(ServerStatus.Error) + robot.setupTimetableScreenContent() + } + check("should show error message") { robot -> + // FIXME: Add check for error message + robot.captureScreenWithChecks() + } + } + } + } } } } From 3f39e361e54134ec7504756e9aff9d02d8778002 Mon Sep 17 00:00:00 2001 From: takahirom Date: Wed, 26 Jun 2024 10:00:40 +0900 Subject: [PATCH 2/8] Fix action --- .github/workflows/screenshot-comparison-comment.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/screenshot-comparison-comment.yml b/.github/workflows/screenshot-comparison-comment.yml index 78f1c9602..48cb313c6 100644 --- a/.github/workflows/screenshot-comparison-comment.yml +++ b/.github/workflows/screenshot-comparison-comment.yml @@ -66,7 +66,7 @@ jobs: # Check for invalid file names and add only valid ones exist_valid_files="false" for file in "${files_to_add[@]}"; do - if [[ $file =~ ^[a-zA-Z0-9_./-]+$ ]]; then + if [[ $file =~ ^[a-zA-Z0-9_./\[\]\-]+$ ]]; then exist_valid_files="true" break fi @@ -83,7 +83,7 @@ jobs: # Check for invalid file names and add only valid ones for file in $files_to_add; do - if [[ "$file" =~ ^[a-zA-Z0-9_./-]+$ ]]; then + if [[ "$file" =~ ^[a-zA-Z0-9_./\[\]\-]+$ ]]; then git add "$file" fi done @@ -99,7 +99,7 @@ jobs: shell: bash run: | # Find all the files ending with _compare.png in roborazzi folder - files=$(find . -type f -name "*_compare.png" | grep "roborazzi/" | grep -E "^[a-zA-Z0-9_./-]+$") + files=$(find . -type f -name "*_compare.png" | grep "roborazzi/" | grep -E "^[a-zA-Z0-9_./\[\]\-]+$") delimiter="$(openssl rand -hex 8)" { echo "reports<<${delimiter}" @@ -115,6 +115,8 @@ jobs: # Get the file name and insert newlines every 20 characters fileName=$(basename "$file" | sed -r 's/(.{20})/\1
/g') urlPart="${BRANCH_NAME//#/%23}/${file//#/%23}" + urlPart="${urlPart//[/%5B}" + urlPart="${urlPart//]/%5D}" echo "| [$fileName](https://github.com/${{ github.repository }}/blob/$urlPart) | ![](https://github.com/${{ github.repository }}/blob/$urlPart?raw=true) |" >> "$GITHUB_OUTPUT" done echo "${delimiter}" >> "$GITHUB_OUTPUT" From be67a0448d3a6ef4cfd78ad49415a5abea739d24 Mon Sep 17 00:00:00 2001 From: takahirom Date: Fri, 5 Jul 2024 10:34:56 +0900 Subject: [PATCH 3/8] Add space to regex --- .github/workflows/screenshot-comparison-comment.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/screenshot-comparison-comment.yml b/.github/workflows/screenshot-comparison-comment.yml index 48cb313c6..bd15c95fb 100644 --- a/.github/workflows/screenshot-comparison-comment.yml +++ b/.github/workflows/screenshot-comparison-comment.yml @@ -66,7 +66,7 @@ jobs: # Check for invalid file names and add only valid ones exist_valid_files="false" for file in "${files_to_add[@]}"; do - if [[ $file =~ ^[a-zA-Z0-9_./\[\]\-]+$ ]]; then + if [[ $file =~ ^[a-zA-Z0-9_./\[\]\- ]+$ ]]; then exist_valid_files="true" break fi @@ -83,7 +83,7 @@ jobs: # Check for invalid file names and add only valid ones for file in $files_to_add; do - if [[ "$file" =~ ^[a-zA-Z0-9_./\[\]\-]+$ ]]; then + if [[ "$file" =~ ^[a-zA-Z0-9_./\[\]\- ]+$ ]]; then git add "$file" fi done From 7d9f5837809fb341fbdd72990be12c085903aef2 Mon Sep 17 00:00:00 2001 From: takahirom Date: Fri, 5 Jul 2024 10:46:05 +0900 Subject: [PATCH 4/8] Fix conflict --- .github/workflows/screenshot-comparison-comment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/screenshot-comparison-comment.yml b/.github/workflows/screenshot-comparison-comment.yml index bd15c95fb..7b97f7140 100644 --- a/.github/workflows/screenshot-comparison-comment.yml +++ b/.github/workflows/screenshot-comparison-comment.yml @@ -99,7 +99,7 @@ jobs: shell: bash run: | # Find all the files ending with _compare.png in roborazzi folder - files=$(find . -type f -name "*_compare.png" | grep "roborazzi/" | grep -E "^[a-zA-Z0-9_./\[\]\-]+$") + files=$(find . -type f -name "*_compare.png" | grep "roborazzi/" | grep -E "^[a-zA-Z0-9_./\[\]\- ]+$") delimiter="$(openssl rand -hex 8)" { echo "reports<<${delimiter}" From ae2787b41e16ea2072ca143095f733099618063b Mon Sep 17 00:00:00 2001 From: takahirom Date: Sat, 6 Jul 2024 17:10:20 +0900 Subject: [PATCH 5/8] Remove unneeded nest --- .../confsched/sessions/TimetableScreenTest.kt | 74 +++++++++---------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/feature/sessions/src/androidUnitTest/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreenTest.kt b/feature/sessions/src/androidUnitTest/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreenTest.kt index d88dd1685..828f583e1 100644 --- a/feature/sessions/src/androidUnitTest/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreenTest.kt +++ b/feature/sessions/src/androidUnitTest/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreenTest.kt @@ -37,56 +37,54 @@ class TimetableScreenTest(private val testCase: DescribedTestCase> { return describeTests { - describe("TimetableScreenTest") { - describe("when server is operational") { + describe("when server is operational") { + run { robot -> + robot.setupTimetableServer(ServerStatus.Operational) + robot.setupTimetableScreenContent() + } + check("should show timetable items") { robot -> + robot.captureScreenWithChecks(checks = { + robot.checkTimetableItemsDisplayed() + }) + } + describe("click first session bookmark") { run { robot -> - robot.setupTimetableServer(ServerStatus.Operational) - robot.setupTimetableScreenContent() - } - check("should show timetable items") { robot -> - robot.captureScreenWithChecks(checks = { - robot.checkTimetableItemsDisplayed() - }) + robot.clickFirstSessionBookmark() } - describe("click first session bookmark") { - run { robot -> - robot.clickFirstSessionBookmark() - } - check("should show bookmarked session") { robot -> - // FIXME: Add check for bookmarked session - robot.captureScreenWithChecks() - } + check("should show bookmarked session") { robot -> + // FIXME: Add check for bookmarked session + robot.captureScreenWithChecks() } - describe("click first session") { - run { robot -> - robot.clickFirstSession() - } - check("should show session detail") { robot -> - // FIXME: Add check for navigation to session detail - robot.captureScreenWithChecks() - } + } + describe("click first session") { + run { robot -> + robot.clickFirstSession() } - describe("click timetable ui type change button") { - run { robot -> - robot.clickTimetableUiTypeChangeButton() - } - check("should change timetable ui type") { robot -> - // FIXME: Add check for timetable ui type change - robot.captureScreenWithChecks() - } + check("should show session detail") { robot -> + // FIXME: Add check for navigation to session detail + robot.captureScreenWithChecks() } } - describe("when server is down") { + describe("click timetable ui type change button") { run { robot -> - robot.setupTimetableServer(ServerStatus.Error) - robot.setupTimetableScreenContent() + robot.clickTimetableUiTypeChangeButton() } - check("should show error message") { robot -> - // FIXME: Add check for error message + check("should change timetable ui type") { robot -> + // FIXME: Add check for timetable ui type change robot.captureScreenWithChecks() } } } + describe("when server is down") { + run { robot -> + robot.setupTimetableServer(ServerStatus.Error) + robot.setupTimetableScreenContent() + } + check("should show error message") { robot -> + // FIXME: Add check for error message + robot.captureScreenWithChecks() + } + } } } } From 43d0a5a409e89236ce01b3bb7b63f01e6054c087 Mon Sep 17 00:00:00 2001 From: takahirom Date: Sat, 6 Jul 2024 17:38:18 +0900 Subject: [PATCH 6/8] Refactor tests --- ...RobolectricDescribeSpecParameterBuilder.kt | 14 +++--- .../testing/robot/TimetableScreenRobot.kt | 11 ++++- .../confsched/sessions/TimetableScreenTest.kt | 47 +++++++++---------- 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/core/testing/src/main/java/io/github/droidkaigi/confsched/testing/RobolectricDescribeSpecParameterBuilder.kt b/core/testing/src/main/java/io/github/droidkaigi/confsched/testing/RobolectricDescribeSpecParameterBuilder.kt index a089b3645..27465fcb0 100644 --- a/core/testing/src/main/java/io/github/droidkaigi/confsched/testing/RobolectricDescribeSpecParameterBuilder.kt +++ b/core/testing/src/main/java/io/github/droidkaigi/confsched/testing/RobolectricDescribeSpecParameterBuilder.kt @@ -26,8 +26,8 @@ fun DescribedTestCase.execute(robot: T) { sealed class TestNode { data class Describe(val description: String, val children: List>) : TestNode() - data class Run(val action: (T) -> Unit) : TestNode() - data class Check(val description: String, val action: (T) -> Unit) : TestNode() + data class Run(val action: T.() -> Unit) : TestNode() + data class Check(val description: String, val action: T.() -> Unit) : TestNode() } data class DescribedTestCase( @@ -59,12 +59,12 @@ class TestCaseTreeBuilder { children.add(TestNode.Describe(description, builder.children)) } - fun run(action: (T) -> Unit) { - children.add(TestNode.Run { robot -> action(robot as T) }) + fun run(action: T.() -> Unit) { + children.add(TestNode.Run { action() }) } - fun check(description: String, action: (T) -> Unit) { - children.add(TestNode.Check(description) { robot -> action(robot as T) }) + fun check(description: String, action: T.() -> Unit) { + children.add(TestNode.Check(description) { action() }) } fun build(): TestNode.Describe = TestNode.Describe("", children) @@ -95,7 +95,7 @@ private fun collectCheckNodes(root: TestNode.Describe): List is TestNode.Check -> { val fullDescription = if (parentDescription.isNotBlank()) { - "$parentDescription-${node.description}" + "$parentDescription - ${node.description}" } else { node.description } diff --git a/core/testing/src/main/java/io/github/droidkaigi/confsched/testing/robot/TimetableScreenRobot.kt b/core/testing/src/main/java/io/github/droidkaigi/confsched/testing/robot/TimetableScreenRobot.kt index 8acbd533b..fa3d1f19a 100644 --- a/core/testing/src/main/java/io/github/droidkaigi/confsched/testing/robot/TimetableScreenRobot.kt +++ b/core/testing/src/main/java/io/github/droidkaigi/confsched/testing/robot/TimetableScreenRobot.kt @@ -12,6 +12,7 @@ import com.github.takahirom.roborazzi.Dump import com.github.takahirom.roborazzi.RoborazziOptions import com.github.takahirom.roborazzi.captureRoboImage import io.github.droidkaigi.confsched.designsystem.theme.KaigiTheme +import io.github.droidkaigi.confsched.model.TimetableItem import io.github.droidkaigi.confsched.sessions.TimetableListItemBookmarkIconTestTag import io.github.droidkaigi.confsched.sessions.TimetableListItemTestTag import io.github.droidkaigi.confsched.sessions.TimetableScreen @@ -31,12 +32,16 @@ class TimetableScreenRobot @Inject constructor( private val timetableServerRobot: DefaultTimetableServerRobot, ) : ScreenRobot by screenRobot, TimetableServerRobot by timetableServerRobot { + val clickedItems = mutableSetOf() + fun setupTimetableScreenContent() { robotTestRule.setContent { CompositionLocalProvider(LocalClock provides FakeClock) { KaigiTheme { TimetableScreen( - onTimetableItemClick = { }, + onTimetableItemClick = { + clickedItems.add(it) + }, ) } } @@ -86,6 +91,10 @@ class TimetableScreenRobot @Inject constructor( } } + fun checkClickedItemsExists() { + assert(clickedItems.isNotEmpty()) + } + fun checkTimetableItemsDisplayed() { composeTestRule .onAllNodes(hasTestTag(TimetableListItemTestTag)) diff --git a/feature/sessions/src/androidUnitTest/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreenTest.kt b/feature/sessions/src/androidUnitTest/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreenTest.kt index 828f583e1..500a5edd2 100644 --- a/feature/sessions/src/androidUnitTest/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreenTest.kt +++ b/feature/sessions/src/androidUnitTest/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreenTest.kt @@ -38,51 +38,50 @@ class TimetableScreenTest(private val testCase: DescribedTestCase> { return describeTests { describe("when server is operational") { - run { robot -> - robot.setupTimetableServer(ServerStatus.Operational) - robot.setupTimetableScreenContent() + run { + setupTimetableServer(ServerStatus.Operational) + setupTimetableScreenContent() } - check("should show timetable items") { robot -> - robot.captureScreenWithChecks(checks = { - robot.checkTimetableItemsDisplayed() + check("should show timetable items") { + captureScreenWithChecks(checks = { + checkTimetableItemsDisplayed() }) } describe("click first session bookmark") { - run { robot -> - robot.clickFirstSessionBookmark() + run { + clickFirstSessionBookmark() } - check("should show bookmarked session") { robot -> + check("should show bookmarked session") { // FIXME: Add check for bookmarked session - robot.captureScreenWithChecks() + captureScreenWithChecks() } } describe("click first session") { - run { robot -> - robot.clickFirstSession() + run { + clickFirstSession() } - check("should show session detail") { robot -> - // FIXME: Add check for navigation to session detail - robot.captureScreenWithChecks() + check("should show session detail") { + checkClickedItemsExists() } } describe("click timetable ui type change button") { - run { robot -> - robot.clickTimetableUiTypeChangeButton() + run { + clickTimetableUiTypeChangeButton() } - check("should change timetable ui type") { robot -> + check("should change timetable ui type") { // FIXME: Add check for timetable ui type change - robot.captureScreenWithChecks() + captureScreenWithChecks() } } } describe("when server is down") { - run { robot -> - robot.setupTimetableServer(ServerStatus.Error) - robot.setupTimetableScreenContent() + run { + setupTimetableServer(ServerStatus.Error) + setupTimetableScreenContent() } - check("should show error message") { robot -> + check("should show error message") { // FIXME: Add check for error message - robot.captureScreenWithChecks() + captureScreenWithChecks() } } } From 52ff51e6f75fa176a9aadaf34d62a15ec0af7458 Mon Sep 17 00:00:00 2001 From: takahirom Date: Sat, 6 Jul 2024 17:40:58 +0900 Subject: [PATCH 7/8] Rename --- .../github/droidkaigi/confsched/sessions/TimetableScreenTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/sessions/src/androidUnitTest/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreenTest.kt b/feature/sessions/src/androidUnitTest/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreenTest.kt index 500a5edd2..d87af33ae 100644 --- a/feature/sessions/src/androidUnitTest/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreenTest.kt +++ b/feature/sessions/src/androidUnitTest/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreenTest.kt @@ -35,7 +35,7 @@ class TimetableScreenTest(private val testCase: DescribedTestCase> { + fun testCases(): List> { return describeTests { describe("when server is operational") { run { From 30cab5f3589deb9d8efb5ea1b34d063a4f4ee332 Mon Sep 17 00:00:00 2001 From: takahirom Date: Sat, 6 Jul 2024 17:56:13 +0900 Subject: [PATCH 8/8] Fix grid screenshot --- .../confsched/testing/robot/TimetableScreenRobot.kt | 1 + .../github/droidkaigi/confsched/sessions/TimetableScreen.kt | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/core/testing/src/main/java/io/github/droidkaigi/confsched/testing/robot/TimetableScreenRobot.kt b/core/testing/src/main/java/io/github/droidkaigi/confsched/testing/robot/TimetableScreenRobot.kt index fa3d1f19a..dd1e33acf 100644 --- a/core/testing/src/main/java/io/github/droidkaigi/confsched/testing/robot/TimetableScreenRobot.kt +++ b/core/testing/src/main/java/io/github/droidkaigi/confsched/testing/robot/TimetableScreenRobot.kt @@ -69,6 +69,7 @@ class TimetableScreenRobot @Inject constructor( composeTestRule .onNode(hasTestTag(TimetableUiTypeChangeButtonTestTag)) .performClick() + waitUntilIdle() } fun clickTimetableTab( diff --git a/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreen.kt b/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreen.kt index 5f39617f6..2f575c692 100644 --- a/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreen.kt +++ b/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/TimetableScreen.kt @@ -180,10 +180,6 @@ private fun TimetableScreen( }, snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, topBar = { -// TimetableTopArea( -// timetableUiType = uiState.timetableUiType, -// onTimetableUiChangeClick = onTimetableUiChangeClick, -// ) Row { Text(text = "UiType: ${uiState.timetableUiType}") Button(