如何使用 swr 编写测试

问题描述

用户在输入搜索中输入一些文本时,必须删除 data-testid = 'loading',现在控制台返回 Unable to find an element by: [data-testid="loading"] 有人可以建议我用 swr 编写测试或建议我如何模拟 swr 的响应

这是我的组件文件

import axios from "axios";
import { useEffect,useState } from "react";
import useSWR from "swr";
import "./styles.css";

const useDebounce = (newValue) => {
  const [value,setValue] = useState("");
  useEffect(() => {
    const timeout = setTimeout(() => {
      setValue(newValue);
    },500);
    return () => clearTimeout(timeout);
  },[newValue]);
  return value;
};

export const fetcher = async (url) => {
  const { data } = await axios.get(url);
  return data;
};
export default function App() {
  const [query,setQuery] = useState("react");
  const searchQuery = useDebounce(query);
  const { data: repos } = useSWR(
    `https://api.github.com/search/repositories?q=${searchQuery}&per_page=1&page=1`,fetcher
  );
  return (
    <div className="App">
      <h1>Hello CodeSandBox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <input
        testId="search"
        data-testid="search"
        id="search-input"
        placeholder="search"
        onChange={(event) => setQuery(event.target.value)}
      />
      {!repos ? (
        <div data-testid="loader" testId="loader">
          <h2 id="loading">loading</h2>
        </div>
      ) : (
        repos?.items?.map((user) => {
          return (
            <div
              data-testid="repo-item"
              style={{
                margin: "1rem",height: "40px",background: "lightpink"
              }}
            >
              {user.name}
            </div>
          );
        })
      )}
    </div>
  );
}

这是我的测试文件

import {
  render,screen,waitForElementToBeRemoved
} from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import App from "./App";
import { act } from "react-dom/test-utils";

describe("test",() => {
  beforeEach(() => {
    jest.resetAllMocks();
    jest.usefaketimers();
  });
  it("happy render",() => {
    expect(() => render(<App />)).not.toThrow();
  });

  it("renders after search",async () => {
    render(<App />);
    userEvent.type(screen.getByTestId("search"),"vue");
    act(() => {
      jest.runAllTimers();
    });
    await waitForElementToBeRemoved(() => screen.getByTestId("loader"));
  });
});

解决方法

您可以模拟 axios.get() 方法及其已解决/拒绝的值,而不是模拟 useSWR 钩子。然后,测试组件的行为,例如返回数据时呈现什么,以及在没有数据可用时呈现什么。

例如

App.tsx

import axios from 'axios';
import React from 'react';
import { useEffect,useState } from 'react';
import useSWR from 'swr';

const useDebounce = (newValue) => {
  const [value,setValue] = useState('');
  useEffect(() => {
    const timeout = setTimeout(() => {
      setValue(newValue);
    },500);
    return () => clearTimeout(timeout);
  },[newValue]);
  return value;
};

export const fetcher = async (url) => {
  const { data } = await axios.get(url);
  return data;
};

export default function App() {
  const [query,setQuery] = useState('react');
  const searchQuery = useDebounce(query);
  const { data: repos } = useSWR(
    `https://api.github.com/search/repositories?q=${searchQuery}&per_page=1&page=1`,fetcher
  );
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <input
        data-testid="search"
        id="search-input"
        placeholder="search"
        onChange={(event) => setQuery(event.target.value)}
      />
      {!repos ? (
        <div data-testid="loader">
          <h2 id="loading">loading</h2>
        </div>
      ) : (
        repos?.items?.map((user) => {
          console.log('user: ',user);
          return (
            <div key={user.id} data-testid="repo-item">
              {user.name}
            </div>
          );
        })
      )}
    </div>
  );
}

App.test.tsx

import React from 'react';
import { render,screen,waitForElementToBeRemoved } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import App from './App';
import { act } from 'react-dom/test-utils';
import axios from 'axios';

describe('test',() => {
  beforeEach(() => {
    jest.clearAllMocks();
    jest.useFakeTimers();
  });
  it('happy render',() => {
    expect(() => render(<App />)).not.toThrow();
  });

  it('renders after search',async () => {
    jest.spyOn(axios,'get').mockResolvedValueOnce({
      data: {
        items: [
          { id: 1,name: 'react' },{ id: 2,name: 'jestjs' },],},});
    render(<App />);
    userEvent.type(screen.getByTestId('search'),'vue');
    act(() => {
      jest.runAllTimers();
    });
    await waitForElementToBeRemoved(() => screen.getByTestId('loader'));
  });
});

测试结果:

 PASS  examples/67958776/App.test.tsx (8.166 s)
  test
    ✓ happy render (42 ms)
    ✓ renders after search (58 ms)

  console.log
    user:  { id: 1,name: 'react' }

      at examples/67958776/App.tsx:45:19
          at Array.map (<anonymous>)

  console.log
    user:  { id: 2,name: 'jestjs' }

      at examples/67958776/App.tsx:45:19
          at Array.map (<anonymous>)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |       80 |     100 |     100 |                   
 App.tsx  |     100 |       80 |     100 |     100 | 44                
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed,1 total
Tests:       2 passed,2 total
Snapshots:   0 total
Time:        8.873 s

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...