我试图监视useState React钩子,但我总是使测试失败
这是我的React组件:
const Counter= () => {
const[counter, setCounter] = useState(0);
const handleClick=() => {
setCounter(counter + 1);
}
return (
<div>
<h2>{counter}</h2>
<button onClick={handleClick} id="button">increment</button>
</div>
)
}
counter.test.js :
it('increment counter correctlry', () => {
let wrapper = shallow(<Counter/>);
const setState = jest.fn();
const useStateSpy = jest.spyOn(React, 'useState');
useStateSpy.mockImplementation((init) => [init, setState]);
const button = wrapper.find("button")
button.simulate('click');
expect(setState).toHaveBeenCalledWith(1);
})
不幸的是,这不起作用,并且我收到该消息的测试失败:
expected 1
Number of calls: 0
答案 0 :(得分:5)
您需要使用The operator '>' isn't defined for the type 'DateTime'.
而不是单个导入var EventSource = require("eventsource");
var url = "..." // Source URL
var es = new EventSource(url);
es.onmessage = (event) => {
console.log(event)
const parsedData = JSON.parse(event.data);
console.log(parsedData)
}
。
我认为代码transpiled是如何获取的,正如您在babel repl中所看到的,一次导入的React.useState
与模块导入的最终结果不同
useState
因此,您监视useState
,但组件使用_react.useState // useState
_react.default.useState // React.useState;
。
监视一次导入似乎是不可能的,因为您需要该函数属于一个对象,因此,这是一本非常详尽的指南,其中介绍了模拟/监视模块https://github.com/HugoDF/mock-spy-module-import
正如@Alex Mackay所提到的,您可能希望改变对测试反应组件的看法,建议您改用react-testing-library,但是如果您确实需要坚持使用酶,则无需走太远嘲笑反应库本身
答案 1 :(得分:3)
令人讨厌的是,Codesandbox当前在其测试模块上遇到了麻烦,因此我无法发布一个有效的示例,但我将尝试解释为什么嘲笑useState
通常是一件不好的事情。
用户不在乎是否调用了useState
,他们关心的是当我单击增量时,计数应该增加一个,因此这就是您要测试的内容。 / p>
// App
import React, { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount((prev) => prev + 1)}>Increment</button>
</div>
);
}
// Tests
import React from "react";
import App from "./App";
import { screen, render } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
describe("App should", () => {
it('increment count value when "Increment" btn clicked', () => {
// Render the App
render(<App />);
// Get the count in the same way the user would, by looking for 'Count'
let count = screen.getByText(/count:/);
// As long as the h1 element contains a '0' this test will pass
expect(count).toContain(0);
// Once again get the button in the same the user would, by the 'Increment'
const button = screen.getByText(/increment/);
// Simulate the click event
userEvent.click(button);
// Refetch the count
count = screen.getByText(/count:/);
// The 'Count' should no longer contain a '0'
expect(count).not.toContain(0);
// The 'Count' should contain a '1'
expect(count).toContain(1);
});
// And so on...
it('reset count value when "Reset" btn is clicked', () => {});
it('decrement count value when "Decrement" btn is clicked', () => {});
});
如果您对此测试风格感兴趣,请绝对签出@testing-library
。我从enzyme
切换到大约2年前,此后一直没有碰过它。
答案 2 :(得分:3)
diedu 的回答为我指明了正确的方向,我想出了这个解决方案:
jest.mock('react', ()=>({
...jest.requireActual('react'),
useState: jest.fn()
}))
import { useState } from 'react';
describe("Test", ()=>{
beforeEach(()=>{
useState.mockImplementation(jest.requireActual('react').useState);
//other preperations
})
//tests
})
it("Actual test", ()=>{
useState.mockImplementation(()=>["someMockedValue", someMockOrSpySetter])
})
离别笔记:虽然在“黑匣子”是单元测试中弄脏手在概念上可能有些错误,但有时这样做确实非常有用。
答案 3 :(得分:1)
只需要在测试文件中导入 React,例如:
import * as React from 'react';
之后就可以使用模拟功能了。
import * as React from 'react';
:
:
it('increment counter correctlry', () => {
let wrapper = shallow(<Counter/>);
const setState = jest.fn();
const useStateSpy = jest.spyOn(React, 'useState');
useStateSpy.mockImplementation((init) => [init, setState]);
const button = wrapper.find("button")
button.simulate('click');
expect(setState).toHaveBeenCalledWith(1);
})