Jest.js Mock useParams()->“无法对原始值进行spyOn;未定义给定”

anauzrmj  于 2023-04-27  发布在  Jest
关注(0)|答案(1)|浏览(138)

我试图测试React中的一个组件,它调用useParams()来获取url id,但我不能。我已经尝试过模拟react-router-dom,但它不起作用,我得到错误Cannot spyOn on a primitive value; undefined given
我已经检查了帖子Mocking react-router-dom hooks using jest is not working,但它没有解决我的问题
Item.js:

import '../styles/item.css';
import { useParams } from 'react-router-dom';
import { Link } from "react-router-dom";

function Item({ itens, setCarrinho }){
    const { id } = useParams();
    const item = itens.filter((item) =>item.id===id);
    return (
        <div id="produto">
            <div id="fundo">
                <img src={ item[0].src } alt={ item[0].nome }></img>
                <div id="detalhes">
                    <h1>{ item[0].nome }</h1>
                    <p>{ item[0].detalhes }</p>
                    <p>{ (item[0].promo !==0) ? "De R$" + item[0].preco + ",00 por R$" + item[0].promo +",00" : "R$ "+item[0].preco+",00" }</p>
                    <div id="btnCompre">
                        <Link to="/carrinho/" data-testid="itemCarrinho"><button onClick={ () => { setCarrinho(item[0].id) } }>Compre agora</button></Link>
                    </div>
                </div>
            </div>
        </div>
    );
}

export default Item;

Item.test.js:

import React from "react";
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import "@testing-library/user-event";
import { fireEvent } from "@testing-library/react";
import Item from '../components/Item.js';
import Router from "react-router-dom";
import { MemoryRouter } from "react-router-dom";

describe("Item component", () => {
    const itens = [{
        id: "1",
        nome: "Fone de ouvido",
        preco: 100,
        promo: 0,
        src: "nome.jpg",
        detalhes: "detalhes",
        quantidade: 1,
    }];
    jest.mock('react-router', () => ({
        ...jest.requireActual('react-router'),
        useParams: jest.fn(),
    }));
    const setCarrinho = jest.fn();
    it("Checks the elements that appear on the screen", () => {
      jest.spyOn(Router, 'useParams').mockReturnValue({ id: '1' });
      render(<MemoryRouter><Item itens={ itens } setCarrinho={ setCarrinho }/></MemoryRouter>);
      expect(screen.getByText("Fone de ouvido")).toBeInTheDocument();
      expect(screen.getByText("detalhes")).toBeInTheDocument();
      expect(screen.getByText("R$ 100,00")).toBeInTheDocument();
      expect(screen.getByTestId("itemCarrinho")).toBeInTheDocument();
    });
    it("Check the button", () => {
        jest.spyOn(Router, 'useParams').mockReturnValue({ id: '1' });
        render(<MemoryRouter><Item itens={ itens } setCarrinho={ setCarrinho }/></MemoryRouter>);
        const btnCompre = screen.getByText("Compre agora");
        fireEvent.click(btnCompre);
        expect(setCarrinho).toHaveBeenCalledTimes(1);
    })
});
7y4bm7vi

7y4bm7vi1#

不要模仿useParams钩子,它的真实的实现不仅返回当前URL的动态参数的键/值对的对象,而且还进行路由路径匹配工作。任意的模仿实现将破坏其功能。
相反,我们可以使用initialEntries prop在MemoryRouter组件中呈现我们的组件。我们可以使用initialEntries prop提供路由参数。
例如:
item.tsx

import React from 'react';
import { useParams } from 'react-router-dom';

function Item() {
  return (
    <pre>{JSON.stringify(useParams())}</pre>
  );
}

export default Item;

item.test.tsx

import React from 'react';
import { MemoryRouter, Route, Routes } from "react-router-dom"
import Item from './item';
import { render } from "@testing-library/react";

describe('76083093', () => {
  test('should pass', () => {
    const { asFragment } = render(
      <MemoryRouter initialEntries={["/1"]}>
        <Routes>
          <Route path="/:id" element={<Item />} />
        </Routes>
      </MemoryRouter>
    )
    expect(asFragment().firstChild).toMatchInlineSnapshot(`
<pre>
  {"id":"1"}
</pre>
`);
  })
})

软件包版本:

"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.8.1",
"jest": "^29.4.3",

相关问题