From 83d48995f3d0860e7a91729c97b9442357c92a7a Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 15 Jul 2026 12:53:39 -0400 Subject: [PATCH 1/3] Revert "Increased are the smoke tests timeouts (#14)" This reverts commit c5e59388925ccf85b3e8128beab0e3d763a0bd4f. --- .github/workflows/build.yml | 11 +++++------ .../bibletranslationtools/writer/uitest/SmokeFlow.kt | 10 +++++----- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3983ef8..52ef4fd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,6 @@ jobs: name: Android E2E (Maestro) runs-on: ubuntu-latest timeout-minutes: 20 - needs: test steps: - name: Free disk space uses: jlumbroso/free-disk-space@v1.3.1 @@ -77,6 +76,7 @@ jobs: test: name: Run tests runs-on: ubuntu-latest + needs: test-android-e2e steps: - name: Checkout uses: actions/checkout@v4 @@ -103,7 +103,6 @@ jobs: name: Desktop smoke runs-on: ubuntu-latest # Own runner so HOME/config/temp are not shared with jvmTest or Maestro. - needs: test steps: - name: Checkout uses: actions/checkout@v4 @@ -140,7 +139,7 @@ jobs: build-android: name: Build Android runs-on: ubuntu-latest - needs: test-android-e2e + needs: test steps: - name: Checkout uses: actions/checkout@v4 @@ -176,7 +175,7 @@ jobs: build-desktop-macos: name: Build Desktop macOS runs-on: macos-latest - needs: test-desktop-smoke + needs: [test, test-desktop-smoke] steps: - name: Checkout uses: actions/checkout@v4 @@ -197,7 +196,7 @@ jobs: build-desktop-windows: name: Build Desktop Windows runs-on: windows-latest - needs: test-desktop-smoke + needs: [test, test-desktop-smoke] steps: - name: Checkout uses: actions/checkout@v4 @@ -218,7 +217,7 @@ jobs: build-desktop-linux: name: Build Desktop Linux runs-on: ubuntu-latest - needs: test-desktop-smoke + needs: [test, test-desktop-smoke] steps: - name: Checkout uses: actions/checkout@v4 diff --git a/shared/src/jvmTest/kotlin/org/bibletranslationtools/writer/uitest/SmokeFlow.kt b/shared/src/jvmTest/kotlin/org/bibletranslationtools/writer/uitest/SmokeFlow.kt index 504eb35..50a0953 100644 --- a/shared/src/jvmTest/kotlin/org/bibletranslationtools/writer/uitest/SmokeFlow.kt +++ b/shared/src/jvmTest/kotlin/org/bibletranslationtools/writer/uitest/SmokeFlow.kt @@ -47,7 +47,7 @@ fun ComposeUiTest.completeSmokeSettings() { onNodeWithText("General").assertIsDisplayed() onNodeWithContentDescription("back").performClick() - waitUntilVisible("Your Translation Projects", timeoutMillis = 15_000) + waitUntilVisible("Your Translation Projects", timeoutMillis = 5_000) } @OptIn(ExperimentalTestApi::class) @@ -152,7 +152,7 @@ private fun ComposeUiTest.scrollUntilVisible(text: String, timeoutMillis: Long = // Review/lists may not expose scroll semantics yet; keep polling. } waitForIdle() - mainClock.advanceTimeBy(100) + mainClock.advanceTimeByFrame() } throw AssertionError("Timed out after ${timeoutMillis}ms waiting for \"$text\" while scrolling") } @@ -163,7 +163,7 @@ private fun ComposeUiTest.waitUntilVisible(text: String, timeoutMillis: Long) { while (System.nanoTime() < deadline) { if (isTextVisible(text)) return waitForIdle() - mainClock.advanceTimeBy(100) + mainClock.advanceTimeByFrame() } throw AssertionError("Timed out after ${timeoutMillis}ms waiting for \"$text\"") } @@ -181,7 +181,7 @@ private fun ComposeUiTest.waitUntilSetTextAction(timeoutMillis: Long) { return } waitForIdle() - mainClock.advanceTimeBy(100) + mainClock.advanceTimeByFrame() } throw AssertionError("Timed out after ${timeoutMillis}ms waiting for editable text field") } @@ -192,7 +192,7 @@ private fun ComposeUiTest.waitUntilContentDescription(description: String, timeo while (System.nanoTime() < deadline) { if (isContentDescriptionVisible(description)) return waitForIdle() - mainClock.advanceTimeBy(100) + mainClock.advanceTimeByFrame() } throw AssertionError("Timed out after ${timeoutMillis}ms waiting for content description \"$description\"") } From 9cfdc712e56b9c01e156031a0fb6ebb0d4364c67 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 15 Jul 2026 13:07:47 -0400 Subject: [PATCH 2/3] add screenshots --- .github/workflows/build.yml | 9 ++++++ shared/build.gradle.kts | 7 +++++ .../writer/uitest/SmokeFlow.kt | 3 ++ .../writer/uitest/SmokeScreenshots.kt | 30 +++++++++++++++++++ 4 files changed, 49 insertions(+) create mode 100644 shared/src/jvmTest/kotlin/org/bibletranslationtools/writer/uitest/SmokeScreenshots.kt diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 52ef4fd..b3d2544 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -136,6 +136,15 @@ jobs: path: "**/build/reports/tests/jvmSmokeTest/" if-no-files-found: ignore + - name: Upload smoke test screenshots + uses: actions/upload-artifact@v4 + if: always() + with: + name: smoke-test-screenshots + path: "**/build/jvmSmokeTest-screenshots/" + if-no-files-found: ignore + retention-days: 7 + build-android: name: Build Android runs-on: ubuntu-latest diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 28855df..c2036ef 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -221,11 +221,18 @@ tasks.register("jvmSmokeTest") { // Isolated work/home/temp so smoke never reuses prefs/library from jvmTest or prior runs. val smokeRoot = layout.buildDirectory.dir("jvmSmokeTest-env") + val smokeScreenshotsDir = layout.buildDirectory.dir("jvmSmokeTest-screenshots") doFirst { val root = smokeRoot.get().asFile root.deleteRecursively() listOf("home", "config", "tmp", "work").forEach { File(root, it).mkdirs() } + smokeScreenshotsDir.get().asFile.deleteRecursively() + smokeScreenshotsDir.get().asFile.mkdirs() } + systemProperty( + "btt.writer.smoke.screenshots.dir", + smokeScreenshotsDir.map { it.asFile.absolutePath }.get(), + ) workingDir = smokeRoot.map { it.dir("work") }.get().asFile systemProperty("java.io.tmpdir", smokeRoot.map { it.dir("tmp").asFile.absolutePath }.get()) environment("HOME", smokeRoot.map { it.dir("home").asFile.absolutePath }.get()) diff --git a/shared/src/jvmTest/kotlin/org/bibletranslationtools/writer/uitest/SmokeFlow.kt b/shared/src/jvmTest/kotlin/org/bibletranslationtools/writer/uitest/SmokeFlow.kt index 50a0953..032a47c 100644 --- a/shared/src/jvmTest/kotlin/org/bibletranslationtools/writer/uitest/SmokeFlow.kt +++ b/shared/src/jvmTest/kotlin/org/bibletranslationtools/writer/uitest/SmokeFlow.kt @@ -41,13 +41,16 @@ fun ComposeUiTest.completeSmokeSettings() { onNodeWithText("I Agree").performClick() waitUntilVisible("Your Translation Projects", timeoutMillis = 3_000) + takeSmokeScreenshot("smoke-settings/projects-home") onNodeWithContentDescription("More Options").performClick() onNodeWithText("Settings").performClick() onNodeWithText("General").assertIsDisplayed() + takeSmokeScreenshot("smoke-settings/settings-general") onNodeWithContentDescription("back").performClick() waitUntilVisible("Your Translation Projects", timeoutMillis = 5_000) + takeSmokeScreenshot("smoke-settings/projects-home-after-settings") } @OptIn(ExperimentalTestApi::class) diff --git a/shared/src/jvmTest/kotlin/org/bibletranslationtools/writer/uitest/SmokeScreenshots.kt b/shared/src/jvmTest/kotlin/org/bibletranslationtools/writer/uitest/SmokeScreenshots.kt new file mode 100644 index 0000000..a5b9024 --- /dev/null +++ b/shared/src/jvmTest/kotlin/org/bibletranslationtools/writer/uitest/SmokeScreenshots.kt @@ -0,0 +1,30 @@ +package org.bibletranslationtools.writer.uitest + +import androidx.compose.ui.graphics.asSkiaBitmap +import androidx.compose.ui.test.ComposeUiTest +import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.captureToImage +import androidx.compose.ui.test.onRoot +import org.jetbrains.skia.EncodedImageFormat +import org.jetbrains.skia.Image +import java.io.File + +private val screenshotRoot: File by lazy { + File( + System.getProperty("btt.writer.smoke.screenshots.dir") + ?: System.getenv("BTT_WRITER_SMOKE_SCREENSHOTS_DIR") + ?: "build/smoke-screenshots", + ).also { it.mkdirs() } +} + +@OptIn(ExperimentalTestApi::class) +fun ComposeUiTest.takeSmokeScreenshot(name: String) { + waitForIdle() + val pngBytes = Image.makeFromBitmap(onRoot().captureToImage().asSkiaBitmap()) + .encodeToData(EncodedImageFormat.PNG) + ?.bytes + ?: error("Failed to encode screenshot as PNG: $name") + val file = File(screenshotRoot, "$name.png") + file.parentFile?.mkdirs() + file.writeBytes(pngBytes) +} From 22ea63c41300db8f4b2c62fc4bfbbed4c7115305 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 15 Jul 2026 13:50:31 -0400 Subject: [PATCH 3/3] clean up build --- .github/workflows/build.yml | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b3d2544..1389178 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -128,22 +128,16 @@ jobs: Xvfb :99 -screen 0 1024x768x24 & DISPLAY=:99 ./gradlew :shared:jvmSmokeTest - - name: Upload smoke test reports + - name: Upload smoke test artifacts uses: actions/upload-artifact@v4 - if: always() - with: - name: smoke-test-reports - path: "**/build/reports/tests/jvmSmokeTest/" - if-no-files-found: ignore - - - name: Upload smoke test screenshots - uses: actions/upload-artifact@v4 - if: always() + if: failure() with: - name: smoke-test-screenshots - path: "**/build/jvmSmokeTest-screenshots/" + name: smoke-test-artifacts + path: | + **/build/reports/tests/jvmSmokeTest/ + **/build/jvmSmokeTest-screenshots/ if-no-files-found: ignore - retention-days: 7 + retention-days: 3 build-android: name: Build Android