From 371ac296d43b8c456e2190143ae5bd8b1a40b9eb Mon Sep 17 00:00:00 2001 From: Piotr Krzeminski Date: Thu, 21 May 2026 17:22:13 +0200 Subject: [PATCH 1/2] Add Selenium smoke test for web app --- .github/workflows/ci.main.kts | 15 ++++ .github/workflows/ci.yaml | 17 +++++ settings.gradle.kts | 2 +- web-e2e/build.gradle.kts | 19 +++++ .../kotlin/it/krzeminski/fsynth/SmokeTest.kt | 71 +++++++++++++++++++ 5 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 web-e2e/build.gradle.kts create mode 100644 web-e2e/src/test/kotlin/it/krzeminski/fsynth/SmokeTest.kt diff --git a/.github/workflows/ci.main.kts b/.github/workflows/ci.main.kts index 0bc90e9..802e75a 100755 --- a/.github/workflows/ci.main.kts +++ b/.github/workflows/ci.main.kts @@ -93,6 +93,21 @@ workflow( ) } + job( + id = "web-e2e", + runsOn = UbuntuLatest, + ) { + uses(name = "Check out", action = Checkout()) + uses( + name = "Set up JDK 8", + action = SetupJava( + javaVersion = "8", + distribution = SetupJava.Distribution.Temurin, + ), + ) + run(name = "E2E smoke test", command = "./gradlew :web-e2e:test") + } + job( id = "web", runsOn = UbuntuLatest, diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 681a50c..d9c72e4 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -87,6 +87,23 @@ jobs: - id: 'step-3' name: 'Upload coverage to Codecov' uses: 'codecov/codecov-action@v4' + web-e2e: + runs-on: 'ubuntu-latest' + needs: + - 'check_yaml_consistency' + steps: + - id: 'step-0' + name: 'Check out' + uses: 'actions/checkout@v4' + - id: 'step-1' + name: 'Set up JDK 8' + uses: 'actions/setup-java@v4' + with: + java-version: '8' + distribution: 'temurin' + - id: 'step-2' + name: 'E2E smoke test' + run: './gradlew :web-e2e:test' web: runs-on: 'ubuntu-latest' permissions: diff --git a/settings.gradle.kts b/settings.gradle.kts index b7379ef..d005414 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,4 +8,4 @@ pluginManagement { rootProject.name = "fsynth" -include("core", "cli", "web", ":web:worker", ":web:serviceworker", "android") +include("core", "cli", "web", ":web:worker", ":web:serviceworker", "android", "web-e2e") diff --git a/web-e2e/build.gradle.kts b/web-e2e/build.gradle.kts new file mode 100644 index 0000000..de6658a --- /dev/null +++ b/web-e2e/build.gradle.kts @@ -0,0 +1,19 @@ +plugins { + kotlin("jvm") +} + +val kotlinVersion: String by rootProject.extra + +dependencies { + testImplementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion") + testImplementation("org.jetbrains.kotlin:kotlin-test") + testImplementation("org.jetbrains.kotlin:kotlin-test-junit") + testImplementation("junit:junit:4.13.2") + testImplementation("org.seleniumhq.selenium:selenium-java:4.15.0") + testImplementation("io.github.bonigarcia:webdrivermanager:5.6.2") +} + +tasks.test { + dependsOn(":web:build") + systemProperty("web.dist", rootProject.projectDir.resolve("web/build/distributions").absolutePath) +} diff --git a/web-e2e/src/test/kotlin/it/krzeminski/fsynth/SmokeTest.kt b/web-e2e/src/test/kotlin/it/krzeminski/fsynth/SmokeTest.kt new file mode 100644 index 0000000..d34f17d --- /dev/null +++ b/web-e2e/src/test/kotlin/it/krzeminski/fsynth/SmokeTest.kt @@ -0,0 +1,71 @@ +package it.krzeminski.fsynth + +import com.sun.net.httpserver.HttpExchange +import com.sun.net.httpserver.HttpServer +import io.github.bonigarcia.wdm.WebDriverManager +import java.io.File +import java.net.InetSocketAddress +import java.nio.file.Files +import org.junit.AfterClass +import org.junit.Assert.assertTrue +import org.junit.BeforeClass +import org.junit.Test +import org.openqa.selenium.By +import org.openqa.selenium.chrome.ChromeDriver +import org.openqa.selenium.chrome.ChromeOptions + +class SmokeTest { + companion object { + private lateinit var server: HttpServer + private lateinit var driver: ChromeDriver + private const val PORT = 8765 + + @BeforeClass + @JvmStatic + fun setup() { + val webDist = System.getProperty("web.dist")!! + server = HttpServer.create(InetSocketAddress(PORT), 0).apply { + createContext("/") { exchange: HttpExchange -> + val file = File(webDist, exchange.requestURI.path).normalize() + if (file.absolutePath.startsWith(File(webDist).absolutePath) && file.isFile) { + exchange.sendResponseHeaders(200, file.length()) + Files.copy(file.toPath(), exchange.responseBody) + } else { + exchange.sendResponseHeaders(404, -1) + } + exchange.close() + } + executor = null + } + server.start() + println("HTTP server started on port $PORT, serving $webDist") + + WebDriverManager.chromedriver().setup() + val options = ChromeOptions().apply { + addArguments("--headless") + addArguments("--no-sandbox") + addArguments("--disable-dev-shm-usage") + } + driver = ChromeDriver(options) + println("ChromeDriver started") + } + + @AfterClass + @JvmStatic + fun teardown() { + driver.quit() + server.stop(0) + println("Cleanup done") + } + } + + @Test + fun titleAndSongListAreDisplayed() { + driver.get("http://localhost:$PORT/index.html") + + val bodyText = driver.findElement(By.tagName("body")).text + assertTrue("Page should contain app title", bodyText.contains("fsynth")) + assertTrue("Page should contain at least one song name", bodyText.contains("Simple demo song")) + assertTrue("Page should contain playback customization section", bodyText.contains("Playback customization")) + } +} From 232fc041d9f17e5dd61860781cc531275eca9422 Mon Sep 17 00:00:00 2001 From: Piotr Krzeminski Date: Thu, 21 May 2026 17:30:27 +0200 Subject: [PATCH 2/2] Fix web-e2e: use JDK 17 for WebDriverManager 5.x compatibility --- .github/workflows/ci.main.kts | 4 ++-- .github/workflows/ci.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.main.kts b/.github/workflows/ci.main.kts index 802e75a..b432cc9 100755 --- a/.github/workflows/ci.main.kts +++ b/.github/workflows/ci.main.kts @@ -99,9 +99,9 @@ workflow( ) { uses(name = "Check out", action = Checkout()) uses( - name = "Set up JDK 8", + name = "Set up JDK 17", action = SetupJava( - javaVersion = "8", + javaVersion = "17", distribution = SetupJava.Distribution.Temurin, ), ) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d9c72e4..ade6086 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -96,10 +96,10 @@ jobs: name: 'Check out' uses: 'actions/checkout@v4' - id: 'step-1' - name: 'Set up JDK 8' + name: 'Set up JDK 17' uses: 'actions/setup-java@v4' with: - java-version: '8' + java-version: '17' distribution: 'temurin' - id: 'step-2' name: 'E2E smoke test'