App.test.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import "raf/polyfill";
  2. import React from "react";
  3. import { App, appName, Link, titleName } from "./App";
  4. import { configure, shallow, mount } from "enzyme";
  5. import Adapter from "enzyme-adapter-react-16";
  6. import toJson from "enzyme-to-json";
  7. // Configure Enzyme for the React version we are using.
  8. // Could be in a test setup file. Required for React 16, 15, 0.14, 0.13.
  9. configure({ adapter: new Adapter() });
  10. describe("<App /> shallow rendering", () => {
  11. const wrapper = shallow(<App />);
  12. it("should find its elements", () => {
  13. // There is one <p> in <App />: only one shoud be present in shallow rendering.
  14. expect(wrapper.find("p").length).toBe(3);
  15. expect(wrapper.find("p.App-intro").exists()).toBe(true);
  16. expect(wrapper.find("ul").hasClass("tyler")).toBe(true);
  17. expect(wrapper.find("ul").children().length).toBe(3);
  18. expect(wrapper.find("h1").text()).toBe("Welcome to React");
  19. });
  20. it("should find using props", () => {
  21. // "key" and "ref" could not be used that way.
  22. // CSS attribute syntax.
  23. expect(wrapper.find("[text='Some title']").length).toBe(1);
  24. // Object property selector.
  25. expect(wrapper.find({ text: "Some title" }).length).toBe(1);
  26. });
  27. // FIXME cannot make sense of video.
  28. // @see http://airbnb.io/enzyme/docs/api/ReactWrapper/find.html
  29. test.skip("should find using a constructor", () => {
  30. // expect(wrapper.find(function App() { return ... }).length).toBe(1);
  31. });
  32. it("should find using displayName", () => {
  33. const w = mount(<App />);
  34. expect(w.find(appName).length).toBe(1);
  35. expect(w.find(titleName).length).toBe(1);
  36. });
  37. it("matches the snapshot", () => {
  38. const tree = shallow(<App />);
  39. expect(toJson(tree)).toMatchSnapshot();
  40. });
  41. it("should change p text on button click", () => {
  42. const button = wrapper.find("button");
  43. expect(wrapper.find(".button-state").text()).toBe("No!");
  44. // Simulate() will fetch the onClick prop on the component and call it.
  45. button.simulate("click");
  46. expect(wrapper.find(".button-state").text()).toBe("Yes!");
  47. });
  48. it("should update className with new State", () => {
  49. expect(wrapper.find(".blue").length).toBe(1);
  50. expect(wrapper.find(".red").length).toBe(0);
  51. // Invoking setState() on the wrapper invokes in on the underlying component,
  52. // and causes a rerender.
  53. wrapper.setState({ mainColor: "red" });
  54. expect(wrapper.find(".blue").length).toBe(0);
  55. expect(wrapper.find(".red").length).toBe(1);
  56. });
  57. it("should change title text on input change", () => {
  58. const input = wrapper.find("input");
  59. const expected = "Tyler";
  60. expect(wrapper.find("h2").text()).toBe("");
  61. // The optional parameter is the mocked event.
  62. input.simulate("change", { currentTarget: { value: expected } });
  63. expect(wrapper.find("h2").text()).toBe(expected);
  64. });
  65. it("should call componentDidMount, update p tag text", () => {
  66. jest.spyOn(App.prototype, "componentDidMount");
  67. const w = shallow(<App />);
  68. // Needs the method to be defined on the component for it to be invoked.
  69. expect(App.prototype.componentDidMount.mock.calls.length).toBe(1);
  70. expect(w.find(".lifeCycle").text()).toBe("componentDidMount");
  71. });
  72. it("should call componentWillReceiveProps", () => {
  73. jest.spyOn(App.prototype, "componentWillReceiveProps");
  74. const w = shallow(<App />);
  75. expect(w.find(".lifeCycle").text()).toBe("componentDidMount");
  76. // Needs the method to be defined on the component for it to be invoked.
  77. expect(App.prototype.componentWillReceiveProps.mock.calls.length).toBe(0);
  78. w.setProps({ hide: true });
  79. expect(App.prototype.componentWillReceiveProps.mock.calls.length).toBe(1);
  80. expect(w.find(".lifeCycle").text()).toBe("componentWillReceiveProps");
  81. });
  82. it("should return correctly from handleStrings()", () => {
  83. // instance() provides access to the underlying class implementing the component.
  84. const expectations = {
  85. "Hello, world": true,
  86. "": false,
  87. };
  88. for (const [value, expected] of Object.entries(expectations)) {
  89. const actual = wrapper.instance().handleStrings(value);
  90. expect(actual).toBe(expected);
  91. }
  92. });
  93. });
  94. describe("<App /> mount rendering", () => {
  95. it("h1 contains correct text", () => {
  96. // Second parameter is optional.
  97. const wrapper = mount(<App />, {
  98. context: {},
  99. attachTo: document.createElement("div"),
  100. });
  101. expect(wrapper.find("h1").text()).toBe("Welcome to React");
  102. // Tests can affect each other if mounted components are not unmounted,
  103. // since they will remain mounted in the same DOM.
  104. // Unmount() can also be used to simulate an unmount/mount cycle in React.
  105. wrapper.unmount();
  106. });
  107. it("matches the snapshot", () => {
  108. const tree = mount(<App />);
  109. expect(toJson(tree)).toMatchSnapshot();
  110. tree.unmount();
  111. });
  112. });
  113. describe("<Link>", () => {
  114. const expected = "www.google.com";
  115. it("link component accepts address prop", () => {
  116. const wrapper = shallow(<Link address={expected} />);
  117. // wrapper.instance() is the React component. "props" is a property.
  118. expect(wrapper.instance().props.address).toBe(expected);
  119. });
  120. // wrapper itself is the ShallowWrapper instance, not the React component.
  121. it("tag node renders href correctly", () => {
  122. const wrapper = shallow(<Link address={expected} />);
  123. // Check its rendering:
  124. // console.log(wrapper.html(), wrapper.props());
  125. expect(wrapper.prop("href")).toBe(expected);
  126. // Here "props" is a method, not a property.
  127. expect(wrapper.props().href).toBe(expected);
  128. });
  129. it("returns null with true hide prop", () => {
  130. const wrapper = shallow(<Link address={expected} hide={false} />);
  131. expect(wrapper.find("a").length).toBe(1);
  132. expect(wrapper.props().href).toBe(expected);
  133. // Causes a rerender() of the component.
  134. // - triggers componentWillReceiveProps()
  135. wrapper.setProps({ hide: true });
  136. expect(wrapper.find("a").length).toBe(0);
  137. // Dangerous: some versions of React might inject comments in HTML.
  138. // expect(wrapper.html()).toBeNull();
  139. // expect(wrapper.getNode()).toBeNull();
  140. // Obsolete: getNode() is deprecated.
  141. // Recommended way https://github.com/airbnb/enzyme/issues/52
  142. expect(wrapper.getElement()).toBe(null);
  143. expect(wrapper.getElement()).toBeNull();
  144. // Get() returns the node at the given index on the wrapper.
  145. expect(wrapper.get(0)).toBeNull();
  146. });
  147. });