我一直试图在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(..)
,但该函数不是对象的一部分,因此无法克服这个类型错误。
任何指针,我可能会出错或误解的笑话嘲笑过程将不胜感激!
1条答案
按热度按时间flvlnr441#
Here is a sample sandbox,两个测试均通过。
您需要两个关键要素:
1.首先,需要模拟模块本身,对
hello
使用模拟函数(jest.fn()
)。1.然后,在希望
hello()
返回不同值的测试中,需要用.mock*Once()
函数之一覆盖它。jest.mocked()
函数本身不做任何事情;它只是返回输入对象,但它将其Assert为模拟类型,以便TypeScript知道其.mock*()
函数。它本身不做任何mock,所以如果没有正确地mock,就会出现错误。