无法在呈现nextjs页面时使用jest / react-testing-library模拟导出的命名函数

8iwquhpp  于 2023-09-28  发布在  Jest
关注(0)|答案(1)|浏览(112)

我一直试图在NextJS页面中模拟一个命名的导入函数,但到目前为止,我从各种网站收集的所有尝试都失败了。
我尝试使用create-next-app--example with-jest来重现这个过程,代码如下。
我的pages/index.tsx

import Head from 'next/head'
import { hello } from '../utils/greeter'

export default function Home() {
  return (
    <div>
      <Head>
        <title>Create Next App</title>
      </Head>

      <main>
        <h1>{hello()}</h1>
      </main>
    </div>
  )
}

然后,我有我的utils/greeter.ts包含命名的导出函数,我希望能够在测试用例中模拟/spyOn

export const hello = (): string => 'hello world';

最后是测试文件__tests__/index.test.tsx

import { render, screen } from '@testing-library/react'
import Home from '@/pages/index'

describe('Home', () => {
  it('renders unmocked greeting', () => {
    render(<Home />)

    const heading = screen.getByRole('heading', {
      name: 'hello world',
    })

    expect(heading).toBeInTheDocument()
  })
  it('renders mocked greeting', () => {
    render(<Home />)

    const heading = screen.getByRole('heading', {
      name: 'hello mock',
    })

    expect(heading).toBeInTheDocument()
  })
})

我可以通过在我的测试用例上添加以下内容来更改模拟实现:

jest.mock('../utils/greeter', () => ({
  __esModule: true,
  hello: () => 'hello mock'
})

这将正确地改变函数,并导致第二个测试用例通过,但所有测试用例都存在模拟,因此导致第一个测试用例失败。
我希望能够为每个测试用例选择是否使用真实的实现,模拟实现,甚至利用间谍来验证模拟函数被调用的内容。
每当我试图用引用替换返回的'hello mock'字符串时,比如

const mockFn = jest.fn()

然后在每个测试用例中尝试覆盖返回值,例如

mockFn.mockReturnValue('hello mock')

这两个测试都失败了,因为hello()函数似乎没有返回模拟值。
我也看到过有人建议使用jest.spyOn(..),但该函数不是对象的一部分,因此无法克服这个类型错误。
任何指针,我可能会出错或误解的笑话嘲笑过程将不胜感激!

flvlnr44

flvlnr441#

Here is a sample sandbox,两个测试均通过。
您需要两个关键要素:
1.首先,需要模拟模块本身,对hello使用模拟函数(jest.fn())。

jest.mock("../utils/greeter", () => ({
  __esModule: true,
  hello: jest.fn(() => "hello world"),
}));

1.然后,在希望hello()返回不同值的测试中,需要用.mock*Once()函数之一覆盖它。jest.mocked()函数本身不做任何事情;它只是返回输入对象,但它将其Assert为模拟类型,以便TypeScript知道其.mock*()函数。它本身不做任何mock,所以如果没有正确地mock,就会出现错误。

jest.mocked(hello).mockReturnValueOnce("hello mock");

相关问题