【问题标题】:Testing React: Target Container is not a DOM element测试 React:目标容器不是 DOM 元素
【发布时间】:2017-02-20 12:31:56
【问题描述】:

我正在尝试在使用 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 行,这是 &lt;App /&gt; 的导入,导致失败。堆栈跟踪显示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 的新更新有关吗?

【问题讨论】:

    标签: javascript reactjs ecmascript-6 tdd


    【解决方案1】:

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

    在我的例子中,我在我的 index.js 中导出了一个对象,我也在其中调用了 ReactDOM.render。我删除了这个出口,瞧!

    【讨论】:

    • 谢谢,这正是我想要的。明确提到调用ReactDOM.render() 正是我需要了解确切问题的原因!
    • 很高兴它有帮助!
    • 我在我的测试中尝试导入操作时遇到了类似的问题。不幸的是,删除 ReactDom 并没有帮助
    • @PraveenSrinivasan 我在尝试调用 ReactDOM.render 并在同一个 javascript 文件中导出某些内容时遇到了 Jest 问题。
    • 啊,是的!谢谢。我在使用ReactDom.render 的条目文件中添加了一个对象的导出。但是该文件还没有测试。
    【解决方案2】:

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

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

    【讨论】:

    • 我得到了同样的错误:- 我用 ava 进行了测试.. 请告诉我我应该在哪里出错.. export default class App extends Component { render() { return (
      {this.props .children}
      ) } } render(( ), document.getElementById('app'));
    • @BhavikKheni 请创建新问题并在其中包含您的完整代码以及错误和堆栈跟踪。
    • 如果不在 App.jsx 中,应该在哪里调用?
    【解决方案3】:

    正如我所见,这个错误在很多情况下都会出现,需要不同的方法来解决它。我的场景与上面的示例不同,我使用 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();
    

    【讨论】:

    • 非常有帮助的答案——虽然令人沮丧,因为我不知道这是否是受支持的方式;不知道是不是因为我们使用了Provider?
    • 从“双引号”更改为“单引号”对我有用,谢谢!!
    • @bibangamba 我很惊讶这很重要。你能详细说明一下吗?
    【解决方案4】:

    我为我的用例找到了解决此错误的方法:使用 React 外部使用的相同 Redux 存储。

    在尝试从 index.tsx 导出我的 React 的 Redux store 以在 React 应用程序之外的其他地方使用时,我在 App.tsx 中运行 Jest 测试(使用 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

    【讨论】:

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

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

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

    【讨论】:

      【解决方案6】:

      我们不能阻止开发人员从任何文件中导出组件并单独测试它,即使它有 react-dom 导入或使用。我的意思是有什么问题。我们不会试图干扰整个文件并测试其中的一些片段,只要那是一段有效的代码。

      Jest 对 react-dom 没有问题,但在概念上它们是 diff 。 Jest 应该是一个无浏览器的虚拟测试环境。 React-DOM 是一个将虚拟 DOM 拼接到真实 DOM 以用于反应组件的库。 如此明显,我们可以/不应该以正常方式对其进行测试。但这不是现在的讨论。只要我们导出的组件是可测试的,我们就可以了。

      让我们模拟一下

      我在 jest config 中配置了“setupFilesAfterEnv”的 testSetup 文件中进行了模拟。

      jest.mock("react-dom", () => {
          return ({
              "render": jest.fn()
          })
      })
      

      这对我来说非常有用。我的 react 和 react-dom 代码现在很高兴地放在一个文件中,可以在浏览器和测试环境中运行。

      因此我没有遇到任何问题。有的话我会去评论区看看

      【讨论】:

        猜你喜欢
        • 2020-09-28
        • 1970-01-01
        • 2022-10-09
        • 2014-07-19
        • 2014-12-12
        • 1970-01-01
        • 2017-11-24
        • 2019-01-16
        相关资源
        最近更新 更多