reactjs 使用Jest和Testing-Library测试React组件呈现时出现问题,因为没有可用于Jest的文档

osh3o9ms  于 2023-01-02  发布在  React
关注(0)|答案(1)|浏览(244)

上下文/设置:

我尝试使用Jest和React-Testing-Library来测试React组件的呈现,但是当我运行测试时,处理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: 'jsdom'

当前问题:

当我运行yarn jest时,我得到以下错误:指向Client.js中的this.token = document.querySelector('meta[name="csrf-token"]').content;TypeError: Cannot read properties of null (reading 'content')
这对我来说是有意义的,因为它正在寻找一个DOM元素,但是Jest在Node中运行(没有浏览器呈现),所以找不到DOM。
我 * 认为 * 我需要:
1.模拟document,这样应用程序就可以运行而不会在浏览器中呈现。不确定如何做到这一点。
1.然后模拟获取调用(也许?)不知道如何做到这一点。

目前为止我所尝试的:

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,然后是一个窗口。

2.我尝试过暂时将React 18降级到React 17(基于一些StackOverflow交换)--我知道这不是最佳的,但它让我不得不至少模拟fetch()调用。

我不知道如何正确地做到这一点,但我也知道降级React可能是错误的道路在这里。

其他可能重要的上下文:

  • 这个React前端是Rails应用程序(webpack)的一部分。
  • 使用yarn
  • 我对如何实现这一目标有很大的控制权,所以我在寻找最简单/最干净的方法。
mftmpeh8

mftmpeh81#

Jest使用了jsdom,所以“没有DOM”不是真的,但是所有的页面都在测试中示例化了--没有来自服务器的东西(jsdom也不支持导航,从服务器请求真实的页面,然后继续测试)。
因此,我们需要在测试中呈现元素:

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

虽然我不知道为什么您在globalSetup中尝试的完全页面替换不起作用,但可能Jest不允许以这种方式覆盖JSDOM示例,并且在globalSetup.js运行之前就绑定了。

相关问题