React Vitest App 测试中没有调用 Mock

问题描述 投票:0回答:1

我有这个 React 组件:

import React, { useState, useEffect } from "react";
import { BrowserRouter } from "react-router-dom";
import "./App.css";
import Home from "./Home";
import SnackOrBoozeApi from "./Api";
import NavBar from "./NavBar";
import { Route, Routes } from "react-router-dom";
import Menu from "./Menu";
import MenuItem from "./MenuItem";
import AddForm from './AddForm';
import NotFound from './NotFound';
import 'bootstrap/dist/css/bootstrap.min.css';

//renders loading screen if loading, else renders app. 
function App() {
  const [isLoading, setIsLoading] = useState(true);
  const [snacks, setSnacks] = useState([]);
  const [drinks, setDrinks] = useState([]);

  useEffect(() => {
    //get the list of snacks from the API and set state appropriately
    async function getSnacks() {
      setIsLoading(true);
      let loadSnacks = await SnackOrBoozeApi.getGoodies('snacks');
      setSnacks(loadSnacks);
      setIsLoading(false);
    }
    //get the list of drinks from the API and set state appropriately
    async function getDrinks() {
      setIsLoading(true);
      let loadDrinks = await SnackOrBoozeApi.getGoodies('drinks');
      setDrinks(loadDrinks);
      setIsLoading(false);
    }
    getSnacks();
    getDrinks();
  }, []);

  if (isLoading) {
    return <p>Loading &hellip;</p>;
  }

  return (
    <div className="App">
      <BrowserRouter>
        <NavBar />
        <main>
          <Routes>
            <Route path="/" element={<Home snacks={snacks} drinks={drinks}/>} />
            <Route path="/snacks" element={<Menu items={snacks} type="snacks" />} />
            <Route path="/snacks/:id" element={<MenuItem items={snacks} cantFind="/snacks" />}/>
            <Route path="/drinks" element={<Menu items={drinks} type="drinks" />} />
            <Route path='/drinks/:id' element={<MenuItem items={drinks} cantFind="/drinks" />}/>
            <Route path='/add' element={<AddForm setSnacks={setSnacks} setDrinks={setDrinks}/>}/>
            <Route path='*' element={<NotFound />}/>
          </Routes>
        </main>
      </BrowserRouter>
    </div>
  );
}

export default App;

还有这个测试:

import {render, screen, waitFor, act} from '@testing-library/react';
import {test, expect, vi} from 'vitest';
import App from '../App';
import SnackOrBoozeApi from '../Api';

//mock the api call to gather appropriate data
vi.mock('SnackOrBoozeApi', () => ({
  getGoodies: vi.fn((type) => {
    if (type ==="snacks"){
      return Promise.resolve([    {
            "id": "nachos",
            "name": "Nachos",
            "description": "An American classic!",
            "recipe": "Cover expensive, organic tortilla chips with Cheez Whiz.",
            "serve": "Serve in a hand-thrown ceramic bowl, garnished with canned black olives"
          },
          {
            "id": "hummus",
            "name": "Hummus",
            "description": "Sure to impress your vegan friends!",
            "recipe": "Purchase one container of hummus.",
            "serve": "Place unceremoniously on the table, along with pita bread."
          }]);
    }
    if (type ==='drinks'){
      return Promise.resolve([    {
            "id": "martini",
            "name": "Martini",
            "description": "An ice-cold, refreshing classic.",
            "recipe": "Mix 3 parts vodka & 1 part dry vermouth.",
            "serve": "Serve very cold, straight up."
          },
          {
            "id": "negroni",
            "name": "Negroni",
            "description": "A nice drink for a late night conversation.",
            "recipe": "Mix equal parts of gin, Campari, and sweet vermouth.",
            "serve": "Serve cold, either on the rocks or straight up."
          }]);
    }
  })
}));

test('renders the App component', async () => {
    await act (async () => {render(<App />)});
});

test('it matches snapshot', async () => {
    let app;
    await act(async () => {
      app = render(<App />)
    });
    await waitFor(() => expect(app).toMatchSnapshot());
});

test('it displays loading message', async () => {
  const {getByText} = render(<App/>);
  expect(getByText('Loading', {exact: false})).toBeInTheDocument();
});

test('fetches and displays api data', async () => {

    await act(async () => {
        render(<App />);
    });

    await waitFor(() => expect(screen.getByText('Snacks: 2')).toBeInTheDocument());
    await waitFor(() => expect(screen.getByText('Drinks: 2')).toBeInTheDocument());
});

但是最终测试没有通过,因为它似乎实际上是在调用 API,而不是模拟它。它返回 Snacks: 5 和 Drinks: 7,这是数据库中的数字。快照测试也没有通过,因为它返回的是加载状态,但我更关心为什么我的模拟不起作用。

我尝试了不同的编写模拟的方法(doMock、returnResolvedValueOnce 等)以及 act 和 wait 的各种组合,但我没有运气。烟雾测试和加载状态测试确实通过了。

reactjs mocking vitest
1个回答
0
投票

在模拟服务器请求时,建议使用

msw
并使用
server.use()
模拟响应。

如果你仍然想用这种方法工作,我认为导入路径不正确

vi.mock('SnackOrBoozeApi', () => ({

这里应该是相对路径,我不知道确切的环境,但是从你的代码来看,它看起来应该是

vi.mock('/Api/SnackOrBoozeApi', () => ({

或者实际的相对路径是什么。 (p.s如果您使用的是VSCode,您可以轻松单击文件本身的相对路径)

© www.soinside.com 2019 - 2024. All rights reserved.