Kotlin es un proyecto brillante. Inicialmente concebido como un lenguaje JVM, luego recibió soporte de compilación para todas las plataformas principales, incluido JavaScript.
Introductorio. Tengo un proyecto favorito: un sitio y una plataforma API para la comunidad para el juego Elite: Dangerous. El backend es Kotlin / JVM (Ktor + Hibernate), el frontend es Kotlin / JS (KVision + Fomantic UI). Te contaré sobre el proyecto de mascotas más tarde, y más en el frente.
KVision es un marco de interfaz para Kotlin que combina ideas de varios marcos de escritorio (desde Swing y JavaFX hasta WinForms y Flutter) y capacidades de sintaxis de Kotlin, como los constructores de DSL.
Fomantic-UI es una bifurcación de Semantic-UI, un marco web HTML / JS basado en componentes similar a Bootstrap, solo que Fomantic es más interesante.
No hace mucho, tuve la idea de conectar estos dos mundos y escribir una biblioteca para KVision, lo que al menos facilitaría la escritura de páginas de KVision con elementos Fomantic. Y, como corresponde a un proyecto de código abierto, planeé cubrir la biblioteca con pruebas. Este artículo será sobre esta aventura.
El código
En primer lugar, definamos la tarea. Tenemos el siguiente código para un simple botón Fomantic en nuestras manos:
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
}
Y hay un par de pruebas:
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.
:
Eso es todo lo que puedo decirte sobre kotest por ahora. Seguiré desarrollando la biblioteca, y cuando esté lista, anunciaré su lanzamiento en la discordia Fomantic y la holgura de Kotlin / kvision. Y en paralelo aprenderé kotest.
Si esto no fue suficiente para ti, entonces te pido disculpas: quería mostrar la conclusión aquí ./gradlew --debug browserTest
, pero la preparación de este material ya se retrasó bastante debido a la apariencia de la vida personal, así que si estás interesado, contempla los registros de depuración de Gradle tú mismo.
¿Y qué? Pues nada. Come Kotlin / JS, bebe kotest y cuídate.