diff --git a/.github/workflows/TEST.yml b/.github/workflows/TEST.yml index 6adbd2cb42..6717772321 100644 --- a/.github/workflows/TEST.yml +++ b/.github/workflows/TEST.yml @@ -26,7 +26,7 @@ jobs: matrix: include: - { outputKey: testIos, os: macos-latest, testTask: iosX64Test, precompileTask: compileTestKotlinIosX64, enableKotlinNative: true } - - { outputKey: testJs, os: ubuntu-latest, testTask: "wasmJsBrowserTest", buildTasks: "jsBrowserTest", precompileTask: "wasmJsTestClasses jsTestClasses" } + - { outputKey: testJs, os: ubuntu-latest, testTask: "wasmJsBrowserTest", buildTasks: "jsBrowserTest jsDenoTest", precompileTask: "wasmJsTestClasses jsTestClasses" } - { outputKey: testAndroid, os: ubuntu-latest, enableAndroid: true, precompileTask: "compileDebugAndroidTestSources" } - { outputKey: testJvmMacos, os: macos-latest, testTask: jvmTest, precompileTask: "compileTestKotlinJvm compileTestKotlin" } - { outputKey: testJvmLinux, os: ubuntu-latest, testTask: jvmTest, precompileTask: "compileTestKotlinJvm compileTestKotlin", enableKotlinNative: true, enableSandbox: true, e2e: true } @@ -42,6 +42,7 @@ jobs: steps: - { uses: actions/checkout@v4 } - { name: Use Node.js 20.x, uses: actions/setup-node@v4, with: { node-version: 20.x } } + - { name: Setup Deno, uses: denoland/setup-deno@v1, with: { deno-version: "1.44.4" } } - { name: Configure parallel in local.properties, run: "echo org.gradle.parallel=true >> local.properties" } - { name: Replace gradle wrapper, run: "sed 's/-all/-bin/g' gradle/wrapper/gradle-wrapper.properties > gradle/wrapper/gradle-wrapper.properties.bak; cp gradle/wrapper/gradle-wrapper.properties.bak gradle/wrapper/gradle-wrapper.properties" } - { if: "${{ startsWith(matrix.os, 'ubuntu-') }}", name: Install freeglut3 & openal, run: sudo apt-get update && sudo apt-get -y install freeglut3-dev libopenal-dev xvfb } diff --git a/buildSrc/src/main/kotlin/korlibs/korge/gradle/targets/js/JavaScript.kt b/buildSrc/src/main/kotlin/korlibs/korge/gradle/targets/js/JavaScript.kt index 010bfa8d56..bfe15b72bb 100644 --- a/buildSrc/src/main/kotlin/korlibs/korge/gradle/targets/js/JavaScript.kt +++ b/buildSrc/src/main/kotlin/korlibs/korge/gradle/targets/js/JavaScript.kt @@ -87,7 +87,9 @@ fun Project.configureJavaScript(projectType: ProjectType) { configureEsbuild() configureWebpackFixes() + configureDenoTest() if (projectType.isExecutable) { + configureDenoRun() configureJavascriptRun() } configureWebpack() diff --git a/buildSrc/src/main/kotlin/korlibs/korge/gradle/targets/js/JavaScriptRun.kt b/buildSrc/src/main/kotlin/korlibs/korge/gradle/targets/js/JavaScriptRun.kt index e155379c34..914b1a7c19 100644 --- a/buildSrc/src/main/kotlin/korlibs/korge/gradle/targets/js/JavaScriptRun.kt +++ b/buildSrc/src/main/kotlin/korlibs/korge/gradle/targets/js/JavaScriptRun.kt @@ -59,6 +59,72 @@ open class RunJsServer : DefaultTask() { } } +fun Project.fullPathName(): String { + if (this.parent == null) return this.name + return this.parent!!.fullPathName() + ":" + this.name +} + +fun Project.configureDenoTest() { + afterEvaluate { + if (tasks.findByName("compileTestDevelopmentExecutableKotlinJs") == null) return@afterEvaluate + + val jsDenoTest = project.tasks.createThis("jsDenoTest") { + group = "verification" + + dependsOn("compileTestDevelopmentExecutableKotlinJs") + + val baseTestFileNameBase = project.fullPathName().trim(':').replace(':', '-') + "-test" + val baseTestFileName = "$baseTestFileNameBase.mjs" + + val runFile = File(rootProject.rootDir, "build/js/packages/$baseTestFileNameBase/kotlin/$baseTestFileName.deno.mjs") + + commandLine("deno", "test", "--unstable-ffi", "--unstable-webgpu", "-A", runFile) + workingDir(runFile.parentFile.absolutePath) + + doFirst { + runFile.parentFile.mkdirs() + runFile.writeText( + //language=js + """ + var describeStack = [] + globalThis.describe = (name, callback) => { describeStack.push(name); try { callback() } finally { describeStack.pop() } } + globalThis.it = (name, callback) => { return Deno.test({ name: describeStack.join(".") + "." + name, fn: callback}) } + globalThis.xit = (name, callback) => { return Deno.test({ name: describeStack.join(".") + "." + name, ignore: true, fn: callback}) } + function exists(path) { try { Deno.statSync(path); return true } catch (e) { return false } } + // Polyfill required for kotlinx-coroutines that detects window + window.postMessage = (message, targetOrigin) => { const ev = new Event('message'); ev.source = window; ev.data = message; window.dispatchEvent(ev); } + const file = './$baseTestFileName'; + if (exists(file)) await import(file) + """.trimIndent()) + } + } + } +} + +fun Project.configureDenoRun() { + afterEvaluate { + if (tasks.findByName("compileDevelopmentExecutableKotlinJs") == null) return@afterEvaluate + + val baseRunFileNameBase = project.fullPathName().trim(':').replace(':', '-') + val baseRunFileName = "$baseRunFileNameBase.mjs" + val runFile = File(rootProject.rootDir, "build/js/packages/$baseRunFileNameBase/kotlin/$baseRunFileName") + + val runDeno = project.tasks.createThis("runDeno") { + group = GROUP_KORGE_RUN + dependsOn("compileDevelopmentExecutableKotlinJs") + commandLine("deno", "run", "--unstable-ffi", "--unstable-webgpu", "-A", runFile) + workingDir(runFile.parentFile.absolutePath) + } + + val packageDeno = project.tasks.createThis("packageDeno") { + group = GROUP_KORGE_PACKAGE + dependsOn("compileDevelopmentExecutableKotlinJs") + commandLine("deno", "compile", "--unstable-ffi", "--unstable-webgpu", "-A", runFile) + workingDir(runFile.parentFile.absolutePath) + } + } +} + fun Project.configureJavascriptRun() { val runJsRelease = project.tasks.createThis(name = "runJsRelease") { group = GROUP_KORGE_RUN diff --git a/buildSrc/src/main/kotlin/korlibs/root/RootKorlibsPlugin.kt b/buildSrc/src/main/kotlin/korlibs/root/RootKorlibsPlugin.kt index b737ad2295..e2b2dfb263 100644 --- a/buildSrc/src/main/kotlin/korlibs/root/RootKorlibsPlugin.kt +++ b/buildSrc/src/main/kotlin/korlibs/root/RootKorlibsPlugin.kt @@ -608,6 +608,7 @@ object RootKorlibsPlugin { project.configureEsbuild() project.configureJavascriptRun() + project.configureDenoRun() } } @@ -723,6 +724,7 @@ object RootKorlibsPlugin { //tasks.withType(Test::class.java).allThis { afterEvaluate { it.configureTests() + project.configureDenoTest() } } } diff --git a/korge-core/test/korlibs/io/file/registry/WindowsRegistryTest.kt b/korge-core/test/korlibs/io/file/registry/WindowsRegistryTest.kt index 712f586302..5d7c25075b 100644 --- a/korge-core/test/korlibs/io/file/registry/WindowsRegistryTest.kt +++ b/korge-core/test/korlibs/io/file/registry/WindowsRegistryTest.kt @@ -4,11 +4,13 @@ import korlibs.encoding.* import korlibs.io.async.* import korlibs.io.file.* import korlibs.io.stream.* +import korlibs.platform.* import kotlin.test.* class WindowsRegistryTest { + // @TODO: Move to korlibs repo @Test - fun testRegistry() = suspendTest({ WindowsRegistry.isSupported }) { + fun testRegistry() = suspendTest({ WindowsRegistry.isSupported && !Platform.isJsDenoJs }) { assertEquals(WindowsRegistry.KEY_MAP.keys.toList().sorted(), WindowsRegistryVfs.root.listNames().sorted()) //println(WindowsRegistryVfs.HKEY_LOCAL_MACHINE["Software"].listNames()) diff --git a/korge-core/test@js/korlibs/webgpu/WebGPUTest.kt b/korge-core/test@js/korlibs/webgpu/WebGPUTest.kt index 6eab71a662..9a92e92569 100644 --- a/korge-core/test@js/korlibs/webgpu/WebGPUTest.kt +++ b/korge-core/test@js/korlibs/webgpu/WebGPUTest.kt @@ -4,6 +4,7 @@ import io.ygdrasil.wgpu.internal.js.* import korlibs.image.bitmap.* import korlibs.image.format.* import korlibs.io.async.* +import korlibs.io.net.* import korlibs.math.geom.* import kotlinx.browser.* import kotlinx.coroutines.* @@ -193,6 +194,8 @@ class WebGPUTest { device.queue.submit(arrayOf(encoder.finish())); createPng(outputBuffer, dimensions) + + device.destroy() } data class CreateCapture(val texture: GPUTexture, val outputBuffer: GPUBuffer) @@ -220,7 +223,7 @@ class WebGPUTest { format = GPUTextureFormat.RGBA8UNORM_SRGB, usage = (GPUTextureUsage.RENDER_ATTACHMENT or GPUTextureUsage.COPY_SRC), ) - ); + ) return CreateCapture(texture, outputBuffer) } @@ -294,28 +297,10 @@ class WebGPUTest { val bitmap = Bitmap32(dimensions.width, dimensions.height, Int32Array(outputBuffer.buffer).unsafeCast()) - val nativeImage = nativeImageFormatProvider.create(dimensions.width, dimensions.height).unsafeCast() - //HtmlNativeImage() - //println(PNG.encode(bitmap).base64) - nativeImage.context2d { - drawImage(bitmap, Point(0, 0)) - } + RegisteredImageFormats.register(PNG) + println(DataURL(nativeImageFormatProvider.encodeSuspend(bitmap, ImageEncodingProps("file.png")), "image/png").url) - println(nativeImage.element.unsafeCast().toDataURL("image/png")) - - //PNG.encode() - //val image = png.encode( - // outputBuffer, - //dimensions.width, - //dimensions.height, - //{ - // stripAlpha: true, - // color: 2, - //}, - //); - //Deno.writeFileSync("./output.png", image); - - buffer.unmap(); + buffer.unmap() } }