Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions .github/workflows/unit-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ run-name: "unit-test by ${{ github.actor }}"
permissions: { }

jobs:
unit-test:
unit-test-android-jvm:
runs-on: ubuntu-latest
timeout-minutes: 60

Expand All @@ -33,7 +33,7 @@ jobs:
name: event-payload
path: ${{ github.event_path }}

- run: ./gradlew testDevDebugUnitTest testDebugUnitTest --stacktrace
- run: ./gradlew testDevDebugUnitTest testDebugUnitTest jvmTest --stacktrace

- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: always()
Expand All @@ -42,3 +42,19 @@ jobs:
path: |
**/reports
**/build/outputs/roborazzi

# For now, just ensuring the test is passing on iOS platform
unit-test-ios:
runs-on: macos-latest
timeout-minutes: 60

permissions:
contents: read # for clone

steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- uses: ./.github/actions/setup-java

- run: ./gradlew iosSimulatorArm64Test --stacktrace
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public class FakeSessionsApiClient : SessionsApiClient {
public val defaultSessionId: String = defaultSession.id

public val defaultSessions: List<SessionResponse> = SessionsAllResponse.fake()
.filterConferenceDaySessions().sessions.filter { it.sessionType == "NORMAL" }.take(7)
.filterConferenceDaySessions().sessions.filter { it.sessionType == "NORMAL" }.take(10)
public val defaultSessionIds: List<String> = defaultSessions.map { it.id }

public val defaultSessionWithLongDescription: SessionResponse = SessionsAllResponse.fake()
Expand Down Expand Up @@ -234,7 +234,7 @@ private fun SessionResponse.Companion.fakes(
for (day in 0 until 3) {
val dayOffsetSeconds = day * 24 * 60 * 60 + 10 * 60 * 60 + (0.5 * 60 * 60).toInt()
for (room in rooms) {
for (index in 0 until 4) {
for (index in 0 until 5) {
val start =
(DroidKaigi2025Day.Workday.start + (index * 30 * 60 * 60 + dayOffsetSeconds).seconds)
val end =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ package io.github.droidkaigi.confsched.model.core

actual fun getDefaultLocale(): Locale {
// FIXME: This is a temporary implementation.
return Locale.JAPAN
return Locale.OTHER
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ actual fun SemanticsNodeInteraction.captureNodeWithDescription(description: Stri
.split(".")
.dropLast(2) // drop method name and extension
.joinToString(".")
.plus(" - $description.png")
.plus(" - $description - android.png")
println("Capture screen: $filePath")
this.captureRoboImage(filePath)
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package io.github.droidkaigi.confsched.testing.compose

import androidx.compose.foundation.layout.Box
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.DeviceConfigurationOverride
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.intl.LocaleList
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
Expand All @@ -18,20 +24,29 @@ import kotlinx.coroutines.test.TestDispatcher
import soil.query.SwrCachePlus
import soil.query.compose.SwrClientProvider

const val TestRootTestTag = "TestRoot"

@Composable
fun TestDefaultsProvider(
testDispatcher: TestDispatcher,
fontFamily: FontFamily? = changoFontFamily(),
content: @Composable () -> Unit,
) {
KaigiTheme(fontFamily = fontFamily) {
Surface {
SwrClientProvider(SwrCachePlus(CoroutineScope(testDispatcher))) {
CompositionLocalProvider(
LocalLifecycleOwner provides FakeLocalLifecycleOwner(),
LocalViewModelStoreOwner provides FakeViewModelStoreOwner(),
content = content,
)
Box(
// Workaround (JVM): Another window (e.g. DropdownMenu) may create duplicate Root nodes,
// causing fetchSemanticsNode inside captureRoboImage to fail with multiple candidates.
// Adding a testTag ensures the Root is uniquely identified.
modifier = Modifier.testTag(TestRootTestTag),
) {
KaigiTheme(fontFamily = fontFamily) {
Surface {
SwrClientProvider(SwrCachePlus(CoroutineScope(testDispatcher))) {
CompositionLocalProvider(
LocalLifecycleOwner provides FakeLocalLifecycleOwner(),
LocalViewModelStoreOwner provides FakeViewModelStoreOwner(),
content = content,
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package io.github.droidkaigi.confsched.testing.robot.core

import androidx.compose.ui.test.ComposeUiTest
import androidx.compose.ui.test.SemanticsNodeInteraction
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.test.onNodeWithTag
import dev.zacsweers.metro.Inject
import io.github.droidkaigi.confsched.testing.behavior.TestCaseDescriptionProvider
import io.github.droidkaigi.confsched.testing.compose.TestRootTestTag

interface CaptureScreenRobot {
context(composeUiTest: ComposeUiTest, checkNode: TestCaseDescriptionProvider)
Expand All @@ -19,6 +20,8 @@ class DefaultCaptureScreenRobot : CaptureScreenRobot {
context(composeUiTest: ComposeUiTest, testCaseDescriptionProvider: TestCaseDescriptionProvider)
override fun captureScreenWithChecks(checks: () -> Unit) {
checks()
composeUiTest.onRoot().captureNodeWithDescription(testCaseDescriptionProvider.description)
composeUiTest
.onNodeWithTag(TestRootTestTag)
.captureNodeWithDescription(testCaseDescriptionProvider.description)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.github.droidkaigi.confsched.testing.robot.search

import androidx.compose.ui.test.ComposeUiTest
import androidx.compose.ui.test.assertAll
import androidx.compose.ui.test.assertCountEquals
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertTextContains
Expand Down Expand Up @@ -364,7 +365,7 @@ class SearchScreenRobot(
fun checkTimetableListNotDisplayed() {
composeUiTest
.onNodeWithTag(TimetableListTestTag)
.assertIsNotDisplayed()
.assertDoesNotExist()
}

context(composeUiTest: ComposeUiTest)
Expand All @@ -387,6 +388,6 @@ class SearchScreenRobot(
composeUiTest
.onAllNodesWithTag(TimetableItemCardTestTag)
.onFirst()
.assertIsNotDisplayed()
.assertDoesNotExist()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ context(composeUiTest: ComposeUiTest)
actual fun SemanticsNodeInteraction.captureNodeWithDescription(description: String) {
captureRoboImage(
composeUiTest = composeUiTest,
filePath = "$description.png",
filePath = "$description - ios.png",
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ actual fun SemanticsNodeInteraction.captureNodeWithDescription(description: Stri
.split(".")
.dropLast(2) // drop method name and extension
.joinToString(".")
.plus(" - $description.png")
.plus(" - $description - desktop.png")
println("Capture screen: $filePath")
this.captureRoboImage(filePath)
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,10 @@ tasks.withType<KotlinNativeCompile>().all {
dependsOn("kspCommonMainKotlinMetadata")
}
}

// ensure JVM target tests run in English locale
tasks.withType<Test>().configureEach {
if (name == "jvmTest") {
systemProperty("user.language", "en")
}
}
Loading