Last active
April 3, 2023 02:59
-
-
Save pylnata/43821fb253557254afcbee0288e97640 to your computer and use it in GitHub Desktop.
Jest+Enzyme example unit test with SHALLOW for React component using useEffect and (useDispatch, useSelector) hooks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const search = (query) => ({type: "SEARCH", query }) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// we do it in such way to be able to mock it in test | |
import { useSelector as originalUseSelector, useDispatch as originalUseDispatch } from "react-redux"; | |
export const useSelector = (state) => originalUseSelector(state); | |
export const useDispatch = () => originalUseDispatch(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
export const Recipeitem = (props) => { | |
return (<div> | |
{props.title} | |
</div>) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { Spinner } from "reactstrap"; | |
import { useDispatch, useSelector } from "./react-redux-hooks"; | |
import RecipeItem from "./RecipeItem"; | |
import { search } from "./actions"; | |
const RecipeList = props => { | |
const dispatch = useDispatch(); | |
const { recipies, isLoading, error } = useSelector((state) => ({ | |
isLoading: state.isLoading, | |
recipies: state.recipies, | |
error: state.error | |
})); | |
React.useEffect(() => { // important to write React.useEffect and not import useEffect | |
dispatch(search()); | |
}, [dispatch]); | |
let result = null; | |
if (isLoading) { | |
result = <Spinner />; | |
} else if (error) { | |
result = error.message; | |
} else if (recipies.length > 0) { | |
result = recipies.map(item => ( | |
<RecipeItem recipe={item} key={item.id} /> | |
)); | |
} | |
return ( | |
<div>{result}</div> | |
); | |
}; | |
export default RecipeList; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { configure, shallow } from "enzyme"; | |
import Adapter from "enzyme-adapter-react-16"; | |
import configureStore from "redux-mock-store"; | |
import * as ReactReduxHooks from "./react-redux-hooks"; | |
import RecipeList from "./RecipeList"; | |
import RecipeItem from "./RecipeItem"; | |
configure({ adapter: new Adapter() }); | |
describe("RecipeList", () => { | |
let wrapper; | |
let useEffect; | |
let store; | |
const mockUseEffect = () => { | |
useEffect.mockImplementationOnce(f => f()); | |
}; | |
beforeEach(() => { | |
store = configureStore()({ | |
recipies: [{id: 1, title: 'Ice Cream'}, {id: 2, title: 'Soup Cream'}, {id:3, title: 'Cream with fruits'}], | |
isLoading: false, | |
error: null | |
}); | |
useEffect = jest.spyOn(React, "useEffect"); | |
mockUseEffect(); // important to do it twice | |
mockUseEffect(); | |
jest | |
.spyOn(ReactReduxHooks, "useSelector") | |
.mockImplementation(state => store.getState()); | |
jest | |
.spyOn(ReactReduxHooks, "useDispatch") | |
.mockImplementation(() => store.dispatch); | |
wrapper = shallow(<RecipeList store={store} />); | |
}); | |
describe("on start", () => { | |
it("dispatch search action to store", () => { | |
const actions = store.getActions(); | |
expect(actions).toEqual([{ type: "SEARCH", query: "cream" }]); | |
}); | |
}); | |
it("should render RecipeItem components if gets recipies array from store", () => { | |
expect(wrapper.find(RecipeItem)).toHaveLength(3); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@pylnata, thanks a lot! It's very helpful