簡體   English   中英

測試 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>

這種特殊的渲染問題可能是什么原因? 與 Jest 15.0 的新更新有關嗎?

對於像我一直在通過互聯網進行梳理的其他任何人 - 在使用 Jest 進行測試時尋找解決方案 - 我將支持 @biphobe 的答案,說 Jest 會在您導出內部內容時發生此錯誤調用 ReactDOM.render 的同一個文件。

在我的例子中,我在我的 index.js 中導出了一個對象,我也在其中調用了 ReactDOM.render。 我刪除了這個出口,瞧!

App.jsx應該導出 App 類並且什么都不做,應該在其他地方調用render

如果您從 App.jsx 中刪除render調用,錯誤應該消失,它會彈出,因為測試環境沒有為 DOM 提供app ID。

正如我所看到的,這個錯誤在很多情況下都會出現,需要不同的方法來解決它。 我的場景與上面的示例不同,我使用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 應用程序之外的其他地方使用時,我在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

確保在您的測試文件中已經很好地導入了渲染組件。 它應該從@testing-library/react導入,而不是從react-dom導入:

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

好吧,我們不能阻止開發人員從任何文件中導出組件並單獨測試它,即使它有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 代碼現在很高興地放在一個文件中,可以在瀏覽器和測試環境中運行。

因此,我沒有遇到任何問題。 有的話我會看評論區

這個解決方案對我有用。 如果元素存在,只需渲染:

const root = document.getElementById('root');
if (root) {
    render(
        <App />,
        root,
    );
}

我發現在測試中使用Portals時也會引發此錯誤。 如果您想跳過錯誤,您可以mock Portals或在您的渲染方法中添加Portal容器元素:

render (
  <div>
    <TestedComponent />
    <div id="portal" />
  </div>
)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM