Kotlin JS 中的单元测试
Unit testing in Kotlin JS
我在 Kotlin JavaScript 中有一个使用 React 的简单项目。我已经添加了单元测试,但是当我 运行 它们时,它们似乎调用了生产代码的主要方法,并且在尝试达到不存在的 DOM 结构时初始化失败。尽管经过测试的 class 没有以任何方式引用 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
上的代码
这不是正确的答案 - 但可以立即解除阻止。
回答指出
the test environment doesn't supply the DOM with an app 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")) {
}
}
希望对您有所帮助
我遇到了同样的问题,我已经解决了。多亏了@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 上启动业力的方法,但由于我现在可以访问所有资源,所以我只是使用了@Yogesh Nachnani 提出的解决方法,因为 HTML 文件通常不会对测试有很大影响(至少对我而言)。因此,我添加了一个 setup.js 文件,其中仅包含:
document.body.insertAdjacentHTML('afterbegin', "<div id='root'></div>");
当您使用 render(document.getElementById("root")){} for React 时,它可以防止呈现目标错误。
我在 Kotlin JavaScript 中有一个使用 React 的简单项目。我已经添加了单元测试,但是当我 运行 它们时,它们似乎调用了生产代码的主要方法,并且在尝试达到不存在的 DOM 结构时初始化失败。尽管经过测试的 class 没有以任何方式引用 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
上的代码这不是正确的答案 - 但可以立即解除阻止。
the test environment doesn't supply the DOM with an app 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")) {
}
}
希望对您有所帮助
我遇到了同样的问题,我已经解决了。多亏了@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 上启动业力的方法,但由于我现在可以访问所有资源,所以我只是使用了@Yogesh Nachnani 提出的解决方法,因为 HTML 文件通常不会对测试有很大影响(至少对我而言)。因此,我添加了一个 setup.js 文件,其中仅包含:
document.body.insertAdjacentHTML('afterbegin', "<div id='root'></div>");
当您使用 render(document.getElementById("root")){} for React 时,它可以防止呈现目标错误。