<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.4.5">Jekyll</generator><link href="https://guigrpa.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://guigrpa.github.io/" rel="alternate" type="text/html" /><updated>2017-07-14T10:42:27+00:00</updated><id>https://guigrpa.github.io/</id><title type="html">Math.random()</title><subtitle>Random thoughts on software development and engineering</subtitle><entry><title type="html">Word documents, The Relay Way™</title><link href="https://guigrpa.github.io/2017/01/01/word-docs-the-relay-way/" rel="alternate" type="text/html" title="Word documents, &lt;i&gt;The Relay Way&lt;/i&gt;™" /><published>2017-01-01T02:00:00+00:00</published><updated>2017-01-01T02:00:00+00:00</updated><id>https://guigrpa.github.io/2017/01/01/word-docs-the-relay-way</id><content type="html" xml:base="https://guigrpa.github.io/2017/01/01/word-docs-the-relay-way/">&lt;p&gt;&lt;strong&gt;&lt;em&gt;TL;DR&lt;/em&gt;    Sometimes you have to set aside your developer work and do some office stuff. And sometimes that includes generating Word reports with dynamic contents. What if you could bridge Word, GraphQL and JavaScript to help you with these chores? &lt;a href=&quot;https://github.com/guigrpa/docx-templates&quot;&gt;docx-templates&lt;/a&gt; helps you do exactly that.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every once in a while you need to produce a Microsoft Word document with dynamic contents. Maybe it’s a project report, or the boring economic section of a tender. Chances are you’re working within a team, and you absolutely need your document to be in the &lt;em&gt;de facto&lt;/em&gt; standard for non-nerdy output: Word.&lt;/p&gt;

&lt;p&gt;You don’t want to write hundreds of tables by hand, so you start thinking about &lt;em&gt;docx&lt;/em&gt; automation. And since you’re a proud Node.js developer, you stumble upon these types of modules from the top of npm’s search results:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Fully programmatic generators&lt;/em&gt;, like &lt;a href=&quot;https://github.com/dolanmiu/docx&quot;&gt;docx&lt;/a&gt;, which provide functions to create paragraphs, text runs, and so on.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Template-based generators&lt;/em&gt;, like &lt;a href=&quot;https://github.com/guigrpa/docx-templates&quot;&gt;docx-templates&lt;/a&gt;, which let you start with an ordinary Word document, adding commands as needed to insert dynamic contents.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The benefits of the second approach are numerous:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;You don’t need the library to support every tiny little feature of Word. The input template will be used transparently, so the output will be compatible with whatever version of Office you’re using.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;You don’t need to write code to generate &lt;em&gt;static&lt;/em&gt; parts of your document.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;You can even write documents &lt;em&gt;à la Relay&lt;/em&gt;. What am I talking about? Well, just keep on reading!&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;colocating-queries&quot;&gt;Colocating queries&lt;/h2&gt;

&lt;p&gt;One of the key ideas in &lt;a href=&quot;https://facebook.github.io/relay/&quot;&gt;Relay&lt;/a&gt; is &lt;em&gt;colocation&lt;/em&gt;. It’s literally front and center in its home page, and what it basically means is that data requirements (the &lt;em&gt;query&lt;/em&gt;) are declared very close to the components that need the data.&lt;/p&gt;

&lt;p&gt;If we translate this idea to report generation, wouldn’t it be nice if we just wrote the data query in the document itself? A very simple template would look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/docx-swapi-simple1.png&quot;&gt;
    &lt;img src=&quot;/img/docx-swapi-simple1.png&quot; alt=&quot;Query colocation in docx-templates&quot; /&gt;
&lt;/a&gt;
&lt;span class=&quot;caption text-muted&quot;&gt;Query colocation&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;We’re using the &lt;a href=&quot;https://swapi.co/&quot;&gt;Star Wars API&lt;/a&gt; with the &lt;a href=&quot;http://graphql.org/&quot;&gt;GraphQL&lt;/a&gt; &lt;a href=&quot;https://github.com/graphql/swapi-graphql&quot;&gt;wrapper&lt;/a&gt; for maximum convenience, but &lt;code class=&quot;highlighter-rouge&quot;&gt;docx-templates&lt;/code&gt; doesn’t really care about the language you choose for queries, as long as they eventually resolve to some data.&lt;/p&gt;

&lt;p&gt;With the data requirements in place, we can write a short JavaScript snippet to execute the embedded query and create the report.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// swapi.js&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createReport&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'docx-templates'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'isomorphic-fetch'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// assuming a modern Node, you need no Promise polyfill&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;createReport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'http://graphql-swapi.parseapp.com'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;Accept&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'application/json'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'Content-Type'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'application/json'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Run this script with &lt;code class=&quot;highlighter-rouge&quot;&gt;node swapi swapi-simple-template.docx&lt;/code&gt; and &lt;em&gt;voilà&lt;/em&gt;, both trilogies come up in your report (alas, no &lt;em&gt;Force Awakens&lt;/em&gt; data yet in the GraphQL wrapper 😱):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/docx-swapi-simple2.png&quot;&gt;
    &lt;img src=&quot;/img/docx-swapi-simple2.png&quot; alt=&quot;A very simple report generated with docx-templates&quot; /&gt;
&lt;/a&gt;
&lt;span class=&quot;caption text-muted&quot;&gt;A simple report generated with &lt;code class=&quot;highlighter-rouge&quot;&gt;docx-templates&lt;/code&gt;&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;a-more-complex-example&quot;&gt;A more complex example&lt;/h2&gt;

&lt;p&gt;GraphQL is really great for describing complex data requirements. Imagine you want to summarize all Star Wars films with some basic data and a table of characters with their species, home planet, and ships (i.e. vehicles with hyperdrive) they appear in. Really nerdy stuff, huh? No problem with GraphQL:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;+++QUERY { allFilms { films {
  title, releaseDate, director, producers, openingCrawl
  characterConnection { characters {
    name
    species { name }
    homeworld { name }
    starshipConnection { starships { name crew passengers } }
  } }
} } }+++
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Your Word template might look like this (right after the query):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/docx-swapi-complex2.png&quot;&gt;
    &lt;img src=&quot;/img/docx-swapi-complex2.png&quot; alt=&quot;A complete template with embedded JS&quot; /&gt;
&lt;/a&gt;
&lt;span class=&quot;caption text-muted&quot;&gt;A complete template with embedded JS&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This templates demonstrates other features of &lt;code class=&quot;highlighter-rouge&quot;&gt;docx-templates&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;You can embed JavaScript in your &lt;code class=&quot;highlighter-rouge&quot;&gt;INS&lt;/code&gt; (shorthand notation: &lt;code class=&quot;highlighter-rouge&quot;&gt;=&lt;/code&gt;), &lt;code class=&quot;highlighter-rouge&quot;&gt;FOR&lt;/code&gt; and other commands.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;You can define aliases (&lt;code class=&quot;highlighter-rouge&quot;&gt;ALIAS&lt;/code&gt;) for complete commands, which you can then resolve with the &lt;code class=&quot;highlighter-rouge&quot;&gt;*&amp;lt;alias-name&amp;gt;&lt;/code&gt; shorthand. We found it quite useful when templating tables.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Loop variables (e.g. &lt;code class=&quot;highlighter-rouge&quot;&gt;$film&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;$character&lt;/code&gt;) can be used from embedded JavaScript snippets, just like any other property of the query result.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Want to see the generated document? Just run &lt;code class=&quot;highlighter-rouge&quot;&gt;node swapi swapi-complex-template.docx&lt;/code&gt; and there it is, in all its geeky splendor:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/docx-swapi-complex3.png&quot;&gt;
    &lt;img src=&quot;/img/docx-swapi-complex3.png&quot; alt=&quot;A complete report generated with docx-templates&quot; /&gt;
&lt;/a&gt;
&lt;span class=&quot;caption text-muted&quot;&gt;A complete report generated with &lt;code class=&quot;highlighter-rouge&quot;&gt;docx-templates&lt;/code&gt;&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;a-final-word&quot;&gt;A final word&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/guigrpa/docx-templates&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;docx-templates&lt;/code&gt;&lt;/a&gt; is a young project and still evolving with our needs. If you use it and have suggestions or —even better— want to contribute, please visit its GitHub repo!&lt;/p&gt;</content><author><name>Guillermo Grau</name></author><summary type="html">TL;DR    Sometimes you have to set aside your developer work and do some office stuff. And sometimes that includes generating Word reports with dynamic contents. What if you could bridge Word, GraphQL and JavaScript to help you with these chores? docx-templates helps you do exactly that.</summary></entry><entry><title type="html">Picture this: snapshot testing</title><link href="https://guigrpa.github.io/2016/09/27/picture-this-snapshot-testing/" rel="alternate" type="text/html" title="Picture this: snapshot testing" /><published>2016-09-27T12:00:00+00:00</published><updated>2016-09-27T12:00:00+00:00</updated><id>https://guigrpa.github.io/2016/09/27/picture-this-snapshot-testing</id><content type="html" xml:base="https://guigrpa.github.io/2016/09/27/picture-this-snapshot-testing/">&lt;p&gt;&lt;strong&gt;&lt;em&gt;TL;DR&lt;/em&gt;    If you’re not testing your React (Native) components at all, or are relying on insufficient, high-level smoke tests, you’re not alone. Writing those unit tests must be one of the less rewarding experiences for a developer. But wait: &lt;em&gt;snapshots to the rescue!&lt;/em&gt; &lt;a href=&quot;https://facebook.github.io/jest/&quot;&gt;Jest&lt;/a&gt;’s newest release features snapshot testing – and might well change your mind.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://facebook.github.io/jest/&quot;&gt;Jest&lt;/a&gt;’s latest release has caused quite a stir, and understandably so: its &lt;a href=&quot;https://facebook.github.io/jest/docs/tutorial-react.html#snapshot-testing&quot;&gt;&lt;strong&gt;snapshot testing&lt;/strong&gt;&lt;/a&gt; feature alone is something of a mind-bender. If you’re like me, maybe you didn’t write unit tests for your React (Native) components for a number of valid reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;“They’re hard to write”&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;“They’re brittle”&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;“They don’t bring so much value if you have at least some integration tests”&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Starting with Jest 14, though, you may need to revisit those arguments. Snapshots are trivial to use, they can easily be updated, and they provide full coverage of your components, dynamic behavior included. How do they work? Even that can be explained in just two bullets:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The first time your test renders a component, a snapshot is taken and saved to a file.&lt;/li&gt;
  &lt;li&gt;Upon re-run, the new render is diffed against the snapshot. If there’s a mismatch, you choose which one to keep (and maybe correct your application).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On top of that, Jest provides a &lt;a href=&quot;https://facebook.github.io/jest/docs/api.html#content&quot;&gt;comprehensive testing framework&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/mikenikles/status/772234132436885504&quot;&gt;good&lt;/a&gt; &lt;a href=&quot;http://facebook.github.io/jest/blog/2016/03/11/javascript-unit-testing-performance.html&quot;&gt;performance&lt;/a&gt;, top-notch diffs and error context and &lt;a href=&quot;https://twitter.com/dan_abramov/status/771496951858733057&quot;&gt;lots of CLI goodies&lt;/a&gt;. Even &lt;a href=&quot;https://facebook.github.io/jest/docs/getting-started.html#use-coverage-to-generate-a-code-coverage-report&quot;&gt;coverage results&lt;/a&gt; out of the box! No wonder it got rave reviews.&lt;/p&gt;

&lt;p&gt;Haven’t tried snapshots yet? Let’s give them a spin. The following examples are loosely based on &lt;a href=&quot;https://github.com/guigrpa/mady&quot;&gt;Mady&lt;/a&gt;, an application for software internationalization. Until now, Mady had absolutely no tests covering its React components.&lt;/p&gt;

&lt;h2 id=&quot;a-hello-world-component&quot;&gt;A &lt;em&gt;hello-world&lt;/em&gt; component&lt;/h2&gt;

&lt;p&gt;We’ll try snapshots on a very simple component first. Mady’s &lt;code class=&quot;highlighter-rouge&quot;&gt;Header&lt;/code&gt; is a stateless functional component showing the application name and a couple of buttons. Lots of styles to be tested, but not much more.&lt;/p&gt;

&lt;p&gt;The full unit test for this component is so short you might think it’s a joke:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/* eslint-env jest */&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;React&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'react'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'react-test-renderer'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Header&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'../header'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'renders correctly'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Header&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toJSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toMatchSnapshot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Run Jest, and a new snapshot will be created:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;exports[`renders correctly 1`] = `
&amp;lt;div
  style={
    Object {
      &quot;WebkitFlex&quot;: &quot;0 0 2.5em&quot;,
      &quot;alignItems&quot;: &quot;center&quot;,
      &quot;backgroundColor&quot;: &quot;#dcd6ff&quot;,
      &quot;display&quot;: &quot;flex&quot;,
      &quot;flex&quot;: &quot;0 0 2.5em&quot;,
      &quot;flexDirection&quot;: &quot;row&quot;,
      &quot;padding&quot;: &quot;5px 8px&quot;
    }
  }&amp;gt;
  ...
&amp;lt;/div&amp;gt;
`;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;That’s all there is to it, and it will cover every tiny little CSS property you may be using. Change a color? Jest will warn you. Nudge the header one pixel down? Warning again. Tell Jest to update the snapshot for you, and you’re done.&lt;/p&gt;

&lt;p&gt;Note: with the current version of React, &lt;a href=&quot;https://github.com/facebook/react/issues/7386#issuecomment-238091398&quot;&gt;you may need to add this&lt;/a&gt; at the beginning: &lt;code class=&quot;highlighter-rouge&quot;&gt;jest.mock('react-dom')&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;mocking-children-components&quot;&gt;Mocking children components&lt;/h2&gt;

&lt;p&gt;Now let’s test a slightly more complicated component. Mady’s &lt;code class=&quot;highlighter-rouge&quot;&gt;TranslatorRow&lt;/code&gt; renders the original message to be translated, as well as several translations. But the translations themselves, which are editable, are handled by a child &lt;code class=&quot;highlighter-rouge&quot;&gt;Translation&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/mady.jpg&quot;&gt;
    &lt;img src=&quot;/img/mady.jpg&quot; alt=&quot;Mady's components in action&quot; /&gt;
&lt;/a&gt;
&lt;span class=&quot;caption text-muted&quot;&gt;Mady’s &lt;code class=&quot;highlighter-rouge&quot;&gt;Header&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;TranslatorRow&lt;/code&gt; components in action&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;We are writing &lt;em&gt;unit&lt;/em&gt; tests for &lt;code class=&quot;highlighter-rouge&quot;&gt;TranslatorRow&lt;/code&gt;, so we don’t want &lt;code class=&quot;highlighter-rouge&quot;&gt;Translation&lt;/code&gt;s to be rendered as well (they will have unit tests themselves). But we &lt;em&gt;do&lt;/em&gt; want to know which props are passed down to them.&lt;/p&gt;

&lt;p&gt;Jest’s mocking functionality comes in handy for this. Let’s use it on &lt;code class=&quot;highlighter-rouge&quot;&gt;Translation&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;jest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'../translation'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;jest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dataMockType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Translation&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Notice how we manage to include in the snapshot the props that are being passed down: &lt;code class=&quot;highlighter-rouge&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...props&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;. Notice also the &lt;code class=&quot;highlighter-rouge&quot;&gt;dataMockType&lt;/code&gt; attribute, which I found useful for easily identifying mocked components in the snapshot.&lt;/p&gt;

&lt;p&gt;Now, one of the actual unit tests may look like this:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TranslatorRow&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'../translatorRow'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MSG_WITH_TRANSLATIONS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'msgId'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'A message'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;translations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'id1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'es'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;translation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Un mensaje'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'id2'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ca'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;translation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Un missatge'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'renders correctly a message with translations'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TranslatorRow&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MSG_WITH_TRANSLATIONS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;langs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'es'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ca'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;
    &lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toJSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toMatchSnapshot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;If we look at the stored snapshot, we’ll see that an empty &lt;code class=&quot;highlighter-rouge&quot;&gt;div&lt;/code&gt; was correctly instantiated for each translation, together with the correct props:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
&amp;lt;div
  dataMockType=&quot;Translation&quot;
  lang=&quot;es&quot;
  msg={...}
  translation={
    Object {
      &quot;id&quot;: &quot;id1&quot;,
      &quot;lang&quot;: &quot;es&quot;,
      &quot;translation&quot;: &quot;Un mensaje&quot;
    }
  } /&amp;gt;
...
&amp;lt;div
  dataMockType=&quot;Translation&quot;
  lang=&quot;ca&quot;
  msg={...}
  translation={
    Object {
      &quot;id&quot;: &quot;id2&quot;,
      &quot;lang&quot;: &quot;ca&quot;,
      &quot;translation&quot;: &quot;Un missatge&quot;
    }
  } /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;snapshotting-relay-containers&quot;&gt;Snapshotting Relay containers&lt;/h2&gt;

&lt;p&gt;In the real application, &lt;code class=&quot;highlighter-rouge&quot;&gt;TranslatorRow&lt;/code&gt; is a Relay container, so it expects to be passed a &lt;code class=&quot;highlighter-rouge&quot;&gt;relay&lt;/code&gt; prop. Now, the Relay Higher-Order Component (HOC) lives outside our application and we may not even know the full shape of that prop.&lt;/p&gt;

&lt;p&gt;I found it more straightforward to just leave the HOC out of our unit test. For this purpose, our default export in &lt;code class=&quot;highlighter-rouge&quot;&gt;translatorRow.js&lt;/code&gt; is the wrapped &lt;code class=&quot;highlighter-rouge&quot;&gt;TranslatorRow&lt;/code&gt;, but we also expose the unwrapped version as a named export.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fragments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Relay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;QL&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;fragment&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Translation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getFragment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'msg'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;translations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;edges&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;lang&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Translation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getFragment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'translation'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}}}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TranslatorRow&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;PureComponent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Relay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createContainer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TranslatorRow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fragments&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TranslatorRow&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_TranslatorRow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// just for unit tests!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The snapshot test and the saved snapshot file will be exactly as before, except that we now need to use the named export and conform to Relay’s connection specs:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_TranslatorRow&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TranslatorRow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'../translatorRow'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MSG_WITH_TRANSLATIONS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'msgId'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'A message'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;translations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;edges&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'id1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'es'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;translation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Un mensaje'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'id2'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ca'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;translation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Un missatge'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;testing-dynamic-behavior-with-snapshots&quot;&gt;Testing dynamic behavior with snapshots&lt;/h2&gt;

&lt;p&gt;React components may respond to user interaction in different ways. One component might update its state and re-render, whereas another one might just call a function passed in as a prop.&lt;/p&gt;

&lt;p&gt;One thing they have in common, though, is that they need to attach event handlers to DOM elements to be notified of user interactions. And those handlers happen to be accessible in Jest and integrate well with snapshot testing; isn’t that awesome?&lt;/p&gt;

&lt;h3 id=&quot;dynamic-tests-on-a-self-rendering-component&quot;&gt;Dynamic tests on a self-rendering component&lt;/h3&gt;

&lt;p&gt;In this example, &lt;code class=&quot;highlighter-rouge&quot;&gt;TranslatorRow&lt;/code&gt; is hoverable and re-renders on &lt;code class=&quot;highlighter-rouge&quot;&gt;mouseEnter&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;mouseLeave&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TranslatorRow&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;PureComponent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kr&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;hovered&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;div&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hovered&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'hovered'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;onMouseEnter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;hovered&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})}&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;onMouseLeave&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;hovered&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})}&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/div&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;To test the component’s dynamic behavior, Jest gives us access to the full rendered tree, &lt;em&gt;including&lt;/em&gt; event handlers we can manually trigger:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'changes its class upon mouseEnter/mouseLeave'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;component&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TranslatorRow&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MSG_WITH_TRANSLATIONS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;langs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'es'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ca'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;
    &lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toJSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toMatchSnapshot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// snapshot 1&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onMouseEnter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toJSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;// re-renders&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toMatchSnapshot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// snapshot 2&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onMouseLeave&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toJSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;// re-renders&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toMatchSnapshot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// snapshot 3&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Jest will store not one, but three snapshots for this test, capturing all details of how the component should render in the idle and hovered states.&lt;/p&gt;

&lt;h3 id=&quot;dynamic-tests-with-callback-props&quot;&gt;Dynamic tests with callback props&lt;/h3&gt;

&lt;p&gt;In this second example, &lt;code class=&quot;highlighter-rouge&quot;&gt;TranslatorRow&lt;/code&gt; responds to &lt;code class=&quot;highlighter-rouge&quot;&gt;click&lt;/code&gt; events by calling its &lt;code class=&quot;highlighter-rouge&quot;&gt;onClick&lt;/code&gt; prop with its message ID:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TranslatorRow&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;PureComponent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/div&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;To test this behavior, we use Jest mock (or &lt;em&gt;spy&lt;/em&gt;) functions:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'reacts correctly to click events'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;spyOnClick&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;jest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TranslatorRow&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MSG_WITH_TRANSLATIONS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;langs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'es'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ca'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;spyOnClick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toJSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;spyOnClick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toBeCalledWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MSG_WITH_TRANSLATIONS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;OK, we’re not using snapshots at all in this example, but I included it to give you a broader picture.&lt;/p&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;This has barely scratched the surface of what &lt;a href=&quot;http://facebook.github.io/jest/&quot;&gt;Jest&lt;/a&gt; can do. After a period in which it was broadly perceived as hard to use and limited to Facebook’s own use cases, &lt;a href=&quot;https://twitter.com/cpojer&quot;&gt;Chris Pojer&lt;/a&gt; &lt;em&gt;et al&lt;/em&gt; did a great rewrite. It’s not just hype: give it a test drive!&lt;/p&gt;

&lt;p&gt;I hope this post gave you some ideas to finally address those virgin areas of your project that have never seen a test. I’ll whisper this to your ear: snapshot testing can even… &lt;em&gt;be fun!&lt;/em&gt;&lt;/p&gt;</content><author><name>Guillermo Grau</name></author><summary type="html">TL;DR    If you’re not testing your React (Native) components at all, or are relying on insufficient, high-level smoke tests, you’re not alone. Writing those unit tests must be one of the less rewarding experiences for a developer. But wait: snapshots to the rescue! Jest’s newest release features snapshot testing – and might well change your mind. Jest’s latest release has caused quite a stir, and understandably so: its snapshot testing feature alone is something of a mind-bender. If you’re like me, maybe you didn’t write unit tests for your React (Native) components for a number of valid reasons: “They’re hard to write” “They’re brittle” “They don’t bring so much value if you have at least some integration tests” Starting with Jest 14, though, you may need to revisit those arguments. Snapshots are trivial to use, they can easily be updated, and they provide full coverage of your components, dynamic behavior included. How do they work? Even that can be explained in just two bullets: The first time your test renders a component, a snapshot is taken and saved to a file. Upon re-run, the new render is diffed against the snapshot. If there’s a mismatch, you choose which one to keep (and maybe correct your application). On top of that, Jest provides a comprehensive testing framework, good performance, top-notch diffs and error context and lots of CLI goodies. Even coverage results out of the box! No wonder it got rave reviews. Haven’t tried snapshots yet? Let’s give them a spin. The following examples are loosely based on Mady, an application for software internationalization. Until now, Mady had absolutely no tests covering its React components. A hello-world component We’ll try snapshots on a very simple component first. Mady’s Header is a stateless functional component showing the application name and a couple of buttons. Lots of styles to be tested, but not much more. The full unit test for this component is so short you might think it’s a joke: /* eslint-env jest */ import React from 'react'; import renderer from 'react-test-renderer'; import Header from '../header'; it('renders correctly', () =&amp;gt; { const tree = renderer.create(&amp;lt;Header /&amp;gt;).toJSON(); expect(tree).toMatchSnapshot(); }); Run Jest, and a new snapshot will be created: exports[`renders correctly 1`] = ` &amp;lt;div style={ Object { &quot;WebkitFlex&quot;: &quot;0 0 2.5em&quot;, &quot;alignItems&quot;: &quot;center&quot;, &quot;backgroundColor&quot;: &quot;#dcd6ff&quot;, &quot;display&quot;: &quot;flex&quot;, &quot;flex&quot;: &quot;0 0 2.5em&quot;, &quot;flexDirection&quot;: &quot;row&quot;, &quot;padding&quot;: &quot;5px 8px&quot; } }&amp;gt; ... &amp;lt;/div&amp;gt; `; That’s all there is to it, and it will cover every tiny little CSS property you may be using. Change a color? Jest will warn you. Nudge the header one pixel down? Warning again. Tell Jest to update the snapshot for you, and you’re done. Note: with the current version of React, you may need to add this at the beginning: jest.mock('react-dom'). Mocking children components Now let’s test a slightly more complicated component. Mady’s TranslatorRow renders the original message to be translated, as well as several translations. But the translations themselves, which are editable, are handled by a child Translation component. Mady’s Header and TranslatorRow components in action We are writing unit tests for TranslatorRow, so we don’t want Translations to be rendered as well (they will have unit tests themselves). But we do want to know which props are passed down to them. Jest’s mocking functionality comes in handy for this. Let’s use it on Translation: jest.mock('../translation', () =&amp;gt; jest.fn((props) =&amp;gt; &amp;lt;div dataMockType=&quot;Translation&quot; {...props} /&amp;gt; )); Notice how we manage to include in the snapshot the props that are being passed down: {...props}. Notice also the dataMockType attribute, which I found useful for easily identifying mocked components in the snapshot. Now, one of the actual unit tests may look like this: import TranslatorRow from '../translatorRow'; const MSG_WITH_TRANSLATIONS = { id: 'msgId', text: 'A message', translations: [ { id: 'id1', lang: 'es', translation: 'Un mensaje' }, { id: 'id2', lang: 'ca', translation: 'Un missatge' }, ], }; it('renders correctly a message with translations', () =&amp;gt; { const tree = renderer.create( &amp;lt;TranslatorRow msg={MSG_WITH_TRANSLATIONS} langs={['es', 'ca']} /&amp;gt; ).toJSON(); expect(tree).toMatchSnapshot(); }); If we look at the stored snapshot, we’ll see that an empty div was correctly instantiated for each translation, together with the correct props: ... &amp;lt;div dataMockType=&quot;Translation&quot; lang=&quot;es&quot; msg={...} translation={ Object { &quot;id&quot;: &quot;id1&quot;, &quot;lang&quot;: &quot;es&quot;, &quot;translation&quot;: &quot;Un mensaje&quot; } } /&amp;gt; ... &amp;lt;div dataMockType=&quot;Translation&quot; lang=&quot;ca&quot; msg={...} translation={ Object { &quot;id&quot;: &quot;id2&quot;, &quot;lang&quot;: &quot;ca&quot;, &quot;translation&quot;: &quot;Un missatge&quot; } } /&amp;gt; Snapshotting Relay containers In the real application, TranslatorRow is a Relay container, so it expects to be passed a relay prop. Now, the Relay Higher-Order Component (HOC) lives outside our application and we may not even know the full shape of that prop. I found it more straightforward to just leave the HOC out of our unit test. For this purpose, our default export in translatorRow.js is the wrapped TranslatorRow, but we also expose the unwrapped version as a named export. const fragments = { msg: () =&amp;gt; Relay.QL` fragment on Message { id text ${Translation.getFragment('msg')} translations(first: 100000) { edges { node { id lang ${Translation.getFragment('translation')} }}} } `, }; class TranslatorRow extends React.PureComponent { // ... } export default Relay.createContainer(TranslatorRow, { fragments }); export { TranslatorRow as _TranslatorRow }; // just for unit tests! The snapshot test and the saved snapshot file will be exactly as before, except that we now need to use the named export and conform to Relay’s connection specs: import { _TranslatorRow as TranslatorRow } from '../translatorRow'; const MSG_WITH_TRANSLATIONS = { id: 'msgId', text: 'A message', translations: { edges: [ { node: { { id: 'id1', lang: 'es', translation: 'Un mensaje' }, } }, { node: { { id: 'id2', lang: 'ca', translation: 'Un missatge' }, } }, ] }, }; // ... Testing dynamic behavior with snapshots React components may respond to user interaction in different ways. One component might update its state and re-render, whereas another one might just call a function passed in as a prop. One thing they have in common, though, is that they need to attach event handlers to DOM elements to be notified of user interactions. And those handlers happen to be accessible in Jest and integrate well with snapshot testing; isn’t that awesome? Dynamic tests on a self-rendering component In this example, TranslatorRow is hoverable and re-renders on mouseEnter and mouseLeave: class TranslatorRow extends React.PureComponent { constructor() { super(); this.state = { hovered: false }; } render() { return ( &amp;lt;div className={this.state.hovered ? 'hovered' : ''} onMouseEnter={() =&amp;gt; this.setState({ hovered: true })} onMouseLeave={() =&amp;gt; this.setState({ hovered: false })} &amp;gt; {/* ... */} &amp;lt;/div&amp;gt; ); } } To test the component’s dynamic behavior, Jest gives us access to the full rendered tree, including event handlers we can manually trigger: it('changes its class upon mouseEnter/mouseLeave', () =&amp;gt; { const component = renderer.create( &amp;lt;TranslatorRow msg={MSG_WITH_TRANSLATIONS} langs={['es', 'ca']} /&amp;gt; ); let tree = component.toJSON(); expect(tree).toMatchSnapshot(); // snapshot 1 tree.props.onMouseEnter(); tree = component.toJSON(); // re-renders expect(tree).toMatchSnapshot(); // snapshot 2 tree.props.onMouseLeave(); tree = component.toJSON(); // re-renders expect(tree).toMatchSnapshot(); // snapshot 3 }); Jest will store not one, but three snapshots for this test, capturing all details of how the component should render in the idle and hovered states. Dynamic tests with callback props In this second example, TranslatorRow responds to click events by calling its onClick prop with its message ID: class TranslatorRow extends React.PureComponent { render() { const { onClick, msg } = this.props; return ( &amp;lt;div onClick={() =&amp;gt; onClick(msg.id)}&amp;gt; {/* ... */} &amp;lt;/div&amp;gt; ); } } To test this behavior, we use Jest mock (or spy) functions: it('reacts correctly to click events', () =&amp;gt; { const spyOnClick = jest.fn(); const tree = renderer.create( &amp;lt;TranslatorRow msg={MSG_WITH_TRANSLATIONS} langs={['es', 'ca']} onClick={spyOnClick} /&amp;gt; ).toJSON(); tree.props.onClick(); expect(spyOnClick).toBeCalledWith(MSG_WITH_TRANSLATIONS.id); }); OK, we’re not using snapshots at all in this example, but I included it to give you a broader picture. Conclusions This has barely scratched the surface of what Jest can do. After a period in which it was broadly perceived as hard to use and limited to Facebook’s own use cases, Chris Pojer et al did a great rewrite. It’s not just hype: give it a test drive! I hope this post gave you some ideas to finally address those virgin areas of your project that have never seen a test. I’ll whisper this to your ear: snapshot testing can even… be fun!</summary></entry><entry><title type="html">Untangling spaghetti logs</title><link href="https://guigrpa.github.io/2016/07/18/untangling-spaghetti-logs/" rel="alternate" type="text/html" title="Untangling spaghetti logs" /><published>2016-07-18T12:00:00+00:00</published><updated>2016-07-18T12:00:00+00:00</updated><id>https://guigrpa.github.io/2016/07/18/untangling-spaghetti-logs</id><content type="html" xml:base="https://guigrpa.github.io/2016/07/18/untangling-spaghetti-logs/">&lt;p&gt;&lt;strong&gt;&lt;em&gt;TL;DR&lt;/em&gt;    Logging might not be super-exciting, but when you hit your head against a wall during debugging, you sometimes wish you’d used better tools. &lt;a href=&quot;https://github.com/guigrpa/storyboard&quot;&gt;Storyboard 2.0&lt;/a&gt; has just been &lt;a href=&quot;https://github.com/guigrpa/storyboard/blob/master/CHANGELOG.md&quot;&gt;released&lt;/a&gt; and provides a flexible architecture, a powerful feature set and a novel approach to &lt;del&gt;storytelling&lt;/del&gt; logging.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OK, so it might not look like the most sexy subject to blog about. When you are building the most exciting new application, why would you even &lt;em&gt;want&lt;/em&gt; to think about logging and not just… go out play Pokémon?&lt;/p&gt;

&lt;p&gt;The fact is: sooner or later, just as with testing, you will &lt;em&gt;need&lt;/em&gt; to give it some thought. In a typical client-server web application, you will start having concurrent sessions. And even at the client side, where you have only one user, simultaneous actions will start making your logs less and less readable. Debugging, or just grasping what’s going on, can quickly turn into a nightmare if you don’t take the necessary precautions.&lt;/p&gt;

&lt;p&gt;Even if you’re not building a web app, you may be overwhelmed by your logs. In my current project, I’m developing a Node-only application with multiple bidirectional interfaces (an interactive SSH session, a proprietary TCP link, an interactive CLI conversation with the user), all of them generating events like crazy.&lt;/p&gt;

&lt;p&gt;In an ideal world, I’d like to have an easy-to-use library that would let me filter logs by relevance or source module, attach objects, group them hierarchically in stories (“John clicks on Buy” + “Goes to check-out” ⊂ “John visits the store”), persist them to a file/database, send them to a separate process for trend analysis… The icing on the cake? I’d love to see what’s happening at the client and the server &lt;em&gt;in a single place&lt;/em&gt; (how about a Chrome DevTools extension for that?).&lt;/p&gt;

&lt;p&gt;Well… &lt;strong&gt;have you checked out &lt;a href=&quot;https://github.com/guigrpa/storyboard&quot;&gt;Storyboard&lt;/a&gt; yet?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/Storyboard.gif&quot;&gt;
    &lt;img src=&quot;/img/Storyboard.gif&quot; alt=&quot;Storyboard DevTools in action&quot; /&gt;
&lt;/a&gt;
&lt;span class=&quot;caption text-muted&quot;&gt;The Storyboard DevTools in action&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;a-flexible-logging-architecture&quot;&gt;A flexible logging architecture&lt;/h2&gt;

&lt;p&gt;Storyboard is based on a hub component that receives messages and broadcasts them to all attached &lt;em&gt;listeners&lt;/em&gt;, or &lt;em&gt;plugins&lt;/em&gt;. Despite their name, listeners can also send messages to the hub, making them quite powerful.&lt;/p&gt;

&lt;p&gt;Let’s say we have a typical client-server application. You could configure the isomorphic Storyboard library like this for development (legend at the bottom):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/sb-typical-arch.png&quot;&gt;
    &lt;img src=&quot;/img/sb-typical-arch.png&quot; alt=&quot;Storyboard logging config for a client-server application&quot; /&gt;
&lt;/a&gt;
&lt;span class=&quot;caption text-muted&quot;&gt;Storyboard logging configuration for a client-server application&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;In this architecture, the server-side hub receives stories and relays them to console, disk and database. In addition, server logs are sent via WebSockets to the client-side hub, which relays server and client stories to the console as well as to the Storyboard DevTools.&lt;/p&gt;

&lt;p&gt;Signalling messages are exchanged between the DevTools extension and the WebSocket Server in both directions. Such messages are required for user authentication or, more interestingly, to configure server-side log filters from the extension itself. If you want to get more logs from a particular server module, you can just tweak the filter (say, from &lt;code class=&quot;highlighter-rouge&quot;&gt;*:INFO&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;*:INFO, suspect:DEBUG&lt;/code&gt;) and logs from the &lt;code class=&quot;highlighter-rouge&quot;&gt;suspect&lt;/code&gt; module will begin to pour in, no reset required.&lt;/p&gt;

&lt;h2 id=&quot;other-example-architectures&quot;&gt;Other example architectures&lt;/h2&gt;

&lt;p&gt;In some cases, you might not be able to include Storyboard in your existing project because your application might not be written in JavaScript, or because you simply don’t want to change it. In this scenario, even though some benefits of the library will be lost, you can still use the Storyboard &lt;a href=&quot;https://github.com/guigrpa/storyboard#cli-tool&quot;&gt;CLI&lt;/a&gt;, which wraps your application’s default input/output streams (&lt;code class=&quot;highlighter-rouge&quot;&gt;stdin&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;stdout&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;stderr&lt;/code&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/sb-with-adapter.png&quot;&gt;
    &lt;img src=&quot;/img/sb-with-adapter.png&quot; alt=&quot;Logging configuration for a Node-only application with the Storyboard CLI tool&quot; /&gt;
&lt;/a&gt;
&lt;span class=&quot;caption text-muted&quot;&gt;Logging configuration for a Node-only application with the Storyboard CLI tool&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This even works with a shell! Just try &lt;code class=&quot;highlighter-rouge&quot;&gt;sb --server bash&lt;/code&gt; and you’re instantly sharing your shell session with others via HTTP.&lt;/p&gt;

&lt;p&gt;As a final example, here is a Storyboard configuration with support for mobile clients. In this case, the WebSocket client is configured with &lt;code class=&quot;highlighter-rouge&quot;&gt;uploadClientStories: true&lt;/code&gt;. Uploaded stories will not pollute the server’s logs as they are written to console or file, but they will get saved to the database for postprocessing, and re-broadcast to other clients with the Storyboard DevTools extension.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/sb-mobile.png&quot;&gt;
    &lt;img src=&quot;/img/sb-mobile.png&quot; alt=&quot;Logging configuration including upload of mobile client logs&quot; /&gt;
&lt;/a&gt;
&lt;span class=&quot;caption text-muted&quot;&gt;Logging configuration including upload of mobile client logs&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Logging is something we should keep in mind when developing an application, be it large or small, same as testing, security and other cross-cutting concerns. The flexible architecture of Storyboard may help you untangle your logs and squeeze the most out of them!&lt;/p&gt;</content><author><name>Guillermo Grau</name></author><summary type="html">TL;DR    Logging might not be super-exciting, but when you hit your head against a wall during debugging, you sometimes wish you’d used better tools. Storyboard 2.0 has just been released and provides a flexible architecture, a powerful feature set and a novel approach to storytelling logging.</summary></entry><entry><title type="html">Painless immutability</title><link href="https://guigrpa.github.io/2016/06/16/painless-immutability/" rel="alternate" type="text/html" title="Painless immutability" /><published>2016-06-16T12:00:00+00:00</published><updated>2016-06-16T12:00:00+00:00</updated><id>https://guigrpa.github.io/2016/06/16/painless-immutability</id><content type="html" xml:base="https://guigrpa.github.io/2016/06/16/painless-immutability/">&lt;p&gt;&lt;strong&gt;&lt;em&gt;TL;DR&lt;/em&gt;    With the popularity of Immutable.js and Seamless-immutable going through the roof, who needs yet another immutability library? Maybe you, if you &lt;em&gt;don’t want to lock read access to your data through a non-native API, need reasonable write performance and an easy-to-use API&lt;/em&gt;. That’s exactly the balance &lt;a href=&quot;https://github.com/guigrpa/timm&quot;&gt;Timm&lt;/a&gt; tries to strike.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We’ve read &lt;a href=&quot;http://jlongster.com/Using-Immutable-Data-Structures-in-JavaScript&quot;&gt;the&lt;/a&gt; &lt;a href=&quot;http://redux.js.org/docs/introduction/ThreePrinciples.html&quot;&gt;posts&lt;/a&gt;, watched the &lt;a href=&quot;https://youtu.be/I7IdS-PbEgI&quot;&gt;videos&lt;/a&gt;, understood the &lt;a href=&quot;https://en.wikipedia.org/wiki/Immutable_object&quot;&gt;concepts&lt;/a&gt;. Immutability can be really useful in many scenarios; for example:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;We perform some lengthy computations on data and want to memoize the results, reusing them until inputs change.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We want to implement an Undo/Redo functionality in an elegant way.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We want to untangle our application’s state and use something like Redux with time travel, serialization, rehydration, you name it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We’re stuck with our React application performance and have heard of &lt;code class=&quot;highlighter-rouge&quot;&gt;shouldComponentUpdate&lt;/code&gt;’s wonders.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In all of these cases, using immutable data is probably the way to go. It can make code more predictable, allows trivial object comparisons, and feels right at home with functional programming. What else could we ask for?&lt;/p&gt;

&lt;p&gt;As it turns out, immutable operations don’t come without their own drawbacks. They’ll never be as fast as in-place mutations, no matter how hard you try. You’ll need to bend your mind around some algorithms, especially recursive ones. And it may become a pain to work with in some cases, depending on the tools/libraries you work with.&lt;/p&gt;

&lt;p&gt;But what if we found a way to alleviate the cognitive burden on the developer, keep performance reasonable, and allow us to reap the benefits of immutability? Enter &lt;a href=&quot;https://github.com/guigrpa/timm&quot;&gt;Timm&lt;/a&gt;, a tiny library that tries to solve some of these trade-offs.&lt;/p&gt;

&lt;h2 id=&quot;trade-off-1-seamlessness-vs-protection&quot;&gt;Trade-off #1: seamlessness vs. protection&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://facebook.github.io/immutable-js&quot;&gt;Immutable.js&lt;/a&gt; is one of the big names in the immutability arena, a rock-solid library that offers you everything you’ll &lt;em&gt;ever&lt;/em&gt; need and then some more. Performance is also excellent, considering the many things it does, and its objects (Maps, Lists and many others) are opaque, so they’re protected against your accidental mutations.&lt;/p&gt;

&lt;p&gt;However, after using it in several projects I’ve always felt the friction of mixing Immutable.js’ Maps and Lists with native JS objects and arrays. It’d be impossible to count how many times I got strange runtime errors because I forgot to use Map’s getter (&lt;code class=&quot;highlighter-rouge&quot;&gt;image.get('url')&lt;/code&gt;), instead of plain old dot notation (&lt;code class=&quot;highlighter-rouge&quot;&gt;image.url&lt;/code&gt;), or a warning because I took the familiar array &lt;code class=&quot;highlighter-rouge&quot;&gt;length&lt;/code&gt; property instead of List’s &lt;code class=&quot;highlighter-rouge&quot;&gt;size&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So: &lt;em&gt;seamless or protected&lt;/em&gt;? Timm goes for &lt;em&gt;seamless&lt;/em&gt;. It would be possible to have native &lt;em&gt;and&lt;/em&gt; protected objects via &lt;code class=&quot;highlighter-rouge&quot;&gt;Object.freeze()&lt;/code&gt;, but there seems to be some performance bottlenecks (or alternatively &lt;a href=&quot;https://github.com/rtfeldman/seamless-immutable#performance&quot;&gt;different behaviours&lt;/a&gt; in Development and Production mode, which seems just as bad). In conclusion: you &lt;em&gt;can&lt;/em&gt; accidentally mutate your objects (watch out!), but:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;You will be able to access your data in a straightforward way; and&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;You won’t be locked in to a particular library, for something as ubiquitous as data management.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;trade-off-2-simplicitysize-vs-write-performance&quot;&gt;Trade-off #2: simplicity/size vs. write performance&lt;/h2&gt;

&lt;p&gt;Immutable.js aims at being both comprehensive and performant. Optimising read/write speeds in immutable operations while keeping an attractive API is not trivial, and Immutable.js uses advanced techniques (&lt;a href=&quot;https://en.wikipedia.org/wiki/Persistent_data_structure&quot;&gt;persistent data structures&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Hash_array_mapped_trie&quot;&gt;structural sharing&lt;/a&gt;) to achieve just that.&lt;/p&gt;

&lt;p&gt;While not providing all the bells and whistles, Timm is 10 times smaller (~ 1 kB minified and compressed) and uses much more basic tools, although it also focuses on performance. Reads are as fast as native (you don’t even need the library for that), and writes are also reasonably fast (&lt;a href=&quot;https://github.com/guigrpa/timm#benchmarks&quot;&gt;benchmarks&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;On small arrays/objects: same performance as Immutable.js for shallow writes, becoming increasingly faster than Immutable.js for deeper writes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;On large arrays or objects (see &lt;em&gt;Array: write&lt;/em&gt; in the figure below, where arrays have 1000 elements): increasingly slower than Immutable.js as arrays become longer or objects have more properties. This is where Immutable.js really shines!&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Faster (even &lt;em&gt;extremely&lt;/em&gt; faster) than &lt;a href=&quot;https://github.com/rtfeldman/seamless-immutable&quot;&gt;Seamless-immutable&lt;/a&gt;, which also uses native objects.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/guigrpa/timm#benchmarks&quot;&gt;
    &lt;img src=&quot;/img/timm-benchmarks.png&quot; alt=&quot;Performance comparison&quot; /&gt;
&lt;/a&gt;
&lt;span class=&quot;caption text-muted&quot;&gt;Read/write benchmarks for Immutable.js, Timm and Seamless-immutable&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;and-what-about-the-js-spread-operator&quot;&gt;…and what about the JS spread operator?&lt;/h2&gt;

&lt;p&gt;Finally, why not exploit ES6’s shiny new &lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Spread_operator&quot;&gt;array spread operator&lt;/a&gt; and its upcoming &lt;a href=&quot;https://github.com/sebmarkbage/ecmascript-rest-spread&quot;&gt;sibling for objects&lt;/a&gt;? After all, native syntax can’t be beaten! Why not do the following?&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'bar'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Why not do this...&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;obj2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'boo'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ...instead of this?&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;obj2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;timm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'boo'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The object spread operator certainly seems nicer. However, beware:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'bar'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Future spread operator without changes&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;obj2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'bar'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;obj2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// -&amp;gt; false&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Timm without changes&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;obj2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;timm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'bar'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;obj2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// -&amp;gt; true!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The spread operator &lt;em&gt;always&lt;/em&gt; creates a new object, no matter whether we are actually modifying the original one. By contrast, Timm and Immutable.js only instantiate a new one (lazily) when they detect that the operation is in fact mutating the object; this way, you’ll create fewer objects, alleviating memory requirements and garbage collection events. And what’s more: you’ll get fewer false positives when checking whether an object has changed.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;After all this, which is the most suitable option?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Don’t forget the obvious: do you really need immutability? Probably yes, but use your best judgement. If performance is crucial and you can sacrifice code elegance and the other nice perks immutability brings along, well… just &lt;strong&gt;mutate in peace!&lt;/strong&gt; I mean, &lt;em&gt;in place&lt;/em&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If you need a complete, battle-tested library and don’t mind the lock-in associated to a non-native API even for reads: use &lt;strong&gt;Immutable.js&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If you prefer plain arrays/objects, use &lt;strong&gt;Timm&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If your typical use cases involve more reading than writing, use &lt;strong&gt;Timm&lt;/strong&gt; as well.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If you do a lot of writes on very long arrays or fat objects, use &lt;strong&gt;Immutable.js&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;</content><author><name>Guillermo Grau</name></author><summary type="html">TL;DR    With the popularity of Immutable.js and Seamless-immutable going through the roof, who needs yet another immutability library? Maybe you, if you don’t want to lock read access to your data through a non-native API, need reasonable write performance and an easy-to-use API. That’s exactly the balance Timm tries to strike.</summary></entry></feed>