I want to test if the handleAddBookToCart function is called when I clicked on the button using Jest.spyOn.
Thank you in advance for your help.
const HomeComponent = props => {
const { addBookToCart } = props;
const handleAddBookToCart = id => {
addBookToCart(id);
};
return (
<button onClick={() => handleAddBookToCart(id)}></button>
)
}
//Container
const mapDispatchToProps = dispatch => ({
addBookToCart: idBook => dispatch(cartOperations.addBookToCart(idBook))
});
//file test
describe('Test home component', () => {
let container;
let wrapper;
let component;
beforeEach(() => {
wrapper = mount(
<Provider store={store}>
<HomeContainer />
</Provider>
);
container = wrapper.find(HomeContainer);
component = container.find(HomeComponent);
it('calls the handleAddBookToCart function when the button is clicked', () => {
const spy = jest.spyOn(???)
component.find('button').simulate('click');
expect(spy).toHaveBeenCalled();
});
Should you must use spyOn? You can just pass a jest mock fn as the addBookToCart prop
it('calls the handleAddBookToCart function when the button is clicked', () => {
const props = {
addBookToCart: jest.fn(),
...your other props
}
const component = shallow(<HomeComponent {...props} />)
component.find('button').simulate('click');
expect(props.addBookToCart).toHaveBeenCalled();
});
An easy way would be to send a mock into the property addBookToCart and spy on that when the button is clicked.
So when you create/mount/shallow your component for the unit test, try the following (mount coming from enzyme but feel free to use your existing method of testing components):
const spy = jest.fn();
const component = mount(<HomeComponent addBookToCart={spy} />);
Related
I am using enzyme to test my react application. This is my react component:
import React from 'react';
const Child = ({name, setName}) => {
return (
<div>
<button onClick={() => setName('test')}>setName</button>
<h2>Name: {name}</h2>
</div>
);
};
export default Child;
By clicking the button i change the setName which is passed as bellow:
function App() {
const [name, setName] = useState();
return (
<div className="App">
<Child setName={setName} name={name}/>
</div>
);
}
export default App;
So, testing Child component i created the next test to test when user clicks the button should trigger setName.
describe('Should test Child component', () => {
const wrapper = (props) => shallow(<Child {...props}/>)
test('should trigger setName', () => {
const mockFun = jest.fn()
const r = wrapper({setName: jest.fn() });
const btn = r.find('button');
btn.simulate('click');
expect(r.props().setName).toHaveBeenCalled()
})
})
Running the test i get:
Error: expect(received).toHaveBeenCalled()
Matcher error: received value must be a mock or spy function
Received has value: undefined
Why i get this error and how to make my test to be valid?
I can't test it right now but I think modifying it like this should do it
describe('Should test Child component', () => {
const wrapper = (props) => shallow(<Child {...props}/>)
test('should trigger setName', () => {
const mockFun = jest.fn()
const r = wrapper({setName: mockFun });
const btn = r.find('button');
btn.simulate('click');
expect(mockFun).toHaveBeenCalled()
})
})
Also see this one as a reference same issue How to test onClick props of a button using Jest and Enzyme
I want to test the page get redirected after click on div, but I dont know how, this is my code. Thank you so much
<div className="bellTest">
<NextLink href="/notifications">
<Bell />
</NextLink>
</div>
test.tsx
jest.mock('next/link', () => {
return ({ children }) => {
return children;
};
});
describe('Test of <HeaderContainer>', () => {
test('Test the page redirect after click', async done => {
const wrapper = mount( <HeaderComponent /> );
await wrapper
.find('.bellTest')
.at(0)
.simulate('click');
// expect the page getting redirect
});
});
Instead of mocking next/link you can register a spy on router events, and check if it was called.
The test will look like this:
import Router from 'next/router';
describe('Test of <HeaderContainer>', () => {
const spies: any = {};
beforeEach(() => {
spies.routerChangeStart = jest.fn();
Router.events.on('routeChangeStart', spies.routerChangeStart);
});
afterEach(() => {
Router.events.off('routeChangeStart', spies.routerChangeStart);
});
test('Test the page redirect after click', async done => {
const wrapper = mount(<HeaderComponent />);
await wrapper
.find('.bellTest')
.at(0)
.simulate('click');
expect(spies.routerChangeStart).toHaveBeenCalledWith('expect-url-here');
});
});
componentWillUnmount() {
document.removeEventListener('click', this.handleClickOutside);
}
/**
* Set the wrapper ref
*/
setWrapperRef(node) {
this.wrapperRef = node;
}
handleClickOutside(event) {
/* istanbul ignore next */
if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
this.props.clickHandler();
}
}
How do i call the handleClickOutside function. How should I mimic the clickOutside here? Please help
it('lets click outside and close dropdown', () => {
const handleClickOutside = sinon.spy();
expect(handleClickOutside.called).to.be.true;
wrapper.unmount();
});
Assuming this is a HOC or render prop that renders other components as children (this.props.children) -- also the following is a Jest and Enzyme test, so it may be slightly different than what you're using.
components/__test__/ClickHandler.test.js
const clickHandler = jest.fn()
const initialProps = {
clickHandler,
children: <button className="example">Test</button>
...other props
};
const wrapper = shallow(<ClickHandler {...initialProps} />);
describe("Example", () => {
it('handles clicks inside of the component', () => { // this would test the event lisenter, the class method, and the clickHandler -- slightly overkill
const spy = jest.spyOn(wrapper.instance(), 'handleClickOutside');
wrapper.instance().forceUpdate();
wrapper.find('button').simulate('click');
expect(spy).toHaveBeenCalled();
expect(clickHandler).toHaveBeenCalledTimes(0);
spy.mockClear();
});
it('handles clicks outside of the component', () => { // this is a more straight forward test that assumes the event listener is already working
const event = { target: <div className="example">Outside Div</div> };
wrapper.instance().handleClickOutside(event);
expect(clickHandler).toHaveBeenCalled();
});
})
I wrote a simple unit test for the following. I am new to React JS testing - Trying to run a test using jest and enzyme.
render() {
return (
<div>
<div className="not-found">
<div className='_2'>WAS NOT FOUND</div>
<div onClick={() => {window.history.back()}} className='not-found-
btn' href='/'>GO BACK</div>
)
}
}
The file looks simple, there are no props and the only thing not being covered when the test is running is onClick . How could I test onClick and make sure the test is 100 % covered. Thanks
<div onClick={() => {window.history.back()}} className='not-found-
btn' href='/'>GO BACK</div>
file.test.js
// jest mock functions (mocks this.props.func)
const onClick = jest.fn();
// defining this.props
const baseProps = {
onClick,
}
describe(' Test', () => {
let wrapper;
let tree;
beforeEach(() => wrapper = shallow(<Component{...baseProps } />));
// before each test, shallow mount the Component
it('should render correctly', () => {
tree = renderer.create(<NotFound {...baseProps} />)
let treeJson = tree.toJSON()
expect(treeJson).toMatchSnapshot();
tree.unmount()
});
it('calls onClick event ', () => {
const mockOnClick = jest.fn();
const wrapper = shallow(
<NotFound onClick={mockOnClick} className='not-found-btn' />
);
const component = wrapper.shallow();
component.find('GO BACK').simulate('click');
expect(mockOnClick.mock.calls.length).toEqual(1);
I'd avoid using window history and instead use react-router-dom for MPAs. In addition, instead of using an anonymous function, you can use a PureComponent class (it's similar to a Component class, but it doesn't update state) with a method class function.
Working example: https://codesandbox.io/s/j3qo6ppxqy (this example uses react-router-dom and has a mix of integration and unit testing -- see the tests tab at the bottom of the page to run the tests and look for __test__ folders to see the code)
components/NotFound/notfound.js
import React, { PureComponent } from "react";
import { Button } from "antd";
export default class NotFound extends PureComponent {
handlePageBack = () => this.props.history.push("/");
render = () => (
<div className="notfound">
<h1>404 - Not Found!</h1>
<Button type="default" onClick={this.handlePageBack}>
Go Back
</Button>
</div>
);
}
components/NotFound/__tests__/notfound.test.js (as mentioned here, you can also test the class method, if desired)
import React from "react";
import { shallowComponent } from "../../../tests/utils";
import NotFound from "../notfound";
const mockGoBack = jest.fn();
const initialProps = {
history: {
goBack: mockGoBack
}
};
/*
the shallowComponent function below is a custom function in "tests/utils/index.js" that
simplifies shallow mounting a component with props and state
*/
const wrapper = shallowComponent(<NotFound {...initialProps} />);
describe("Not Found", () => {
it("renders without errors", () => {
const notfoundComponent = wrapper.find("div.notfound");
expect(notfoundComponent).toHaveLength(1);
});
it("pushes back a page when Go Back button is clicked", () => {
wrapper.find("Button").simulate("click");
expect(mockGoBack).toHaveBeenCalled();
});
});
window.history.back is being called, but it has a delay time. I can make it work using a Promise:
const Component = ()=> (<div>
<button onClick={()=> window.history.back()} className="btn btn-back">
Back
</button>
</div>)
Component.test.js
import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import { act } from "react-dom/test-utils";
const delayAction = (fn, time = 1000) =>
new Promise((resolve) => {
fn();
setTimeout(() => {
resolve();
}, time);
});
let container = null;
describe("App tests", () => {
afterEach(() => {
//unmount Component...
});
beforeEach(() => {
//mount Component
});
it("should call history.back()", async (done) => {
const btnBack = container.querySelector(".btn-back");
await act(() =>
delayAction(() => btnBack.dispatchEvent(new MouseEvent("click", { bubbles: true })))
);
// asserts..
done();
});
});
I want to write unit test for React component's method.
The component's code is
export class LoginForm extends Component {
constructor() {
super();
this.tryLoginProp = this.tryLoginProp.bind(this)
}
render() {
return (
<div className="login-form">
<div className="form-input">
<CustomButton label="Log in"
class="login-button"
action={this.tryLoginProp}
id="login-button-loginform"
renderSpinner={this.props.renderSpinner}
/>
</div>
</div>
)
}
tryLoginProp () {
if (!this.props.renderSpinner) {
this.props.tryLoginProp()
}
}
}
const mapStateToProps = (state) => {
return {
login: state.login,
renderSpinner: state.layout.renderSpinner
};
};
const mapDispatchToProps = (dispatch) => ({
tryLoginProp: () => {
dispatch(tryLogin())
}
});
export default connect(mapStateToProps, mapDispatchToProps)(LoginForm);
I want to write unit test for tryLoginProp method, but I am not getting how to mock this.props.tryLoginProp function and pass the test case.
Current unit test is as follows:
describe('<LoginForm />', () => {
const initialState = {renderSpinner: false};
let wrapper;
beforeEach(() => {
wrapper = mount(<LoginForm {...initialState}/>);
});
it('renders without expolding', () => {
expect(wrapper.length).toEqual(1);
});
it('tryLoginProp should dispatch an action', () => {
expect(wrapper.tryLoginProp()). //test tryLoginProp method.
})
});
Please help me to write proper test case for this method.
Thanks
You can use wrapper.instance().tryLoginProp() to call the method...like this I think without testing it
it('tryLoginProp should dispatch an action', () => {
const mockedTryLoginProp = jest.fn();
const wrapper = shallow(
<LoginForm
tryLoginProp={mockedTryLoginProp}
renderSpinner={false}
/>
);
wrapper.instance().tryLoginProp();
expect(mockedTryLoginProp).toHaveBeenCalled();
})
On a side note, you may consider naming the internal function differently than the one being passed in to avoid confusion