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

IT技术 javascript reactjs ecmascript-6 tdd
2021-04-02 19:53:29

我正在尝试在使用 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)

测试文件引用<App />了导致失败的第 4 行,它是 的导入堆栈跟踪说第 14 行App.js是失败的原因——这只不过是来自 的渲染调用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 更新有关吗?

6个回答

对于像我一样通过互联网梳理的其他任何人 - 在使用 Jest 进行测试时寻找解决方案 - 我将通过@bophobe 支持答案,说 Jest 会在您导出某些内容时导致此错误发生调用 ReactDOM.render 的同一个文件。

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

很高兴它有帮助!
2021-05-25 19:53:29
谢谢,这正是我要找的。明确提到调用ReactDOM.render()正是我需要了解的确切问题!
2021-05-31 19:53:29
没错!谢谢。我将对象的导出添加到使用ReactDom.render. 但目前还没有针对该文件的测试。
2021-06-03 19:53:29
@PraveenSrinivasan 当我尝试调用 ReactDOM.render 并在同一个 javascript 文件中导出某些内容时,我遇到了 Jest 的问题。
2021-06-11 19:53:29
尝试在我的测试中导入操作时,我遇到了类似的问题。不幸的是,删除 ReactDom 没有帮助
2021-06-19 19:53:29

App.jsx应该导出 App 类,什么也不做,render应该在别处调用。

如果render从 App.jsx 中删除调用错误应该消失,它会弹出,因为测试环境没有为 DOM 提供appid。

@BhavikKheni 请创建新问题,并在其中包含您的完整代码以及错误和堆栈跟踪。
2021-05-23 19:53:29
我遇到了同样的错误:- 我用 ava 测试过 .. 请告诉我我应该在哪里出错.. 导出默认类 App extends Component { render() { return ( <div> {this.props.children} </div> ) } } render(( <Router history={browserHistory}> <Route path="/" component={App}> <IndexRoute component={Index} /> <Route path="page1" component={Page1} /> < Route path="page2" component={Page2} /> </Route> </Router> ), document.getElementById('app'));
2021-05-24 19:53:29
如果不是在 App.jsx 中,应该在哪里调用它?
2021-06-16 19:53:29

正如我所见,这个错误在很多情况下都会出现,需要不同的方法来解决。我的场景与上面的示例不同,我使用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();
@bibangamba 我很惊讶这很重要。你能详细说明一下吗?
2021-05-29 19:53:29
非常有用的答案——虽然令人沮丧,因为我不知道这是否是受支持的方式;不知道是不是因为我们用的是Provider?
2021-06-13 19:53:29
从“双引号”更改为“单引号”对我有用,谢谢!!
2021-06-17 19:53:29

我为我的用例找到了针对此错误的解决方案:使用 React 在 React 之外使用的相同 Redux 存储。

在尝试汇出我的阵营的终极版storeindex.tsx使用别的地方以外的应用做出react,我得到了同样的错误,同时运行玩笑测试(其中利用酶)中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 应用程序使用)和一个非默认导出 with 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

感谢您的问题@IvOv。我一年前写了这篇文章,这似乎是重点。我将不得不再次测试它,但据我所知,访问与 React 访问相同的商店对我不起作用,这就是我必须使用此解决方法的原因。
2021-05-26 19:53:29
这不会导致创建两个商店吗?
2021-06-02 19:53:29
这为我解决了它!非常感谢这个解决方案 :) 关于这个解决方案的问题,如果我们在“MyClass.ts”和“index.ts”中都导入“stores”,这是否意味着调用 createStore() 两次?谢谢!@不,不
2021-06-03 19:53:29
我们不能import store from "./store";在我们的非 React 文件中使用吗?因此,避免了 store.ts 中非默认导出的需要
2021-06-14 19:53:29
这是给我的。它涉及一些重构以store从 index.tsx 中删除创建,但是一旦我将它移动到它自己的文件中,并从那里导入,测试就通过了。为什么不像从 index.tsx/js 导出的 store 开玩笑?
2021-06-15 19:53:29

确保在您的测试文件中您已经很好地导入了渲染组件。它应该从而@testing-library/react不是从react-dom以下导入

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