测试 React:目标容器不是 DOM 元素
Testing React: Target Container is not a DOM element
我正在尝试在使用 Webpack 时使用 Jest/Enzyme 测试 React 组件。
我有一个非常简单的测试@
import React from 'react';
import { shallow } from 'enzyme';
import App from './App';
it('App', () => {
const app = shallow(<App />);
expect(1).toEqual(1);
});
它拾取的相关组件是:
import React, { Component } from 'react';
import { render } from 'react-dom';
// import './styles/normalize.css';
class App extends Component {
render() {
return (
<div>app</div>
);
}
}
render(<App />, document.getElementById('app'));
然而,运行 jest
导致失败:
Invariant Violation: _registerComponent(...): Target container is not a DOM element.
有错误 @
at Object.<anonymous> (src/App.js:14:48)
at Object.<anonymous> (src/App.test.js:4:38)
测试文件引用第 4 行,这是 <App />
的导入,导致失败。堆栈跟踪显示 App.js
的第 14 行是失败的原因——这只不过是来自 react-dom
的渲染调用,这是我从未遇到过的挑战(应用程序从我的 Webpack 设置)。
对于那些感兴趣的人(Webpack 代码):
module.exports = {
entry: './src/App',
output: {
filename: 'bundle.js',
path: './dist'
},
module: {
loaders: [
{
test: /\.js?$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['react', 'es2015']
}
},
{
test: /\.css$/,
loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'
},
{
test: /\.scss$/,
loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!sass'
}
]
}
}
还有我的 package.json
:
{
"name": "tic-tac-dux",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack-dev-server --devtool eval --progress --colors --inline --hot --content-base dist/",
"test": "jest"
},
"jest": {
"moduleNameMapper": {
"^.+\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"^.+\.(css|sass)$": "<rootDir>/__mocks__/styleMock.js"
}
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.17.0",
"babel-jest": "^16.0.0",
"babel-loader": "^6.2.5",
"babel-polyfill": "^6.16.0",
"babel-preset-es2015": "^6.16.0",
"babel-preset-react": "^6.16.0",
"css-loader": "^0.25.0",
"enzyme": "^2.4.1",
"jest": "^16.0.1",
"jest-cli": "^16.0.1",
"node-sass": "^3.10.1",
"react-addons-test-utils": "^15.3.2",
"react-dom": "^15.3.2",
"sass-loader": "^4.0.2",
"style-loader": "^0.13.1",
"webpack": "^1.13.2",
"webpack-dev-server": "^1.16.2"
},
"dependencies": {
"react": "^15.3.2",
"react-dom": "^15.3.2"
}
}
哦,如果有人要说 div 元素没有在脚本之前加载,这是我的 index.html
:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>App</title>
</head>
<body>
<div id="app"></div>
<script src="/bundle.js"></script>
</body>
</html>
这个特殊的渲染问题可能是什么原因造成的?与 15.0 的新 Jest 更新有关吗?
App.jsx
应该导出 App class 并且什么都不做,render
应该在别处调用。
如果您从 App.jsx 中删除 render
调用,错误应该会消失,但它会弹出,因为测试环境没有为 DOM 提供 app
id.
对于像我一样通过互联网进行梳理的任何其他人 - 在使用 Jest 进行测试时寻找解决方案 - 我将支持@biphobe 的答案,说 Jest 会导致此错误发生时您在调用 ReactDOM.render 的同一文件中导出某些内容。
在我的例子中,我在 index.js 中导出了一个对象,我也在其中调用了 ReactDOM.render。我删除了这个出口,瞧!
据我所知,这个错误在很多情况下都会出现,需要不同的方法来解决。我的场景和上面的例子不太一样,我用的是redux & router,虽然我一直在纠结同样的错误。帮助我解决这个问题的是将 index.js
从:
更改为
ReactDOM.render(
<Provider store={store}>
<AppRouter />
</Provider>,
document.getElementById("root")
);
registerServiceWorker();
至:
ReactDOM.render(
(<Provider store={store}>
<AppRouter/>
</Provider>),
document.getElementById('root') || document.createElement('div') // for testing purposes
);
registerServiceWorker();
我找到了针对我的用例的此错误的解决方案:使用相同的 Redux 存储 React 在 React 之外使用。
在尝试从 index.tsx
导出我的 React 的 Redux store
以便在 React 应用程序之外的其他地方使用时,我在 运行 Jest 测试时遇到了同样的错误(在 App.tsx
文件中使用 Enzyme。
错误
在测试 React 时不起作用的初始代码如下所示。
// index.tsx
import * as React from "react";
import { render } from "react-dom";
import { Provider } from "react-redux";
import { applyMiddleware, compose, createStore } from "redux";
import App from "./components/App";
import { rootReducer } from "./store/reducers";
import { initialState } from "./store/state";
const middlewares = [];
export const store = createStore(
rootReducer,
initialState,
compose(applyMiddleware(...middlewares)),
);
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root"),
);
对我有用的解决方案
将 Redux 存储逻辑分离到一个名为 store.ts
的新文件中,然后创建一个 default export
(供 index.tsx
,即 React 应用程序使用)和一个非默认用export const store
导出(从非React类使用),如下。
// store.ts
import { applyMiddleware, compose, createStore } from "redux";
import logger from "redux-logger";
import { rootReducer } from "./store/reducers";
import { initialState } from "./store/state";
const middlewares = [];
export const store = createStore(
rootReducer,
initialState,
compose(applyMiddleware(...middlewares)),
);
export default store;
// updated index.tsx
import * as React from "react";
import { render } from "react-dom";
import { Provider } from "react-redux";
import App from "./components/App";
import store from "./store";
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root"),
);
在非 React 中使用 Redux 存储 类
// MyClass.ts
import { store } from "./store"; // store.ts
export default class MyClass {
handleClick() {
store.dispatch({ ...new SomeAction() });
}
}
default
导出
出发前的小提示。以下是如何使用 default
和非默认导出。
default export store;
与 import store from "./store";
一起使用
export const store = ...
与 import { store } from "./store";
一起使用
希望对您有所帮助!
https://nono.ma/says/solved-invariant-violation-target-container-is-not-a-dom-element
确保在您的测试文件中您已正确导入 render 组件。
它应该从 @testing-library/react
而不是 react-dom
:
导入
import { render } from '@testing-library/react';
好吧,我们不能阻止开发人员从任何文件导出组件并单独测试它,即使它有 react-dom import or usage in it 。我的意思是它有什么问题。我们不会试图破坏整个文件并测试它的某些部分,只要那是一段有效的代码即可。
Jest 与 react-dom 没有问题,但从概念上讲它们是 diff 。 Jest 应该是一个无浏览器的虚拟测试环境。 React-DOM 是一个将虚拟 DOM 拼接到真实 DOM 的库,用于反应组件。
很明显我们 can/should 没有以正常方式测试它。但这不是现在的讨论。只要我们导出的组件是可测试的,我们就没问题。
所以让我们嘲笑它
我在 jest config 中配置了“setupFilesAfterEnv”的 testSetup 文件中进行了模拟。
jest.mock("react-dom", () => {
return ({
"render": jest.fn()
})
})
这对我来说非常有用。我的 react 和 react-dom 代码现在可以愉快地放在一个文件中,在浏览器和测试环境中也能正常工作。
我还没有遇到任何问题。有的话我会去评论区看看
我正在尝试在使用 Webpack 时使用 Jest/Enzyme 测试 React 组件。
我有一个非常简单的测试@
import React from 'react';
import { shallow } from 'enzyme';
import App from './App';
it('App', () => {
const app = shallow(<App />);
expect(1).toEqual(1);
});
它拾取的相关组件是:
import React, { Component } from 'react';
import { render } from 'react-dom';
// import './styles/normalize.css';
class App extends Component {
render() {
return (
<div>app</div>
);
}
}
render(<App />, document.getElementById('app'));
然而,运行 jest
导致失败:
Invariant Violation: _registerComponent(...): Target container is not a DOM element.
有错误 @
at Object.<anonymous> (src/App.js:14:48)
at Object.<anonymous> (src/App.test.js:4:38)
测试文件引用第 4 行,这是 <App />
的导入,导致失败。堆栈跟踪显示 App.js
的第 14 行是失败的原因——这只不过是来自 react-dom
的渲染调用,这是我从未遇到过的挑战(应用程序从我的 Webpack 设置)。
对于那些感兴趣的人(Webpack 代码):
module.exports = {
entry: './src/App',
output: {
filename: 'bundle.js',
path: './dist'
},
module: {
loaders: [
{
test: /\.js?$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['react', 'es2015']
}
},
{
test: /\.css$/,
loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'
},
{
test: /\.scss$/,
loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!sass'
}
]
}
}
还有我的 package.json
:
{
"name": "tic-tac-dux",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack-dev-server --devtool eval --progress --colors --inline --hot --content-base dist/",
"test": "jest"
},
"jest": {
"moduleNameMapper": {
"^.+\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"^.+\.(css|sass)$": "<rootDir>/__mocks__/styleMock.js"
}
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.17.0",
"babel-jest": "^16.0.0",
"babel-loader": "^6.2.5",
"babel-polyfill": "^6.16.0",
"babel-preset-es2015": "^6.16.0",
"babel-preset-react": "^6.16.0",
"css-loader": "^0.25.0",
"enzyme": "^2.4.1",
"jest": "^16.0.1",
"jest-cli": "^16.0.1",
"node-sass": "^3.10.1",
"react-addons-test-utils": "^15.3.2",
"react-dom": "^15.3.2",
"sass-loader": "^4.0.2",
"style-loader": "^0.13.1",
"webpack": "^1.13.2",
"webpack-dev-server": "^1.16.2"
},
"dependencies": {
"react": "^15.3.2",
"react-dom": "^15.3.2"
}
}
哦,如果有人要说 div 元素没有在脚本之前加载,这是我的 index.html
:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>App</title>
</head>
<body>
<div id="app"></div>
<script src="/bundle.js"></script>
</body>
</html>
这个特殊的渲染问题可能是什么原因造成的?与 15.0 的新 Jest 更新有关吗?
App.jsx
应该导出 App class 并且什么都不做,render
应该在别处调用。
如果您从 App.jsx 中删除 render
调用,错误应该会消失,但它会弹出,因为测试环境没有为 DOM 提供 app
id.
对于像我一样通过互联网进行梳理的任何其他人 - 在使用 Jest 进行测试时寻找解决方案 - 我将支持@biphobe 的答案,说 Jest 会导致此错误发生时您在调用 ReactDOM.render 的同一文件中导出某些内容。
在我的例子中,我在 index.js 中导出了一个对象,我也在其中调用了 ReactDOM.render。我删除了这个出口,瞧!
据我所知,这个错误在很多情况下都会出现,需要不同的方法来解决。我的场景和上面的例子不太一样,我用的是redux & router,虽然我一直在纠结同样的错误。帮助我解决这个问题的是将 index.js
从:
ReactDOM.render(
<Provider store={store}>
<AppRouter />
</Provider>,
document.getElementById("root")
);
registerServiceWorker();
至:
ReactDOM.render(
(<Provider store={store}>
<AppRouter/>
</Provider>),
document.getElementById('root') || document.createElement('div') // for testing purposes
);
registerServiceWorker();
我找到了针对我的用例的此错误的解决方案:使用相同的 Redux 存储 React 在 React 之外使用。
在尝试从 index.tsx
导出我的 React 的 Redux store
以便在 React 应用程序之外的其他地方使用时,我在 运行 Jest 测试时遇到了同样的错误(在 App.tsx
文件中使用 Enzyme。
错误
在测试 React 时不起作用的初始代码如下所示。
// index.tsx
import * as React from "react";
import { render } from "react-dom";
import { Provider } from "react-redux";
import { applyMiddleware, compose, createStore } from "redux";
import App from "./components/App";
import { rootReducer } from "./store/reducers";
import { initialState } from "./store/state";
const middlewares = [];
export const store = createStore(
rootReducer,
initialState,
compose(applyMiddleware(...middlewares)),
);
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root"),
);
对我有用的解决方案
将 Redux 存储逻辑分离到一个名为 store.ts
的新文件中,然后创建一个 default export
(供 index.tsx
,即 React 应用程序使用)和一个非默认用export const store
导出(从非React类使用),如下。
// store.ts
import { applyMiddleware, compose, createStore } from "redux";
import logger from "redux-logger";
import { rootReducer } from "./store/reducers";
import { initialState } from "./store/state";
const middlewares = [];
export const store = createStore(
rootReducer,
initialState,
compose(applyMiddleware(...middlewares)),
);
export default store;
// updated index.tsx
import * as React from "react";
import { render } from "react-dom";
import { Provider } from "react-redux";
import App from "./components/App";
import store from "./store";
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root"),
);
在非 React 中使用 Redux 存储 类
// MyClass.ts
import { store } from "./store"; // store.ts
export default class MyClass {
handleClick() {
store.dispatch({ ...new SomeAction() });
}
}
default
导出
出发前的小提示。以下是如何使用 default
和非默认导出。
default export store;
与import store from "./store";
一起使用
export const store = ...
与import { store } from "./store";
一起使用
希望对您有所帮助!
https://nono.ma/says/solved-invariant-violation-target-container-is-not-a-dom-element
确保在您的测试文件中您已正确导入 render 组件。
它应该从 @testing-library/react
而不是 react-dom
:
import { render } from '@testing-library/react';
好吧,我们不能阻止开发人员从任何文件导出组件并单独测试它,即使它有 react-dom import or usage in it 。我的意思是它有什么问题。我们不会试图破坏整个文件并测试它的某些部分,只要那是一段有效的代码即可。
Jest 与 react-dom 没有问题,但从概念上讲它们是 diff 。 Jest 应该是一个无浏览器的虚拟测试环境。 React-DOM 是一个将虚拟 DOM 拼接到真实 DOM 的库,用于反应组件。 很明显我们 can/should 没有以正常方式测试它。但这不是现在的讨论。只要我们导出的组件是可测试的,我们就没问题。
所以让我们嘲笑它
我在 jest config 中配置了“setupFilesAfterEnv”的 testSetup 文件中进行了模拟。
jest.mock("react-dom", () => {
return ({
"render": jest.fn()
})
})
这对我来说非常有用。我的 react 和 react-dom 代码现在可以愉快地放在一个文件中,在浏览器和测试环境中也能正常工作。
我还没有遇到任何问题。有的话我会去评论区看看