测试React:目标容器不是DOM元素

时间:2016-10-11 20:29:10

标签: javascript reactjs ecmascript-6 tdd

我试图在使用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>

造成这种特殊渲染问题的原因是什么?与新的Jest更新到15.0有什么关系?

5 个答案:

答案 0 :(得分:25)

App.jsx应该导出App类而不再执行任何操作,render应该在别处调用。

如果从App.jsx中删除render调用错误消失,则会弹出,因为测试环境不会为DOM提供app id。

答案 1 :(得分:21)

对于正在通过互联网梳理的其他任何人 - 在使用Jest测试时寻找解决方案 - 我将通过@biphobe支持Jest将导致此错误的答案您导出调用ReactDOM.render的同一文件内的东西。

就我而言,我在index.js中导出一个对象,我也在那里调用ReactDOM.render。我删除了这个导出,瞧!

答案 2 :(得分:7)

如我所见,此错误在许多情况下都会出现,并且需要使用不同的方法来解决。我的场景与上面的示例不同,尽管我正遇到相同的错误,但我使用的是 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();

答案 3 :(得分:1)

我为我的用例找到了解决此错误的解决方案:使用相同的Redux存储区,而React正在外部使用。

试图从store导出我的React的Redux index.tsx以便在React应用程序之外的其他地方使用时,我在运行Jest测试(使用Enzyme)时遇到了相同的错误。 App.tsx文件。

错误

测试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

答案 4 :(得分:0)

确保在测试文件中已正确导入 render 组件。 应该从@testing-library/react而不是从react-dom导入:

import { render } from '@testing-library/react';