Home About Contact
Kotlin , Kotlin Multiplatform , JavaScript

Kotlin Multiplatform 2.0.0 Kotlin/JS でテストを書く、生成したライブラリをHTMLから使用する覚え書き

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/ です。

hello プロジェクト

プロジェクトディレクトリを作成:

$ 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 テスト結果のレポートが出るので確認しよう。

これでテストできるようになった。

hello.js ライブラリを生成して 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

できました。

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 で記述して使うというやり方ができる。