3

I have a simple project in Kotlin JavaScript using React. I've added unit tests, but when I run them, they seem to call main method of production code, and fail on initialization, when trying to reach unexsistent DOM structure. Despite the fact that the tested class does not reference React or DOM in any way.

The error looks the same when run from Intelij IDEA or by gradlew build (I've replaced the full path to my project with /APP/ for clarity):

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

Minimal example:

./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")
    }
}

The error does not occur if I don't reference production code at all (remove DummyClass().foo() from the test), or when main method does not call render(document.getElementById("root")).

PS: If it matters I run the code on Windows

4

2 回答 2

2

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

这个答案指出

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

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

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

同时,您可以

  • <div id="root"></div>作为一部分删除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")) {

    }
}

希望有帮助

于 2020-05-28T06:39:54.747 回答
0

我有同样的问题,我修复了它。感谢@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 时,它可以防止呈现目标错误。

于 2020-12-11T18:24:29.297 回答