{"id":1420,"date":"2017-07-31T21:03:51","date_gmt":"2017-08-01T04:03:51","guid":{"rendered":"http:\/\/www.bradleycbuchanan.com\/b\/?p=1420"},"modified":"2017-07-31T21:03:51","modified_gmt":"2017-08-01T04:03:51","slug":"clean-react-enzyme","status":"publish","type":"post","link":"https:\/\/www.bradleycbuchanan.com\/b\/clean-react-enzyme\/","title":{"rendered":"How to write clean React unit tests with Enzyme"},"content":{"rendered":"<p>Lately I&#8217;ve been writing a lot of UI in <a href=\"https:\/\/facebook.github.io\/react\/\">React<\/a> and testing a lot of that code using <a href=\"http:\/\/airbnb.io\/enzyme\/\">Enzyme<\/a> (running on <a href=\"https:\/\/karma-runner.github.io\/\">Karma<\/a> with <a href=\"http:\/\/chaijs.com\/\">Chai<\/a> assertions).  It&#8217;s a great combination, but I don&#8217;t think we (the JavaScript community) have got the idiom down yet.  <!--more--><\/p>\n<p>For example, I&#8217;ve been reading a lot of test cases that <a href=\"https:\/\/github.com\/code-dot-org\/code-dot-org\/blob\/476a4d7d5182ff03e39c43936591e6d866e05c47\/apps\/test\/unit\/templates\/studioHomepages\/TeacherHomepageTest.js#L356-L387\">look like this<\/a>:<\/p>\n<pre>\r\n\/\/ TeacherHomepageTest.js\r\nit('if there are no courses, RecentCourses component shows a SetUpMessage', () => {\r\n  const wrapper = mount(\r\n    &lt;TeacherHomepage\r\n      announcements={[]}\r\n      courses={[]}\r\n      sections={[]}\r\n      codeOrgUrlPrefix=\"http:\/\/localhost:3000\/\"\r\n    \/&gt;\r\n  );\r\n  const recentCourses = wrapper.childAt(4);\r\n  assert.equal(recentCourses.name(),'RecentCourses');\r\n  const coursesContentContainer = recentCourses.childAt(0);\r\n  assert.equal(coursesContentContainer.name(), 'ContentContainer');]\r\n  const coursesSetUpMessage = coursesContentContainer.childAt(5).childAt(0);\r\n  assert.equal(coursesSetUpMessage.name(), 'SetUpMessage');\r\n  assert.equal(coursesSetUpMessage.props().type, 'courses');\r\n  assert.equal(coursesSetUpMessage.childAt(0).text(), 'Start learning');\r\n  assert.equal(coursesSetUpMessage.childAt(1).text(), 'Assign a course to your classroom or start your own course.');\r\n  assert.equal(coursesSetUpMessage.childAt(2).name(), 'Button');\r\n  assert.equal(coursesSetUpMessage.childAt(2).props().href, '\/courses');\r\n  assert.equal(coursesSetUpMessage.childAt(2).props().text, 'Find a course');\r\n});\r\n<\/pre>\n<p>That&#8217;s one of the simpler React tests in our repo, with a lot of assertions cut for brevity &#8211; I&#8217;ve seen upwards of 50 assertions in a test case trying pin the exact DOM output of a React component.  Needless to say, these tests are not fun to write and they&#8217;re even worse to read.  Let&#8217;s turn this into a readable unit test together!<\/p>\n<h2>Test where the logic lives<\/h2>\n<p>The first problem with the test above is that it&#8217;s not a unit test at all.  The test is supposed to be checking the <code>TeacherHomepage<\/code> component, but the logic being tested &#8211; whether the <code>SetUpMessage<\/code> gets rendered &#8211; <a href=\"https:\/\/github.com\/code-dot-org\/code-dot-org\/blob\/476a4d7d5182ff03e39c43936591e6d866e05c47\/apps\/src\/templates\/studioHomepages\/RecentCourses.jsx#L85-L90\">lives in the <code>RecentCourses<\/code> component<\/a>, so it should be tested there.  As a first step, let&#8217;s change this into a test case for <code>RecentCourses<\/code>.<\/p>\n<pre>\r\n\/\/ RecentCoursesTest.js\r\nit('shows a SetUpMessage when there are no courses', () => {\r\n  const wrapper = mount(\r\n    &lt;RecentCourses\r\n      courses={[]}\r\n      heading=\"Recent Courses\"\r\n      showAllCoursesLink\r\n      isTeacher\r\n    \/&gt;\r\n  );\r\n  const coursesContentContainer = recentCourses.childAt(0);\r\n  assert.equal(coursesContentContainer.name(), 'ContentContainer');]\r\n  const coursesSetUpMessage = coursesContentContainer.childAt(5).childAt(0);\r\n  assert.equal(coursesSetUpMessage.name(), 'SetUpMessage');\r\n  assert.equal(coursesSetUpMessage.props().type, 'courses');\r\n  assert.equal(coursesSetUpMessage.childAt(0).text(), 'Start learning');\r\n  assert.equal(coursesSetUpMessage.childAt(1).text(), 'Assign a course to your classroom or start your own course.');\r\n  assert.equal(coursesSetUpMessage.childAt(2).name(), 'Button');\r\n  assert.equal(coursesSetUpMessage.childAt(2).props().href, '\/courses');\r\n  assert.equal(coursesSetUpMessage.childAt(2).props().text, 'Find a course');\r\n});\r\n<\/pre>\n<h2>Test as shallow as possible<\/h2>\n<p>That takes care of the layers <em>above<\/em> the component under test, now how about the layers <em>below<\/em>?  Right now our test is making several assertions about the behavior of <code>SetUpMessage<\/code> but it would be better if the <code>SetUpMessage<\/code>&#8216;s own unit tests took care of that.  Once we&#8217;ve extracted those tests, we can make fewer assertions here&#8230; and we can use Enzyme&#8217;s <a href=\"http:\/\/airbnb.io\/enzyme\/docs\/api\/shallow.html\"><code>shallow()<\/code> rendering<\/a> instead of <a href=\"http:\/\/airbnb.io\/enzyme\/docs\/api\/mount.html\"><code>mount()<\/code><\/a>.<\/p>\n<pre>\r\n\/\/ RecentCoursesTest.js\r\nit('shows a SetUpMessage when there are no courses', () => {\r\n  const wrapper = shallow(\r\n    &lt;RecentCourses\r\n      courses={[]}\r\n      showAllCoursesLink\r\n      isTeacher\r\n      heading=\"Recent Courses\"\r\n    \/&gt;\r\n  );\r\n  const coursesContentContainer = recentCourses.childAt(0);\r\n  assert.equal(coursesContentContainer.name(), 'ContentContainer');]\r\n  const coursesSetUpMessage = coursesContentContainer.childAt(5).childAt(0);\r\n  assert.equal(coursesSetUpMessage.name(), 'SetUpMessage');\r\n  assert.equal(coursesSetUpMessage.props().type, 'courses');\r\n  assert.equal(coursesSetUpMessage.props().isTeacher, true);\r\n});\r\n<\/pre>\n<h2>Extract default props<\/h2>\n<p>I find this makes a big difference for test readability.  Your component will have several required props, but you want your unit tests to check one thing &#8211; why not highlight the props that matter?  In our case the empty courses array is the pivotal factor in our test case.  Let&#8217;s extract the other props to minimize distractions.<\/p>\n<pre>\r\n\/\/ RecentCoursesTest.js\r\nconst defaultProps = {\r\n  showAllCoursesLink: true,\r\n  isTeacher: true,\r\n  heading=\"Recent Courses\",\r\n};\r\n\r\nit('shows a SetUpMessage when there are no courses', () => {\r\n  const wrapper = shallow(\r\n    &lt;RecentCourses\r\n      {...defaultProps}\r\n      courses={[]}\r\n    \/&gt;\r\n  );\r\n  const coursesContentContainer = recentCourses.childAt(0);\r\n  assert.equal(coursesContentContainer.name(), 'ContentContainer');]\r\n  const coursesSetUpMessage = coursesContentContainer.childAt(5).childAt(0);\r\n  assert.equal(coursesSetUpMessage.name(), 'SetUpMessage');\r\n  assert.equal(coursesSetUpMessage.props().type, 'courses');\r\n  assert.equal(coursesSetUpMessage.props().isTeacher, true);\r\n});\r\n<\/pre>\n<h2>Assert in JSX<\/h2>\n<p>It&#8217;s still awfully clunky to query our way down the tree of components and assert one property at a time.  Wouldn&#8217;t it be nice if we could just use JSX to describe the expected output of the component?<\/p>\n<p>Enzyme has a fairly powerful <a href=\"http:\/\/airbnb.io\/enzyme\/docs\/api\/ShallowWrapper\/containsMatchingElement.html\"><code>.containsMatchingElement(node)<\/code><\/a> method that lets you do exactly this.  It&#8217;s not obvious from the documentation, but you can pass a fairly complex JSX structure to compare to your wrapper.  All children must be present, but you can skip props you don&#8217;t care about for this test case (like the <code>ContentContainer<\/code>&#8216;s props here) and still get a match.<\/p>\n<pre>\r\n\/\/ RecentCoursesTest.js\r\nit('shows a SetUpMessage when there are no courses', () => {\r\n  const wrapper = shallow(\r\n    &lt;RecentCourses\r\n      {...defaultProps}\r\n      courses={[]}\r\n    \/&gt;\r\n  );\r\n  assert(wrapper.containsMatchingElement(\r\n    &lt;div&gt;\r\n      &lt;ContentContainer&gt;\r\n        &lt;SetUpMessage type=\"courses\" isTeacher \/&gt;\r\n      &lt;\/ContentContainer&gt;\r\n    &lt;\/div&gt;\r\n  ));\r\n});\r\n<\/pre>\n<p>It&#8217;s that so much better?  It even gets a little tigheter with <tt>chai-enzyme<\/tt>&#8216;s <a href=\"https:\/\/github.com\/producthunt\/chai-enzyme#containmatchingelementnode\"><code>containMatchingElement<\/code><\/a> assertion, and it provides nicer output when the assertion fails.<\/p>\n<pre>\r\n\/\/ RecentCoursesTest.js\r\nit('shows a SetUpMessage when there are no courses', () => {\r\n  expect(shallow(\r\n    &lt;RecentCourses\r\n      {...defaultProps}\r\n      courses={[]}\r\n    \/&gt;\r\n  )).to.containMatchingElement(\r\n    &lt;div&gt;\r\n      &lt;ContentContainer&gt;\r\n        &lt;SetUpMessage type=\"courses\" isTeacher \/&gt;\r\n      &lt;\/ContentContainer&gt;\r\n    &lt;\/div&gt;\r\n  ));\r\n});\r\n<\/pre>\n<p>I&#8217;ve been looking for React+Enzyme best practices online, but for some reason I can&#8217;t find any guides describing tests like this.  I&#8217;m not sure why &#8211; it&#8217;s so much nicer to write and read than what we started with.  If you&#8217;ve got other ways to improve on this pattern, please let me know.  Thanks!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Lately I&#8217;ve been writing a lot of UI in React and testing a lot of that code using Enzyme (running on Karma with Chai assertions). It&#8217;s a great combination, but I don&#8217;t think we (the JavaScript community) have got the idiom down yet.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24,8],"tags":[456,454,459,453,455,452,457,458],"class_list":["post-1420","post","type-post","status-publish","format-standard","hentry","category-featured","category-programmer","tag-chai","tag-chai-enzyme","tag-clean-code","tag-enzyme","tag-karma","tag-react","tag-tdd","tag-unit-testing"],"_links":{"self":[{"href":"https:\/\/www.bradleycbuchanan.com\/b\/wp-json\/wp\/v2\/posts\/1420","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.bradleycbuchanan.com\/b\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bradleycbuchanan.com\/b\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bradleycbuchanan.com\/b\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bradleycbuchanan.com\/b\/wp-json\/wp\/v2\/comments?post=1420"}],"version-history":[{"count":18,"href":"https:\/\/www.bradleycbuchanan.com\/b\/wp-json\/wp\/v2\/posts\/1420\/revisions"}],"predecessor-version":[{"id":1438,"href":"https:\/\/www.bradleycbuchanan.com\/b\/wp-json\/wp\/v2\/posts\/1420\/revisions\/1438"}],"wp:attachment":[{"href":"https:\/\/www.bradleycbuchanan.com\/b\/wp-json\/wp\/v2\/media?parent=1420"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bradleycbuchanan.com\/b\/wp-json\/wp\/v2\/categories?post=1420"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.bradleycbuchanan.com\/b\/wp-json\/wp\/v2\/tags?post=1420"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}