From 382c6a319b5f48f574733da83525521c29aca4aa Mon Sep 17 00:00:00 2001 From: Oleksandr Karpovich Date: Mon, 18 Dec 2023 13:33:50 +0300 Subject: [PATCH] run k/wasm tests in resources library (#4031) Co-authored-by: Oleksandr.Karpovich --- components/resources/library/build.gradle.kts | 16 ++++-- .../library/karma.config.d/wasm/config.js | 55 +++++++++++++++++++ .../compose/resources/TestUtils.blocking.kt | 8 ++- .../jetbrains/compose/resources/TestUtils.kt | 4 +- .../compose/resources/TestUtils.js.kt | 10 ++-- .../compose/resources/TestUtils.wasmJs.kt | 16 +++++- 6 files changed, 94 insertions(+), 15 deletions(-) create mode 100644 components/resources/library/karma.config.d/wasm/config.js diff --git a/components/resources/library/build.gradle.kts b/components/resources/library/build.gradle.kts index ba8ef3cfb9..56c2eaad08 100644 --- a/components/resources/library/build.gradle.kts +++ b/components/resources/library/build.gradle.kts @@ -36,10 +36,13 @@ kotlin { wasmJs { browser { testTask(Action { - // TODO: fix the test setup and enable - enabled = false + useKarma { + useChromeHeadless() + useConfigDirectory(project.projectDir.resolve("karma.config.d").resolve("wasm")) + } }) } + binaries.executable() } macosX64() macosArm64() @@ -105,7 +108,7 @@ kotlin { dependsOn(jvmAndAndroidTest) dependencies { implementation(compose.desktop.currentOs) - implementation("org.jetbrains.compose.ui:ui-test-junit4:$composeVersion") + implementation(compose.desktop.uiTestJUnit4) implementation(libs.kotlinx.coroutines.swing) } } @@ -192,9 +195,14 @@ configureMavenPublication( name = "Resources for Compose JB" ) +// adding it here to make sure skiko is unpacked and available in web tests +compose.experimental { + web.application {} +} + afterEvaluate { // TODO(o.k.): remove this after we refactor jsAndWasmMain source set in skiko to get rid of broken "common" js-interop tasks.configureEach { if (name == "compileWebMainKotlinMetadata") enabled = false } -} \ No newline at end of file +} diff --git a/components/resources/library/karma.config.d/wasm/config.js b/components/resources/library/karma.config.d/wasm/config.js new file mode 100644 index 0000000000..22429e585a --- /dev/null +++ b/components/resources/library/karma.config.d/wasm/config.js @@ -0,0 +1,55 @@ +// see https://kotlinlang.org/docs/js-project-setup.html#webpack-configuration-file +// This file provides karma.config.d configuration to run tests with k/wasm + +const path = require("path"); + +config.browserConsoleLogOptions.level = "debug"; + +const basePath = config.basePath; +const projectPath = path.resolve(basePath, "..", "..", "..", ".."); +const generatedAssetsPath = path.resolve(projectPath, "build", "karma-webpack-out") + +const debug = message => console.log(`[karma-config] ${message}`); + +debug(`karma basePath: ${basePath}`); +debug(`karma generatedAssetsPath: ${generatedAssetsPath}`); + +config.proxies["/"] = path.resolve(basePath, "kotlin"); + +config.files = [ + {pattern: path.resolve(generatedAssetsPath, "**/*"), included: false, served: true, watched: false}, + {pattern: path.resolve(basePath, "kotlin", "**/*.png"), included: false, served: true, watched: false}, + {pattern: path.resolve(basePath, "kotlin", "**/*.gif"), included: false, served: true, watched: false}, + {pattern: path.resolve(basePath, "kotlin", "**/*.ttf"), included: false, served: true, watched: false}, + {pattern: path.resolve(basePath, "kotlin", "**/*.txt"), included: false, served: true, watched: false}, + {pattern: path.resolve(basePath, "kotlin", "**/*.json"), included: false, served: true, watched: false}, + {pattern: path.resolve(basePath, "kotlin", "**/*.xml"), included: false, served: true, watched: false}, +].concat(config.files); + +function KarmaWebpackOutputFramework(config) { + // This controller is instantiated and set during the preprocessor phase. + const controller = config.__karmaWebpackController; + + // only if webpack has instantiated its controller + if (!controller) { + console.warn( + "Webpack has not instantiated controller yet.\n" + + "Check if you have enabled webpack preprocessor and framework before this framework" + ) + return + } + + config.files.push({ + pattern: `${controller.outputPath}/**/*`, + included: false, + served: true, + watched: false + }) +} + +const KarmaWebpackOutputPlugin = { + 'framework:webpack-output': ['factory', KarmaWebpackOutputFramework], +}; + +config.plugins.push(KarmaWebpackOutputPlugin); +config.frameworks.push("webpack-output"); \ No newline at end of file diff --git a/components/resources/library/src/blockingTest/kotlin/org/jetbrains/compose/resources/TestUtils.blocking.kt b/components/resources/library/src/blockingTest/kotlin/org/jetbrains/compose/resources/TestUtils.blocking.kt index 1dc80a47eb..94a48bf768 100644 --- a/components/resources/library/src/blockingTest/kotlin/org/jetbrains/compose/resources/TestUtils.blocking.kt +++ b/components/resources/library/src/blockingTest/kotlin/org/jetbrains/compose/resources/TestUtils.blocking.kt @@ -3,4 +3,10 @@ package org.jetbrains.compose.resources import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.runBlocking -actual fun runBlockingTest(block: suspend CoroutineScope.() -> Unit) = runBlocking(block = block) \ No newline at end of file + +actual typealias TestReturnType = Unit + +actual fun runBlockingTest(block: suspend CoroutineScope.() -> Unit): TestReturnType { + return runBlocking { block() } +} + diff --git a/components/resources/library/src/commonTest/kotlin/org/jetbrains/compose/resources/TestUtils.kt b/components/resources/library/src/commonTest/kotlin/org/jetbrains/compose/resources/TestUtils.kt index 929011679a..b308653028 100644 --- a/components/resources/library/src/commonTest/kotlin/org/jetbrains/compose/resources/TestUtils.kt +++ b/components/resources/library/src/commonTest/kotlin/org/jetbrains/compose/resources/TestUtils.kt @@ -2,7 +2,9 @@ package org.jetbrains.compose.resources import kotlinx.coroutines.CoroutineScope -expect fun runBlockingTest(block: suspend CoroutineScope.() -> Unit) +expect class TestReturnType + +expect fun runBlockingTest(block: suspend CoroutineScope.() -> Unit): TestReturnType internal fun TestStringResource(key: String) = StringResource( "STRING:$key", diff --git a/components/resources/library/src/jsTest/kotlin/org/jetbrains/compose/resources/TestUtils.js.kt b/components/resources/library/src/jsTest/kotlin/org/jetbrains/compose/resources/TestUtils.js.kt index 1884a096d8..2d9dfb5498 100644 --- a/components/resources/library/src/jsTest/kotlin/org/jetbrains/compose/resources/TestUtils.js.kt +++ b/components/resources/library/src/jsTest/kotlin/org/jetbrains/compose/resources/TestUtils.js.kt @@ -1,9 +1,7 @@ package org.jetbrains.compose.resources -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.promise +import kotlinx.coroutines.* -@OptIn(DelicateCoroutinesApi::class) -actual fun runBlockingTest(block: suspend CoroutineScope.() -> Unit): dynamic = GlobalScope.promise(block = block) \ No newline at end of file +actual typealias TestReturnType = Any +actual fun runBlockingTest(block: suspend CoroutineScope.() -> Unit): TestReturnType = + TODO("Implement if necessary. We focus on k/wasm target for now") \ No newline at end of file diff --git a/components/resources/library/src/wasmJsTest/kotlin/org/jetbrains/compose/resources/TestUtils.wasmJs.kt b/components/resources/library/src/wasmJsTest/kotlin/org/jetbrains/compose/resources/TestUtils.wasmJs.kt index 52a1bcaab2..0cfd4d8b96 100644 --- a/components/resources/library/src/wasmJsTest/kotlin/org/jetbrains/compose/resources/TestUtils.wasmJs.kt +++ b/components/resources/library/src/wasmJsTest/kotlin/org/jetbrains/compose/resources/TestUtils.wasmJs.kt @@ -1,7 +1,17 @@ package org.jetbrains.compose.resources -import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.* +import kotlinx.coroutines.test.runTest -actual fun runBlockingTest(block: suspend CoroutineScope.() -> Unit) { - TODO("To be implemented in PR 4031") +@JsFun("() => ''") +private external fun jsRef(): JsAny + + +actual typealias TestReturnType = Any +/** + * Runs the [block] in a coroutine. + */ +actual fun runBlockingTest(block: suspend CoroutineScope.() -> Unit): TestReturnType = MainScope().promise { + block() + jsRef() } \ No newline at end of file