5

当用户在输入搜索中键入一些文本时 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"));
  });
});
4

1 回答 1

0

您可以模拟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
于 2021-07-26T03:39:10.140 回答