Kotlin Multiplatform 2.0.0 Kotlin/JS, webpack で sayHello するライブラリをつくるところまで の続きです。
この sayHello ライブラリのテストを書きたいのだが、書き方がわからなかったので、調べました。 結論としては、このKotlin オフィシャルページの説明の通りです。 ここではテストに Firefox を使うので、 実行するOSに Firefox がインストールされている必要があります。
Firefox 以外でテストに使えるブラウザはこちら: https://kotlinlang.org/docs/js-project-setup.html#test-task
useChromeHeadless() を使えば Ubuntu Server 上でも(それがインストールされていれば)テスト実行できるようだ。
$ java --version
openjdk 17.0.2 2022-01-18
OpenJDK Runtime Environment (build 17.0.2+8-86)
OpenJDK 64-Bit Server VM (build 17.0.2+8-86, mixed mode, sharing)
$ gradle --version
Gradle 8.9
余談ですが、今回 Macbook Air M1 に新規に JDK をインストールしたのですが、 OpenJDK のバイナリ (openjdk-17.0.2_macos-aarch64_bin.tar.gz) を ここ https://jdk.java.net/archive/ から ダウンロードして展開、それを ~/.local/jdk-17 に配置しました。 JAVA_HOME 環境変数設定と PATH の設定をしたら普通に動かすことができました。 JDKを入れる方法はいくつかありますが、 この方法が一番楽な気がします。 なお OpenJDK のインストール方法のオフィシャル説明はここ https://openjdk.org/install/ です。
プロジェクトディレクトリを作成:
$ mkdir hello
$ cd hello
$ touch build.gradle.kts
build.gradle.kts の内容:
plugins {
kotlin("multiplatform") version "2.0.0"
}
version = "0.1"
repositories {
mavenCentral()
}
kotlin {
sourceSets {
commonTest.dependencies {
implementation(kotlin("test"))
}
}
js {
browser {
testTask {
useKarma {
useFirefox()
}
}
}
//binaries.library()
}
}
説明の都合上、今のところ binaries.library() はコメントアウトしています。
続いて Main.kt の用意:
$ mkdir -p src/jsMain/kotlin
$ touch src/jsMain/kotlin/Main.kt
Main.kt に次のコードを記述。
@ExperimentalJsExport
@JsExport
fun sayHello(name: String): String {
return "Hello, ${name}!"
}
続いて MainTest.kt を用意:
$ mkdir src/jsTest/kotlin
$ touch src/jsTest/kotlin/MainTest.kt
MainTest.kt に次のテストコードを記述。
import kotlin.test.Test
import kotlin.test.assertEquals
class MainTest {
@Test
fun sayHelloTest() {
val greeting = sayHello("World")
assertEquals(greeting, "Hello, World!")
}
}
ここで gradle wrapper しておきます。
$ gradle wrapper
これ以後は gradle コマンドの代わりに ./gradlew を使います。
それでは本題のテストを実行してみます。
./gradlew jsBrowserTest
はじめて実行すると (macOSでは)何か Firefox の追加コンポーネント?のインストールを促された。
ここに ./build/reports/tests/jsBrowserTest/index.html テスト結果のレポートが出るので確認しよう。
これでテストできるようになった。
ついでに、index.html からこの sayHello 関数を使う方法を確認する。
前回 は node.js 上で使うことは確認したが、ブラウザ上の HTML から直接使うのは試していなかった。
試しにビルドする。
$ ./gradlew build
ビルドした hello.js がどこに生成されたか確認。
$ find . -name hello.js
./build/js/packages/hello-test/kotlin/hello.js
./build/compileSync/js/test/testDevelopmentExecutable/kotlin/hello.js
binaries.library() をコメントアウトしていたので、意図した hello.js は生成できていない。
build.gradle.kts を編集して、 binaries.library() のコメントを外しイキにする。 その上で、再度 ./gradlew build する。
生成された hello.js を確認:
$ find . -name hello.js
./build/dist/js/productionLibrary/hello.js
./build/js/packages/hello-test/kotlin/hello.js
./build/js/packages/hello/kotlin/hello.js
./build/compileSync/js/test/testDevelopmentExecutable/kotlin/hello.js
./build/compileSync/js/main/productionLibrary/kotlin/hello.js
これを使えばよいのか?
またはこれ。
diff してみると内容は同じだった。
$ diff build/compileSync/js/main/productionLibrary/kotlin/hello.js build/js/packages/hello/kotlin/hello.js
それでは、hello.js を使う HTML を index.html に書く。
<html>
<body>
<h1>hello</h1>
<script src="hello.js"></script>
<script>
const message = hello.sayHello("World");
const newDiv = document.createElement("div");
const newContent = document.createTextNode(message);
newDiv.appendChild(newContent);
document.body.appendChild(newDiv);
</script>
</body>
</html>
テキストノードを生成して配置する方法 https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement
あとは先ほどの hello.js を この index.html と同じディレクトリに入れて、index.html を Firefox などのブラウザで開くだけです。
できました。
Hello, World! するだけならこれで作動するとして、普通は build/js 以下で webpack を使って依存するライブラリをまとめる必要がある。 詳しくはこちらをKotlin Multiplatform 2.0.0 Kotlin/JS, webpack で sayHello するライブラリをつくるところまで 参照。
webpack するときの webpack.config.js の設定。webpack で生成したライブラリを Node.js からではなく直接 Web で使う場合は、 libraryTarget の値は commonjs ではなく this を指定する。
webpack.config.js
const path = require('path'); module.exports = { mode: 'production', entry: './packages/hello/kotlin/hello.js', output: { library: 'hello', //libraryTarget: 'commonjs', libraryTarget: 'this', path: __dirname, filename: 'hellolib.js' } }
HTMLファイルに に記述している js でライブラリ使用する記述も変更がたぶん必要(未確認)。
//const message = hello.sayHello("World"); const message = sayHello("World");
これで、vanilla JS でコードを書くときに複雑なことは Kotlin JS で記述して使うというやり方ができる。