React 测试笔记 02 - 异步 UI 及 Mock API

React 测试笔记 02 - 异步 UI 及 Mock API

上一篇: React 测试笔记 01 - 基础 UI 类

这里的功能函数基本为异步操作,以 React Testing Library 和 msw 为主要依赖。

UI 操作

大多数的 UI 操作是即时的,如上一篇提到的点击事件、输入事件,但是也有那么一两个特殊情况,其中一个就包括从 DOM 中移除元素。

同步情况下 query 元素使用的函数以 getBy 开头,如 getByLabelText, getByPlaceholderText 等,异步函数 query 元素则需要使用另一个函数:findBy。以官方文档 Async Methods 中的案例来说,假设元素,如 Modal, Popup, tooltip 等需要被在用户 unhover 或 click 之后消失,测试方法如下:

// 非 React,直接 JS 操作 DOM
const el = document.querySelector("div.getOuttaHere");// 注意这里使用的了 waitForElementToBeRemoved
waitForElementToBeRemoved(document.querySelector("div.getOuttaHere")).then(() =>console.log("Element no longer in DOM")
);el.setAttribute("data-neat", true);
// other mutations are ignored...el.parentElement.removeChild(el);
// logs 'Element no longer in DOM'

使用 waitForElementToBeRemoved 就不需要再使用 Jest 的 expect 函数去进行断言操作,其本身会返回一个 Promise,在 Jest 中直接会被测试。

以 Popup 为案例,使用 React Testing Library, Jest 和 React 写的一个测试代码为:

// async 是必须的,因为需要 await waitForElementToBeRemoved
test("popover responds to hover", async () => {// 我将 render() 这部分抽离到了另一个函数里initialization();const btn = screen.getByRole("button");const nullModal = screen.queryByText(/Terms and conditions/i);expect(nullModal).not.toBeInTheDocument();userEvent.click(userEvent);await waitForElementToBeRemoved(screen.queryByText(/Terms and conditions/i));
});

基本上来说,90%的 case 是可以被 getBy 解决的,但是在确定逻辑是正确的情况下,做了 E2E 测试发现也没有问题,那可能就代表这个操作时异步的,需要使用 queryBy 搭配 async/await 与 waitFor 去进行测试。

Mock API

这里使用的另一个包是 msw,官方文档提供了配置方法,主要就是自己需要写一个 mock 文件触发 mocking server,并且要手写一堆 handler 去进行 mocking。使用 CRA 的情况下几乎不怎么需要配置,需要修改的文件包括:

  • setupTests.js (CRA 原本就提供的文件)

    // 新增内容如下
    // src/setupTests.js
    import { server } from "./mocks/server.js";
    // Establish API mocking before all tests.
    beforeAll(() => server.listen());// Reset any request handlers that we may add during the tests,
    // so they don't affect other tests.
    afterEach(() => server.resetHandlers());// Clean up after the tests are finished.
    afterAll(() => server.close());
    
  • mocks/handlers

    这里导出的是一个 RESTful API,msw 也提供 GraphQL 的 mock

    import { rest } from "msw";export const handlers = [rest.get("http://localhost:3030/testa", (req, res, ctx) => {return res(ctx.json([{}, {}]));}),rest.get("http://localhost:3030/testb", (req, res, ctx) => {return res(ctx.json([]));}),
    ];
    

    req, res, ctx 的作用与 express 中的 server 基本差不多,这里不多赘述。

  • mocks/server.js

    msw 的配置,主要是设置 server

    // src/mocks/server.js
    import { setupServer } from "msw/node";
    import { handlers } from "./handlers";// This configures a request mocking server with the given request handlers.
    export const server = setupServer(...handlers);
    

配置完成之后就可以在测试中调用 mock APIs 了。

介于 API 操作肯定都是异步操作,在测试文件中 query 元素也需要使用 async/await + findBy 这样的组合。

Mock API Exception

mocks/handlers 中返回的都是正常的 json 格式,有些 UI 测试也会要求对 exception 进行测试,如 404 要重定向到 404 文件,403 重定向到对应页面或显示用户没有权限。

handlers 可以在测试文件内进行重写,如:

test("handles error for sccops and toppings routes", async () => {server.resetHandlers(rest.get("http://localhost:3030/testa", (req, res, ctx) => {return res(ctx.status(404));}),rest.get("http://localhost:3030/testb", (req, res, ctx) => {return res(ctx.status(403));}));render(<Element />);
});

这时候 Element 中的 API 再去 fetch 的时候,testa 所获取的状态码就是 404,testb 所获取的状态码是 403,这时候也可以测试对应的 UI 反应。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部