Kotlin / JSのテスト:フレームワーク、コロチン、すべて-すべて-すべて

Kotlinは素晴らしいプロジェクトです。当初は単なるJVM言語として考えられていましたが、後にJavaScriptを含むすべての主流プラットフォームのコンパイルサポートを受けました。





入門。私はペットプロジェクトを持っています-ゲームElite:Dangerousのコミュニティ用のサイトとAPIプラットフォームです。バックエンドはKotlin / JVM(Ktor + Hibernate)、フロントエンドはKotlin / JS(KVision + Fomantic UI)です。ペットプロジェクトについては、後ほどお話しします。





  • KVisionは、さまざまなデスクトップフレームワーク(SwingやJavaFXからWinFormsやFlutterまで)のアイデアと、DSLビルダーなどのKotlin構文機能を組み合わせたKotlinのフロントエンドフレームワークです。





  • Fomantic-UIは、Bootstrapと比較できるコンポーネントHTML / JS WebフレームワークであるSemantic-UIのフォークであり、Fomanticだけがより興味深いものです。





少し前に、これら2つの世界をリンクして、KVisionのライブラリを作成するというアイデアを思いつきました。これにより、少なくともFomantic要素を使用してKVisionページを簡単に作成できるようになります。そして、オープンソースプロジェクトにふさわしいので、私はライブラリをテストでカバーすることを計画しました。この記事はこの冒険についてです。





コード

まず、タスクを定義しましょう。手元にある単純なFomanticボタンの次のコードがあります。





package com.github.kam1sh.kvision.fomantic

import pl.treksoft.kvision.html.*
import pl.treksoft.kvision.panel.SimplePanel


open class FoButton(text: String) : Button(text = text, classes = setOf("ui", "button")) {
    var primary: Boolean = false
        set(value) {
            if (value) addCssClass("primary") else removeCssClass("primary")
            field = value
        }
}

fun SimplePanel.foButton(
    text: String,
    init: (FoButton.() -> Unit)? = null
): FoButton {
    val btn = FoButton(text)
    init?.invoke(btn)
    add(btn)
    return btn
}    

      
      



そして、いくつかのテストがあります:





package com.github.kam1sh.kvision.fomantic

import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlinx.browser.document
import kotlinx.coroutines.*
import pl.treksoft.kvision.panel.ContainerType
import pl.treksoft.kvision.panel.Root

class FoButtonTest {
    lateinit var kvapp: Root

    @BeforeTest
    fun before() {
        kvapp = Root("kvapp", containerType = ContainerType.NONE, addRow = false)        
    }

    @Test
    fun genericButtonTest() {
        kvapp.foButton("Button")
        assertEqualsHtml("""...""")
    }

    @Test
    fun buttonPrimaryTest() {
        val btn = kvapp.foButton("Button") { primary = true }
        assertEqualsHtml("""...""")
        btn.primary = false
        assertEqualsHtml("""...""")
    }
}

fun assertEqualsHtml(expected: String, message: String? = null) {
    val actual = document.getElementById("kvapp")?.innerHTML
    assertEquals(expected, actual, message)
}
      
      



: "" KVision div id=kvapp, HTML-.





. div? HTML- - document.body?.insertAdjacentHTML(...)



, , - ?





<source lang="html">
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.3.1/dist/jquery.min.js"></script>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.8.7/dist/semantic.min.css">
    <script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.8.7/dist/semantic.min.js"></script>
</head>
<body>
    <main>
        <div id="kvapp">

        </div>
    </main>
</body>
</html>
</source>
      
      



You've lost karma

Kotlin/JS.

For browser projects, it downloads and installs the Karma test runner with other required dependencies; for Node.js projects, the Mocha test framework is used.

. Karma Mocha. , Karma js- karma.config.d



.





Karma , -:





// karma.config.d/page.js
config.set({
  customContextFile: "../../../../../src/test/resources/test.html"
})
      
      



test.html, , src/test/resources/test.html



. - , Karma build/js/packages/kvision-fomantic-test/node_modules



, .





, ? ./gradlew browserTest



, ... Disconnected (0 times), because no message in 30000 ms.





, HTML- , JS-. build/js/node_modules/karma/static/context.html



.





main-:





<!-- The scripts need to be in the body DOM element, as some test running frameworks need the body
     to have already been created so they can insert their magic into it. For example, if loaded
     before body, Angular Scenario test framework fails to find the body and crashes and burns in
     an epic manner. -->
<script src="context.js"></script>
<script type="text/javascript">
    // Configure our Karma and set up bindings
    %CLIENT_CONFIG%
    window.__karma__.setupContext(window);

    // All served files with the latest timestamps
    %MAPPINGS%
</script>
<!-- Dynamically replaced with <script> tags -->
%SCRIPTS%
<!-- Since %SCRIPTS% might include modules, the `loaded()` call needs to be in a module too.
This ensures all the tests will have been declared before karma tries to run them. -->
<script type="module">
    window.__karma__.loaded();
</script>
<script nomodule>
    window.__karma__.loaded();
</script>
      
      



, ... , .





- . ? , HTTP- Ktor . Python async



, pytest pytest-async, .





suspend .





> Task :compileTestKotlinJs FAILED





e: ...src/test/kotlin/com/github/kam1sh/kvision/fomantic/FoButtonTest.kt: (44, 5): Unsupported [suspend test functions]





- Gradle





. . .





, runBlocking {}



. ...





runBlocking Kotlin/JVM.





, , , , , by design. GlobalScope.promise



, runBlocking :





fun runBlocking(block: suspend (scope: CoroutineScope) -> Unit) = GlobalScope.promise { block(this) }
      
      



. , . Karma :





config.set({
  client: {
    mocha: {
      timeout: 9000
    }
  }
})
      
      



. workaround. UPD: @ilgonmic, , 0. !





Mocha, , , , :





  • , done-, .





  • , Promise.





, , . , kotlin-test-js .

, , . , Promise, Mocha .





, , ? -- ?





- Kotest. .





. , .





// build.gradle.kts
testImplementation("io.kotest:kotest-assertions-core-js:4.3.2")
testImplementation("io.kotest:kotest-framework-api-js:4.3.2")
testImplementation("io.kotest:kotest-framework-engine:4.3.2")
      
      



class FoButtonTest : FunSpec({
    var kvapp: Root? = null
    beforeEach {
        kvapp = Root("kvapp", containerType = ContainerType.NONE, addRow = false)
    }
    test("generic button") {
        kvapp!!.foButton("Button")
        assertEqualsHtml("""...""")
    }

    test("primary button") {
        val btn = kvapp!!.foButton("Button") { primary = true }
        assertEqualsHtml("""...""")
        btn.primary = false
        delay(200)
        assertEqualsHtml("""...""")
    }
})
      
      



kotest , , FunSpec -- .





, , delay() suspend.





:





今のところ、kotestについてお話しできるのはこれだけです。私はまだライブラリを開発し、準備ができたら、FomanticdiscordとKotlin / kvisionslackでリリースを発表します。そして並行して、私はkotestを学びます。





これだけでは不十分な場合は、お詫び申し上げます。ここ./gradlew --debug browserTest



結論を示したかったのですが、個人的な生活の様子により、この資料の準備はすでにかなり遅れていました。興味がある場合は、Gradleデバッグログを自分で検討してください。





だから何?まあ、何も。Kotlin / JSを食べ、kotestを飲み、自分の世話をします。








All Articles