Sah*_*ndy 12 javascript testing jes reactjs enzyme
I am trying to spy on useState React hook but i always get the test failed
This is my React component:
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>
)
}
Run Code Online (Sandbox Code Playgroud)
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);
})
Run Code Online (Sandbox Code Playgroud)
Unfortunately this doesn't work and i get the test failed with that message:
expected 1
Number of calls: 0
Run Code Online (Sandbox Code Playgroud)
小智 28
dieu的回答引导了我正确的方向,我想出了这个解决方案:
jest.mock('react', ()=>({
...jest.requireActual('react'),
useState: jest.fn()
}))
import { useState } from 'react';
Run Code Online (Sandbox Code Playgroud)
describe("Test", ()=>{
beforeEach(()=>{
useState.mockImplementation(jest.requireActual('react').useState);
//other preperations
})
//tests
})
Run Code Online (Sandbox Code Playgroud)
it("Actual test", ()=>{
useState.mockImplementation(()=>["someMockedValue", someMockOrSpySetter])
})
Run Code Online (Sandbox Code Playgroud)
临别说明:虽然从概念上来说,在“黑匣子”中亲自动手进行单元测试可能有些错误,但有时这样做确实非常有用。
die*_*edu 14
您需要使用React.useState
而不是单个 import useState
。
我认为是关于代码如何转换的,正如您在 babel repl 中看到的那样,useState
从单个导入最终与模块导入之一不同
_react.useState // useState
_react.default.useState // React.useState;
Run Code Online (Sandbox Code Playgroud)
所以你监视_react.default.useState
但你的组件使用_react.useState
. 监视单个导入似乎是不可能的,因为您需要该函数属于一个对象,这里有一个非常广泛的指南,解释了模拟/监视模块的方法https://github.com/HugoDF/mock-spy-module-进口
正如@Alex Mackay 提到的,你可能想改变你对测试 React 组件的心态,推荐使用 react-testing-library,但如果你真的需要坚持使用酶,你不需要走那么远去模拟反应库本身
小智 8
只需要在测试文件中导入 React 即可,例如:
import * as React from 'react';
Run Code Online (Sandbox Code Playgroud)
之后就可以使用mock函数了。
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);
})
Run Code Online (Sandbox Code Playgroud)
令人烦恼的是,Codesandbox 目前在其测试模块上遇到了问题,因此我无法发布工作示例,但我会尝试解释为什么模拟useState
通常是一件坏事。
用户不关心是否useState
已被调用,他们关心当我单击增量时计数应该增加一,因此这就是您应该测试的内容。
// 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', () => {});
});
Run Code Online (Sandbox Code Playgroud)
一定要检查一下@testing-library
您是否对这种测试方式感兴趣。我enzyme
大约两年前就换了,从那以后就再也没有碰过它。