【React高级】 数据获取然后进行创建测试(使用多渲染器以及计时器)

简介: 【React高级】 数据获取然后进行创建测试(使用多渲染器以及计时器)

@[toc]

创建

对于每个测试,我们通常都希望将React树呈现给附加到文档的DOM元素。这很重要,因为它可以接收DOM事件。测试完成后,我们需要“清理”并从文档中卸载树。

import { unmountComponentAtNode } from "react-dom";

let container = null;
beforeEach(() => {
  // 创建一个 DOM 元素作为渲染目标
  container = document.createElement("div");
  document.body.appendChild(container);
});

afterEach(() => {
  // 退出时进行清理
  unmountComponentAtNode(container);
  container.remove();
  container = null;
});

一种常见的方法是使用一对beforeEach和afterEach块来保持它们运行并隔离测试本身的影响。

act(() => {
  // 渲染组件
});
// 进行断言

这有助于在使用应用程序时使测试运行更接近真实用户体验。这些示例的其余部分使用act()进行这些保证。
可能会发现直接使用act()有点过于冗长。为了避免一些样板代码,可以使用React测试库。这些助手使用act()函数封装。


import React from "react";

export default function Hello(props) {
  if (props.name) {
    return <h1>你好,{props.name}!</h1>;
  } else {
    return <span>嘿,陌生人</span>;
  }
}

数据获取

可以使用假数据模拟请求,而不是在所有测试中调用真实的API。使用“假”数据模拟数据采集可以防止由于后端不可用而导致的不稳定测试,并使其运行更快。注意:可能仍然希望使用“端到端”框架运行测试子集,以显示整个应用程序是否协同工作。


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

export default function User(props) {
  const [user, setUser] = useState(null);

  async function fetchUserData(id) {
    const response = await fetch("/" + id);
    setUser(await response.json());
  }

  useEffect(() => {
    fetchUserData(props.id);
  }, [props.id]);

  if (!user) {
    return "加载中...";
  }

  return (
    <details>
      <summary>{user.name}</summary>
      <strong>{user.age}</strong> 岁
      <br />
      住在 {user.address}
    </details>
  );
}
import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import { act } from "react-dom/test-utils";
import User from "./user";

let container = null;
beforeEach(() => {
  // 创建一个 DOM 元素作为渲染目标
  container = document.createElement("div");
  document.body.appendChild(container);
});

afterEach(() => {
  // 退出时进行清理
  unmountComponentAtNode(container);
  container.remove();
  container = null;
});

it("渲染用户数据", async () => {
  const fakeUser = {
    name: "Joni Baez",
    age: "32",
    address: "123, Charming Avenue"
  };
  jest.spyOn(global, "fetch").mockImplementation(() =>
    Promise.resolve({
      json: () => Promise.resolve(fakeUser)
    })
  );

  // 使用异步的 act 应用执行成功的 promise
  await act(async () => {
    render(<User id="123" />, container);
  });

  expect(container.querySelector("summary").textContent).toBe(fakeUser.name);
  expect(container.querySelector("strong").textContent).toBe(fakeUser.age);
  expect(container.textContent).toContain(fakeUser.address);

  // 清理 mock 以确保测试完全隔离
  global.fetch.mockRestore();
});

某些模块在测试环境中可能无法正常工作,或者对测试本身不重要。用虚拟数据模拟这些模块,更容易为代码编写测试。

多渲染器

在极少数情况下,可能在使用多个渲染器的组件上运行测试。例如, 可能正在内部使用ReactDOM的react测试渲染器组件上运行快照测试。在子组件中渲染以渲染某些内容。在此场景中,可以使用与其渲染器对应的动作()来包装更新。

import { act as domAct } from "react-dom/test-utils";
import { act as testAct, create } from "react-test-renderer";
// ...
let root;
domAct(() => {
  testAct(() => {
    root = create(<App />);
  });
});
expect(root).toMatchSnapshot();

计时器

代码可能使用基于计时器的函数(如setTimeout)来安排将来的更多工作。在此示例中,多选面板等待选择并向前移动。如果在5秒内没有选择,则超时:

import React, { useEffect } from "react";

export default function Card(props) {
  useEffect(() => {
    const timeoutID = setTimeout(() => {
      props.onSelect(null);
    }, 5000);
    return () => {
      clearTimeout(timeoutID);
    };
  }, [props.onSelect]);

  return [1, 2, 3, 4].map(choice => (
    <button
      key={choice}
      data-testid={choice}
      onClick={() => props.onSelect(choice)}
    >
      {choice}
    </button>
  ));
}

我们可以使用Jest的计时器模拟为这个组件编写测试,并测试它可能处于的不同状态。

import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import { act } from "react-dom/test-utils";

import Card from "./card";

jest.useFakeTimers();

let container = null;
beforeEach(() => {
  // 创建一个 DOM 元素作为渲染目标
  container = document.createElement("div");
  document.body.appendChild(container);
});

afterEach(() => {
  // 退出时进行清理
  unmountComponentAtNode(container);
  container.remove();
  container = null;
});

it("超时后应选择 null", () => {
  const onSelect = jest.fn();
  act(() => {
    render(<Card onSelect={onSelect} />, container);
  });

  // 提前 100 毫秒执行
  act(() => {
    jest.advanceTimersByTime(100);
  });
  expect(onSelect).not.toHaveBeenCalled();

  // 然后提前 5 秒执行
  act(() => {
    jest.advanceTimersByTime(5000);
  });
  expect(onSelect).toHaveBeenCalledWith(null);
});

it("移除时应进行清理", () => {
  const onSelect = jest.fn();
  act(() => {
    render(<Card onSelect={onSelect} />, container);
  });
  act(() => {
    jest.advanceTimersByTime(100);
  });
  expect(onSelect).not.toHaveBeenCalled();

  // 卸载应用程序
  act(() => {
    render(null, container);
  });
  act(() => {
    jest.advanceTimersByTime(5000);
  });
  expect(onSelect).not.toHaveBeenCalled();
});

it("应接受选择", () => {
  const onSelect = jest.fn();
  act(() => {
    render(<Card onSelect={onSelect} />, container);
  });

  act(() => {
    container
      .querySelector("[data-testid='2']")
      .dispatchEvent(new MouseEvent("click", { bubbles: true }));
  });

  expect(onSelect).toHaveBeenCalledWith(2);
});

只能在某些测试中使用假计时器。上面,我们调用jestUseFakeTimers()来启用它们。它们提供的主要优点是,的测试实际上不需要等待5秒才能执行,并且不需要使组件代码更复杂地进行测试。

相关文章
|
23天前
|
前端开发 JavaScript
React学习之——条件渲染
【10月更文挑战第16天】React 中没有像Vue中v-if这种指令。React 中的条件渲染和 JavaScript 中的一样,使用 JavaScript 运算符 if 或者条件运算符去创建元素来表现当前的状态,然后让 React 根据它们来更新 UI。
|
1月前
|
前端开发 JavaScript 容器
React 元素渲染
10月更文挑战第7天
23 1
|
28天前
|
监控 前端开发 UED
在 React 18 中利用并发渲染提高应用性能
【10月更文挑战第12天】利用并发渲染需要综合考虑应用的特点和需求,合理运用相关特性和策略,不断进行优化和调整,以达到最佳的性能提升效果。同时,要密切关注 React 的发展和更新,以便及时利用新的技术和方法来进一步优化应用性能。你还可以结合具体的项目实践来深入理解和掌握这些方法,让应用在 React 18 的并发渲染机制下发挥出更好的性能优势。
104 59
|
14天前
|
前端开发 JavaScript 安全
学习如何为 React 组件编写测试:
学习如何为 React 组件编写测试:
32 2
|
16天前
|
前端开发 JavaScript 测试技术
React 模拟测试与 Jest
【10月更文挑战第21天】本文介绍了如何使用 Jest 进行 React 组件的单元测试和模拟测试,涵盖了基础概念、常见问题及解决方案,并提供了实践案例。通过学习本文,你将掌握如何有效地使用 Jest 提高代码质量和稳定性。
28 1
|
20天前
|
JavaScript 前端开发 算法
前端优化之超大数组更新:深入分析Vue/React/Svelte的更新渲染策略
本文对比了 Vue、React 和 Svelte 在数组渲染方面的实现方式和优缺点,探讨了它们与直接操作 DOM 的差异及 Web Components 的实现方式。Vue 通过响应式系统自动管理数据变化,React 利用虚拟 DOM 和 `diffing` 算法优化更新,Svelte 通过编译时优化提升性能。文章还介绍了数组更新的优化策略,如使用 `key`、分片渲染、虚拟滚动等,帮助开发者在处理大型数组时提升性能。总结指出,选择合适的框架应根据项目复杂度和性能需求来决定。
|
28天前
|
存储 测试技术 数据库
数据驱动测试和关键词驱动测试的区别
数据驱动测试 数据驱动测试或 DDT 也被称为参数化测试。
|
1月前
|
前端开发 JavaScript 算法
React 渲染优化策略
【10月更文挑战第6天】React 是一个高效的 JavaScript 库,用于构建用户界面。本文从基础概念出发,深入探讨了 React 渲染优化的常见问题及解决方法,包括不必要的渲染、大量子组件的渲染、高频事件处理和大量列表渲染等问题,并提供了代码示例,帮助开发者提升应用性能。
50 6
|
1月前
|
SQL 分布式计算 Hadoop
Hadoop-14-Hive HQL学习与测试 表连接查询 HDFS数据导入导出等操作 逻辑运算 函数查询 全表查询 WHERE GROUP BY ORDER BY(一)
Hadoop-14-Hive HQL学习与测试 表连接查询 HDFS数据导入导出等操作 逻辑运算 函数查询 全表查询 WHERE GROUP BY ORDER BY(一)
35 4
|
1月前
|
SQL 消息中间件 大数据
大数据-159 Apache Kylin 构建Cube 准备和测试数据(一)
大数据-159 Apache Kylin 构建Cube 准备和测试数据(一)
47 1