【问题标题】:Unit testing in Kotlin JSKotlin JS 中的单元测试
【发布时间】:2020-09-02 11:49:48
【问题描述】:

我有一个使用 React 的 Kotlin JavaScript 简单项目。我添加了单元测试,但是当我运行它们时,它们似乎调用了生产代码的主要方法,并且在尝试访问不存在的 DOM 结构时初始化失败。尽管测试的类没有以任何方式引用 React 或 DOM。

从 Intelij IDEA 或 gradlew build 运行时,错误看起来相同(为清楚起见,我已将项目的完整路径替换为 /APP/):

Testing started at 17:51 ...
> Task :cleanBrowserTest
> Task :packageJson UP-TO-DATE
> Task :testPackageJson UP-TO-DATE
> Task :kotlinNodeJsSetup SKIPPED
> Task :kotlinNpmInstall
> Task :compileKotlinJs
> Task :processResources
> Task :mainClasses
> Task :compileTestKotlinJs
> Task :testProcessResources NO-SOURCE
> Task :testClasses

> Task :browserTest

(...)

Error: Target container is not a DOM element.

    at render (http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:25359:13)

    at render_0 (http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:29868:5)

    at main (http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:146311:5)

    at Object.<anonymous> (http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:146315:3)

    at http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:146289:37

    at Object.../example/kotlin/example.js (http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:146292:2)

    at __webpack_require__ (http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:20:30)

    at http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:146346:134

    at Object../kotlin/example-test.js (http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:146351:2)

    at __webpack_require__ (http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:20:30)

HeadlessChrome 81.0.4044 (Windows 10.0.0) ERROR

  Uncaught Error: Target container is not a DOM element.

  at d:/APP/build/js/node_modules/react-dom/cjs/react-dom.development.js:24828:1 <- D:/APP/build/js/packages/example-test/adapter-browser.js:25359:7

(...)


> Task :browserTest FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':browserTest'.
> command 'C:\Users\Arsen\.gradle\nodejs\node-v12.14.0-win-x64\node.exe' exited with errors (exit code: 1)

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 10s
8 actionable tasks: 6 executed, 2 up-to-date

小例子:

./build.gradle.kts

plugins {
    id("org.jetbrains.kotlin.js") version "1.3.70-eap-184"
}

group = "org.example"
version = "1.0-SNAPSHOT"

repositories {
    maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") }
    maven("https://kotlin.bintray.com/kotlin-js-wrappers/")
    mavenCentral()
    jcenter()
}

dependencies {
    implementation(kotlin("stdlib-js"))

    implementation("org.jetbrains:kotlin-react:16.13.0-pre.94-kotlin-1.3.70")
    implementation("org.jetbrains:kotlin-react-dom:16.13.0-pre.94-kotlin-1.3.70")
    implementation(npm("react", "16.13.1"))
    implementation(npm("react-dom", "16.13.1"))
    testImplementation(kotlin("test-js"))
}

kotlin.target.browser {
}

./settings.gradle.kts

pluginManagement {
    repositories {
        maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") }

        mavenCentral()

        maven { setUrl("https://plugins.gradle.org/m2/") }
    }
}
rootProject.name = "example"

./src/main/resources/index.html

<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
        <div id="root"></div>
        <script src="example.js"></script>
    </body>
</html>

./src/main/kotlin/Main.kt

import react.dom.*
import kotlin.browser.document

fun main(args: Array<String>) {
    render(document.getElementById("root")) {

    }
}

./src/main/kotlin/DummyClass.kt

class DummyClass {
    fun foo(): String {
        return "foo"
    }
}

./src/test/kotlin/ExampleTest.kt

import kotlin.test.*

class ExampleTest {
    @Test
    fun foo() {
        assertEquals(DummyClass().foo(), "foo")
    }
}

如果我根本不引用生产代码(从测试中删除 DummyClass().foo()),或者当 main 方法没有调用 render(document.getElementById("root")) 时,错误不会发生。

PS:如果重要的话,我会在 Windows 上运行代码

【问题讨论】:

    标签: reactjs unit-testing kotlin-js


    【解决方案1】:

    这不是正确的答案 - 但它会立即解除您的阻止。

    This回答指出

    测试环境不向 DOM 提供应用 ID。

    我们的测试框架也是如此——它没有提供 id 为“root”的元素。 这让我相信 main/resources/index.html 没有被测试框架使用。异常跟踪证实了这一点——注意它是如何从__webpack_require__开始的

    理想的解决方案是让 karma 或 webpack 为我们的代码提供正确的 index.html;但我不知道如何做到这一点。

    在此期间,您可以

    • 删除&lt;div id="root"&gt;&lt;/div&gt; 作为index.html 的一部分
    • 让您的 kotlin 代码生成它,如下所示:

      ./src/main/kotlin/Main.kt

    fun main(args: Array<String>) {
        document.body!!.insertAdjacentHTML("afterbegin", "<div id='root'></div>" )
        render(document.getElementById("root")) {
    
        }
    }
    

    希望有帮助

    【讨论】:

    • 谢谢。这是一个非常好的解决方法。 :) 我会等待一个非解决方法的解决方案,但如果在赏金到期之前它没有发生,你就会得到它。 ;)
    • 感谢您的解决方法。但是,有人找到解决此问题的方法吗?因为(至少对我而言)无法使用资源中的任何文件,例如,它阻止我根据翻译文件进行测试。
    【解决方案2】:

    我遇到了同样的问题,我已经解决了。感谢@Yogesh Nachnani 的解决方法,我明白缺少什么。事实上,所有资源文件都不包括在内。因此,首先我使用 fs-extra(将文件从资源复制到本地目录)创建了一个新的解决方法,然后当我探索 Karma 时,我发现最干净的解决方案是使用代理将请求重定向到资源。因此我在 karma.config.js 中使用了以下代码:

    const path = require('path');
    const resourcesSourcePath = path.resolve(__dirname, '../../../../build/processedResources/js/main');
    const setupFile = path.resolve(__dirname, '../../../../src/test/setup.js');
    config.files.unshift(setupFile);
    config.proxies = {
        "/strings/": "absolute" + resourcesSourcePath + "/strings/",
        "/css/": "absolute" + resourcesSourcePath + "/css/",
        "/images/": "absolute" + resourcesSourcePath + "/images/"
    }
    

    这样,如果您有很多资源,您就不必等待内容的副本。但是,我没有找到在 index.html 上启动 karma 的方法,但是由于我现在可以访问所有资源,因此我只使用了@Yogesh Nachnani 提出的解决方法,因为 HTML 文件通常对测试没有太大影响(至少对我来说)。因此我添加了一个 setup.js 文件,它只包含:

    document.body.insertAdjacentHTML('afterbegin', "<div id='root'></div>");
    

    当您将 render(document.getElementById("root")){} 用于 React 时,它可以防止呈现目标错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-06
      • 1970-01-01
      • 2022-01-24
      相关资源
      最近更新 更多