React Test-组件访问窗口对象时错误

发布于 2025-02-01 04:33:22 字数 2217 浏览 3 评论 0原文

由于特定原因,我在index.html文件中使用脚本 public 文件夹中,此脚本在window> window对象上创建属性。该属性是异步函数。这是我在public/index.html中创建的脚本:

 <script>
      const txt = "Hello Word";

      async function waitText() {
        try {
          const data = await fetch(
            "https://jsonplaceholder.typicode.com/all/1"
          );
          const text = await data.json();
          returntext;
        } catch (error) {
          console.error(error);
          return "Error";
        }
      }

      Object.defineProperty(window, "waitText", { value: waitText });
    </script>

我的应用程序组件首先渲染加载...在USESTATE中指定的文本,然后在使用效果中的异步函数调用Windom对象的功能,等待响应并执行响应固定状态并更改加载...文本为从API获得的文本。到目前为止,该应用程序毫无问题地工作。在这里,app.tsx的代码

import logo from "./logo.svg";
import "./App.css";
import { useEffect, useState } from "react";

function App() {
  const [txt, setTxt] = useState("Loading...");

  useEffect(() => {
    const getTxt = async() => {
      try {
        const text = await window.waitText();
        setTxt(text.title);
      } catch (error) {
        console.error(error);
      }
    };

    getTxt();
  }, []);

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>{txt}</p>
      </header>
    </div>
  );
}

export defaultApp;

到目前为止,应用程序正常运行。问题是用开玩笑和反应测试图表进行测试。在这里,文本的代码:

import { render, screen } from '@testing-library/react';
import App from './App';

test('renders learn react link', async () => {
  render(<App />);
    screen.debug()
  const linkElement = await screen.findByText("delectus aut autem");
  expect(linkElement).toBeInTheDocument();
});

运行此测试时,在呼叫window.waittext()时专门在使用效率区域中引起错误。显然,当执行嘲笑测试时,它不会执行索引中的脚本。

从public/index.html中删除脚本不是解决方案。很好,尽管这不是一个好的做法,但在某些情况下,有必要这样做。

创建反应的文档对此表示了:

某些库可能与webpack不相容,您别无选择,您别无选择但是将其包括在标签中。

无论如何,如何使该组件通过测试?

For a specific reason I use a script in the index.html file in the public folder, this script creates a property on the window object. The property is an asynchronous function. here is the script i created in public/index.html:

 <script>
      const txt = "Hello Word";

      async function waitText() {
        try {
          const data = await fetch(
            "https://jsonplaceholder.typicode.com/all/1"
          );
          const text = await data.json();
          returntext;
        } catch (error) {
          console.error(error);
          return "Error";
        }
      }

      Object.defineProperty(window, "waitText", { value: waitText });
    </script>

My App component starts by rendering a Loading... text specified in a useState, then an asynchronous function in useEffect calls the function of the windom object, waits for the response and does the setState and changes the Loading... text to the one it got from the api. So far the app works without problems. Here the code of App.tsx

import logo from "./logo.svg";
import "./App.css";
import { useEffect, useState } from "react";

function App() {
  const [txt, setTxt] = useState("Loading...");

  useEffect(() => {
    const getTxt = async() => {
      try {
        const text = await window.waitText();
        setTxt(text.title);
      } catch (error) {
        console.error(error);
      }
    };

    getTxt();
  }, []);

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>{txt}</p>
      </header>
    </div>
  );
}

export defaultApp;

Up to this point the app works fine. The problem is to do the test with jest and react-testing-library. Here the code of the text:

import { render, screen } from '@testing-library/react';
import App from './App';

test('renders learn react link', async () => {
  render(<App />);
    screen.debug()
  const linkElement = await screen.findByText("delectus aut autem");
  expect(linkElement).toBeInTheDocument();
});

When running this test, an error is raised in the useEffect area specifically when calling window.waitText(). Apparently when executing the jest test it does not execute the script that is in the index.html and therefore the property is never created in the window object, consequently an error arises in the useEffect and the text does not work.

Removing the script from public/index.html is not a solution. Well, although it is not a good practice, there are certain cases in which it is necessary to do so.

The create-react-app documentation says about this:

Some libraries may be incompatible with webpack and you have no choice but to include it as a tag.

Anyway, how to make this component pass the test?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

沉鱼一梦 2025-02-08 04:33:22

您可以模拟window.waittext()方法及其在测试案例中呈现组件之前的解决/拒绝值。

例如

app.jsx

import { useEffect, useState } from 'react';
import React from 'react';

function App() {
  const [txt, setTxt] = useState('Loading...');

  useEffect(() => {
    const getTxt = async () => {
      try {
        const text = await window.waitText();
        setTxt(text.title);
      } catch (error) {
        console.error(error);
      }
    };

    getTxt();
  }, []);

  return (
    <div className="App">
      <header className="App-header">
        <p>{txt}</p>
      </header>
    </div>
  );
}

export default App;

app.test.jsx

import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import React from 'react';
import App from './App';

test('renders learn react link', async () => {
  Object.defineProperty(window, 'waitText', { value: () => Promise.resolve({ title: 'delectus aut autem' }) });
  render(<App />);
  const linkElement = await screen.findByText('delectus aut autem');
  expect(linkElement).toBeInTheDocument();
});

测试结果:

 PASS  stackoverflow/72355656/App.test.jsx (13.14 s)
  ✓ renders learn react link (33 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |   92.31 |      100 |     100 |   91.67 |                   
 App.jsx  |   92.31 |      100 |     100 |   91.67 | 13                
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        14.9 s, estimated 15 s

You can mock the window.waitText() method and its resolve/rejected value before rendering the component in the test case.

E.g.

App.jsx:

import { useEffect, useState } from 'react';
import React from 'react';

function App() {
  const [txt, setTxt] = useState('Loading...');

  useEffect(() => {
    const getTxt = async () => {
      try {
        const text = await window.waitText();
        setTxt(text.title);
      } catch (error) {
        console.error(error);
      }
    };

    getTxt();
  }, []);

  return (
    <div className="App">
      <header className="App-header">
        <p>{txt}</p>
      </header>
    </div>
  );
}

export default App;

App.test.jsx:

import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import React from 'react';
import App from './App';

test('renders learn react link', async () => {
  Object.defineProperty(window, 'waitText', { value: () => Promise.resolve({ title: 'delectus aut autem' }) });
  render(<App />);
  const linkElement = await screen.findByText('delectus aut autem');
  expect(linkElement).toBeInTheDocument();
});

Test result:

 PASS  stackoverflow/72355656/App.test.jsx (13.14 s)
  ✓ renders learn react link (33 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |   92.31 |      100 |     100 |   91.67 |                   
 App.jsx  |   92.31 |      100 |     100 |   91.67 | 13                
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        14.9 s, estimated 15 s
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文