簡體   English   中英

無法使用 Jest 和 Testing-Library 測試 React 組件渲染,因為 Jest 沒有可用的文檔

[英]Trouble testing React component render with Jest and Testing-Library because there's no Document available to Jest

上下文/設置:

我正在嘗試使用 Jest 和 React-Testing-Library 來測試 React 組件 <Main/> 的呈現,但是當我運行測試時,處理fetchclient會拋出錯誤,因為它正在使用document.querySelector() -但是當 Jest 運行時沒有document ,因為沒有呈現瀏覽器。

我的目標是:設置 Jest 和 RTL,以便我們可以開始為所有組件編寫測試。 我想首先驗證我可以無錯誤地渲染<Main/>

這是Client.js

class Client {
  constructor() {
    console.log("Client initializing")
    console.log(document.querySelector('meta[name="csrf-token"]'))
    console.log(document)

    this.token = document.querySelector('meta[name="csrf-token"]').content;
    
  }

  getData(path) {
    return (
      fetch(`${window.location.origin}${path}`, {
        headers: { "X-CSRF-Token": this.token }
      })
    )
  }

  submitData(path, method, body) {
    return (
      fetch(`${window.location.origin}${path}`, {
        method: method,
        headers: { "X-CSRF-Token": this.token },
        body: body
      })
    )
  }

  deleteData(path) {
    return (
      fetch(`${window.location.origin}${path}`, {
        method: "DELETE",
        headers: {
          "X-CSRF-Token": this.token,
          "Content-Type": "application/json"
        }
      })
    )
  }

}
export default Client;

這是main.test.js

/**
 * @jest-environment jsdom
 */

import React from 'react';
import { render, screen } from '@testing-library/react';
// import userEvent from '@testing-library/user-event';
import Main from '../../app/javascript/components/Main';

test("renders without errors", ()=> {
    render(<Main/>);

});

我還設置了一個setupTests.js文件:


require("jest-fetch-mock").enableMocks();
import '@testing-library/jest-dom';

並在package.json中調用它:

"jest": {
        "roots": [
            "test/javascript"
        ],
        "moduleNameMapper": {
            "\\.(svg|png)": "<rootDir>/__mocks__/svgrMock.js"
        },
        "automock": false,
        "setupFilesAfterEnv": [
            "./test/javascript/setupTests.js"
        ]
    },

我還在jest.config.js文件中設置了 testEnvironment testEnvironment: 'jsdom'

當前問題:

當我運行yarn jest時,出現以下錯誤: TypeError: Cannot read properties of null (reading 'content') which points to this.token = document.querySelector('meta[name="csrf-token"]').content; Client.js

這對我來說很有意義,因為它正在尋找 DOM 元素,但是 Jest 在 Node 中運行(沒有瀏覽器渲染)所以找不到 DOM。

我需要:

  1. 模擬document ,以便應用程序可以在不在瀏覽器中呈現的情況下運行。 不知道該怎么做。
  2. 然后模擬提取調用(也許?)不知道該怎么做。

到目前為止我嘗試過的:

1. 我已經嘗試了各種方法來全局模擬 DOM 元素(來自setupTests.js ),包括許多類似這樣的排列:

import { TextDecoder, TextEncoder } from 'util'
global.TextEncoder = TextEncoder
global.TextDecoder = TextDecoder

//variables to mock a csrf token
const csrfToken = 'abcd1234';
const virtualDom = `
<!doctype html>
    <head>
        <meta name="csrf-token" content="${csrfToken}" />
    </head>
  <body>
    <form>
        <input type="hidden" name="csrf-token" value=${csrfToken}>
      </form>
  </body>
</html>
`;

const { JSDOM } = require("jsdom");
//mock a page passing virtualDom to JSDOM
const page = new JSDOM(virtualDom);

const { window } = page;

function copyProps(src, target) {
    const props = Object.getOwnPropertyNames(src)
      .filter(prop => typeof target[prop] === 'undefined')
      .map(prop => Object.getOwnPropertyDescriptor(src, prop));
    Object.defineProperties(target, props);
  }

global.window = window;
global.document = window.document;
global.navigator = {
  userAgent: 'node.js',
};
copyProps(window, global);

但是global.window = window似乎從來沒有工作,因為如果我聲明然后立即console.log(global.window, window)我得到 null 然后是 window。

2. 我已經嘗試將 React 18 暫時降級到 React 17(基於一些 StackOverflow 交換)——我知道這不是最佳選擇,但它讓我到了至少必須模擬 fetch() 調用的地步。

我也不知道如何正確地做到這一點,但我也知道降級 React 可能是錯誤的路徑。

其他可能重要的上下文:

  • 這個 React 前端是 Rails 應用程序 (webpack) 的一部分。
  • 使用yarn
  • 我對我們如何實現這一點有很多控制權,所以我正在尋找最簡單/最干凈的方法來做到這一點。

Jest 在后台使用jsdom ,所以“沒有 DOM”是不正確的,但是所有頁面都在測試中實例化了 - 沒有來自服務器的東西(並且jsdom既不支持導航以從服務器請求真實頁面然后繼續測試).

因此我們需要在測試中渲染元素:

render(<>
  <meta name="csrf-token" content="mocked-token" />
  <Main/>
</>);

雖然我不確定為什么您在 globalSetup 中嘗試的完整頁面替換不起作用,但也許 Jest 不允許以這種方式覆蓋 JSDOM 實例並且在運行 globalSetup.js 之前綁定。

事實證明,我必須模擬所有進入從 Main 呈現的組件的數據。 (除了 CSRF 令牌模擬)

一旦我這樣做了,其他一切就都到位了。

暫無
暫無

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

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