Menguji Kotlin / JS: framework, coroutine, dan semuanya-semuanya-semuanya

Kotlin adalah proyek yang brilian. Awalnya dipahami hanya sebagai bahasa JVM, kemudian menerima dukungan kompilasi untuk semua platform utama, termasuk JavaScript.





Pengantar. Saya memiliki proyek hewan peliharaan - situs web dan platform API untuk komunitas untuk game Elite: Dangerous. Backendnya adalah Kotlin / JVM (Ktor + Hibernate), frontendnya adalah Kotlin / JS (KVision + Fomantic UI). Saya akan memberi tahu Anda tentang proyek hewan peliharaan nanti, dan lebih banyak lagi tentang bagian depan.





  • KVision adalah kerangka kerja front - end untuk Kotlin yang menggabungkan ide dari berbagai kerangka kerja desktop (dari Swing dan JavaFX hingga WinForms dan Flutter) dan kemampuan sintaks Kotlin, seperti pembuat DSL.





  • Fomantic-UI adalah cabang dari Semantic-UI, sebuah komponen kerangka web HTML / JS yang dapat dibandingkan dengan Bootstrap, hanya Fomantic yang lebih menarik.





Belum lama ini, saya mendapat ide untuk menghubungkan kedua dunia ini dan menulis perpustakaan untuk KVision, yang setidaknya akan mempermudah penulisan halaman KVision dengan elemen Fomantic. Dan, sebagai proyek open source, saya berencana untuk menutupi perpustakaan dengan tes. Artikel ini akan membahas tentang petualangan ini.





Kode

Pertama-tama, mari kita definisikan tugasnya. Kami memiliki kode berikut untuk tombol Fomantic sederhana di tangan kami:





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
}    

      
      



Dan ada beberapa tes:





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.





:





Hanya itu yang bisa saya ceritakan tentang kotest untuk saat ini. Saya masih akan mengembangkan library tersebut, dan jika sudah siap, saya akan mengumumkan rilisnya di Fomantic discord dan slack Kotlin / kvision. Dan secara paralel saya akan belajar kotest.





Jika ini belum cukup bagi Anda, maka saya mohon maaf: Saya ingin menunjukkan kesimpulan di sini ./gradlew --debug browserTest



, tetapi persiapan materi ini sudah cukup tertunda karena penampilan kehidupan pribadi, jadi jika Anda tertarik - renungkan sendiri log debug Gradle.





Terus? Tidak apa-apa. Makan Kotlin / JS, minum kotest, dan jaga dirimu.








All Articles