import "raf/polyfill";
import React from "react";
import { App, appName, Link, titleName } from "./App";
import { configure, shallow, mount } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import toJson from "enzyme-to-json";
// Configure Enzyme for the React version we are using.
// Could be in a test setup file. Required for React 16, 15, 0.14, 0.13.
configure({ adapter: new Adapter() });
describe(" shallow rendering", () => {
const wrapper = shallow();
it("should find its elements", () => {
// There is one
in : only one shoud be present in shallow rendering.
expect(wrapper.find("p").length).toBe(3);
expect(wrapper.find("p.App-intro").exists()).toBe(true);
expect(wrapper.find("ul").hasClass("tyler")).toBe(true);
expect(wrapper.find("ul").children().length).toBe(3);
expect(wrapper.find("h1").text()).toBe("Welcome to React");
});
it("should find using props", () => {
// "key" and "ref" could not be used that way.
// CSS attribute syntax.
expect(wrapper.find("[text='Some title']").length).toBe(1);
// Object property selector.
expect(wrapper.find({ text: "Some title" }).length).toBe(1);
});
// FIXME cannot make sense of video.
// @see http://airbnb.io/enzyme/docs/api/ReactWrapper/find.html
test.skip("should find using a constructor", () => {
// expect(wrapper.find(function App() { return ... }).length).toBe(1);
});
it("should find using displayName", () => {
const w = mount();
expect(w.find(appName).length).toBe(1);
expect(w.find(titleName).length).toBe(1);
});
it("matches the snapshot", () => {
const tree = shallow();
expect(toJson(tree)).toMatchSnapshot();
});
it("should change p text on button click", () => {
const button = wrapper.find("button");
expect(wrapper.find(".button-state").text()).toBe("No!");
// Simulate() will fetch the onClick prop on the component and call it.
button.simulate("click");
expect(wrapper.find(".button-state").text()).toBe("Yes!");
});
it("should update className with new State", () => {
expect(wrapper.find(".blue").length).toBe(1);
expect(wrapper.find(".red").length).toBe(0);
// Invoking setState() on the wrapper invokes in on the underlying component,
// and causes a rerender.
wrapper.setState({ mainColor: "red" });
expect(wrapper.find(".blue").length).toBe(0);
expect(wrapper.find(".red").length).toBe(1);
});
it("should change title text on input change", () => {
const input = wrapper.find("input");
const expected = "Tyler";
expect(wrapper.find("h2").text()).toBe("");
// The optional parameter is the mocked event.
input.simulate("change", { currentTarget: { value: expected } });
expect(wrapper.find("h2").text()).toBe(expected);
});
it("should call componentDidMount, update p tag text", () => {
jest.spyOn(App.prototype, "componentDidMount");
const w = shallow();
// Needs the method to be defined on the component for it to be invoked.
expect(App.prototype.componentDidMount.mock.calls.length).toBe(1);
expect(w.find(".lifeCycle").text()).toBe("componentDidMount");
});
it("should call componentWillReceiveProps", () => {
jest.spyOn(App.prototype, "componentWillReceiveProps");
const w = shallow();
expect(w.find(".lifeCycle").text()).toBe("componentDidMount");
// Needs the method to be defined on the component for it to be invoked.
expect(App.prototype.componentWillReceiveProps.mock.calls.length).toBe(0);
w.setProps({ hide: true });
expect(App.prototype.componentWillReceiveProps.mock.calls.length).toBe(1);
expect(w.find(".lifeCycle").text()).toBe("componentWillReceiveProps");
});
it("should return correctly from handleStrings()", () => {
// instance() provides access to the underlying class implementing the component.
const expectations = {
"Hello, world": true,
"": false,
};
for (const [value, expected] of Object.entries(expectations)) {
const actual = wrapper.instance().handleStrings(value);
expect(actual).toBe(expected);
}
});
});
describe(" mount rendering", () => {
it("h1 contains correct text", () => {
// Second parameter is optional.
const wrapper = mount(, {
context: {},
attachTo: document.createElement("div"),
});
expect(wrapper.find("h1").text()).toBe("Welcome to React");
// Tests can affect each other if mounted components are not unmounted,
// since they will remain mounted in the same DOM.
// Unmount() can also be used to simulate an unmount/mount cycle in React.
wrapper.unmount();
});
it("matches the snapshot", () => {
const tree = mount();
expect(toJson(tree)).toMatchSnapshot();
tree.unmount();
});
});
describe("", () => {
const expected = "www.google.com";
it("link component accepts address prop", () => {
const wrapper = shallow();
// wrapper.instance() is the React component. "props" is a property.
expect(wrapper.instance().props.address).toBe(expected);
});
// wrapper itself is the ShallowWrapper instance, not the React component.
it("tag node renders href correctly", () => {
const wrapper = shallow();
// Check its rendering:
// console.log(wrapper.html(), wrapper.props());
expect(wrapper.prop("href")).toBe(expected);
// Here "props" is a method, not a property.
expect(wrapper.props().href).toBe(expected);
});
it("returns null with true hide prop", () => {
const wrapper = shallow();
expect(wrapper.find("a").length).toBe(1);
expect(wrapper.props().href).toBe(expected);
// Causes a rerender() of the component.
// - triggers componentWillReceiveProps()
wrapper.setProps({ hide: true });
expect(wrapper.find("a").length).toBe(0);
// Dangerous: some versions of React might inject comments in HTML.
// expect(wrapper.html()).toBeNull();
// expect(wrapper.getNode()).toBeNull();
// Obsolete: getNode() is deprecated.
// Recommended way https://github.com/airbnb/enzyme/issues/52
expect(wrapper.getElement()).toBe(null);
expect(wrapper.getElement()).toBeNull();
// Get() returns the node at the given index on the wrapper.
expect(wrapper.get(0)).toBeNull();
});
});