Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Sample code for a blog post about shallow-testing hooks
describe("given selected author", () => {
beforeEach(() => {
// Expect one more render loop of useEffect
mockUseEffect();
mockUseEffect();
// Trigger the select action
wrapper
.find("Author")
.first()
.simulate("select", alice);
});
it("sets the active author", () => {
expect(wrapper.find("Author")).toHaveLength(2);
const firstAuthor = wrapper.find("Author").first();
expect(firstAuthor.prop("author")).toEqual(alice);
});
it("loads the right posts", () => {
expect(props.fetchPosts).toHaveBeenCalledWith(alice.id);
});
it("renders the posts", () => {
expect(wrapper.find("Post").prop("post")).toEqual(posts[0]);
});
});
import React from "react";
import { shallow } from "enzyme";
import Authors from "./Authors";
describe("Authors", () => {
let props;
let wrapper;
const alice = { id: 1, name: "alice" };
const bob = { id: 2, name: "bob" };
const authors = [alice, bob];
const posts = [{ id: 1, title: "a post", body: "the body" }];
beforeEach(() => {
useEffect = jest.spyOn(React, "useEffect").mockImplementation(f => f());
props = {
fetchAuthors: jest.fn().mockResolvedValue(authors),
fetchPosts: jest.fn().mockResolvedValue(posts)
};
wrapper = shallow(<Authors {...props} />);
});
describe("on start", () => {
it("loads the authors", () => {
expect(props.fetchAuthors).toHaveBeenCalled();
});
it("does not load posts", () => {
expect(props.fetchPosts).not.toHaveBeenCalled();
});
it("renders the authors", () => {
expect(wrapper.find("Author")).toHaveLength(2);
const firstAuthor = wrapper.find("Author").first();
expect(firstAuthor.prop("author")).toEqual(alice);
expect(firstAuthor.prop("activeAuthor")).toEqual(null);
});
});
});
describe("Authors", () => {
let props;
let wrapper;
let useEffect;
const mockUseEffect = () => {
useEffect.mockImplementationOnce(f => f());
};
beforeEach(() => {
useEffect = jest.spyOn(React, "useEffect");
props = {
fetchAuthors: jest.fn().mockResolvedValue(authors),
fetchPosts: jest.fn().mockResolvedValue(posts)
};
mockUseEffect();
mockUseEffect();
wrapper = shallow(<Authors {...props} />);
});
describe("on start", () => {
it("loads the authors", () => {
expect(props.fetchAuthors).toHaveBeenCalled();
});
});
});
const Authors = ({ fetchAuthors, fetchPosts }) => {
const [authors, setAuthors] = useState([]);
const [activeAuthor, setActiveAuthor] = useState(null);
const [posts, setPosts] = useState([]);
// Load authors on start
React.useEffect(() => {
fetchAuthors().then(setAuthors);
}, []);
// Load Posts when author changes
React.useEffect(() => {
setPosts([]);
if (activeAuthor) {
fetchPosts(activeAuthor.id).then(setPosts);
}
}, [activeAuthor]);
return (
<div className="authors">
<div className="author-options">
<h3>Select an Author:</h3>
{authors.map(author => (
<Author
key={author.id}
author={author}
activeAuthor={activeAuthor}
onSelect={setActiveAuthor}
/>
))}
</div>
{activeAuthor && (
<div className="posts">
<h3>Posts by {activeAuthor.name}</h3>
{posts.map(post => (
<Post key={post.id} post={post} />
))}
</div>
)}
</div>
);
};
const HelloWorld = ({ onLoad, onExit }) => {
// Set up local state
const [name, setName] = React.useState("");
// run onLoad on mount, and onExit when object unmounts.
React.useEffect(() => {
onLoad();
return onExit;
}, []);
// Say hello every time the name changes.
React.useEffect(() => console.log(`hello ${name}`), [name]);
// Control an input with the name.
return <input value={name} onChange={event => setName(event.target.value)} />;
};
const [activeAuthor, setActiveAuthor] = useState(null);
const [posts, setPosts] = useState([]);
React.useEffect(() => {
fetchPosts(activeAuthor.id).then(setPosts);
}, [activeAuthor]);
const [authors, setAuthors] = useState([]);
React.useEffect(() => {
fetchAuthors().then(setAuthors);
}, []);
jest.spyOn(React, 'useEffect').mockImplementation(f => f());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment