Anton Korzunov
Posted on May 16, 2019
As one my friend once said - In every joke there is a joke. The inner joke.
This is quite deep philosophical observation which means basically - you might derive one joke from another, making the first one even more funny. You may find endless reflections and nuances, making a little joke a real THING.
And here is the joke of mine:
Does not sounds funny? So let's find a real joke inside the joke, and just do that it said - let's create a shallow snapshot! :)
import React from 'react';
import Link from 'react-router';
import Section from './section';
// const Section = ({children}) => <section><SomeStuff/>{children}</section>
describe('Mark-testing', () => {
it('should match snapshot', () => {
expect(shallow(<Section><Link>click me</Link></Section>)).toMatchSnapshot());
});
});
What we just did? We tested a skeleton
, and, long story shot, the result would be....
<section>
<SomeStuff />
<Link to=\\"#\\">
click me
</Link>
</section>
We tested nothing.
That was something expected. This is how shallow rendering works, and that's a feature, not a bug. A reason Why I Always Use Shallow Rendering.
But... you are right - that's absolutely useless π’
So - shallow
would not help is find the inner joke. Let's mount
then!
describe('Mark-mount-testing', () => {
it('should match snapshot', () => {
expect(mount(<Section><Link>click me</Link></Section>)).toMatchSnapshot());
});
});
What would happen next? π Error: Uncaught [Error: Invariant failed: You should not use <Link> outside a <Router>]
So let's wrap everything a router and rerun. Now our snapshot is:
<StaticRouter>
<Router history={{...}} staticContext={{...}}>
<Section>
<section>
<SomeStuff>
<div>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
</div>
</SomeStuff>
<Link to=\\"#\\">
<a onClick={[Function: onClick]} href=\\"/\\">
click me
</a>
</Link>
</section>
</Section>
</Router>
</StaticRouter>
You know - that's much better than before but at the same time a bit more than I expected.
In my personal experience, with StyledComponets, MoreComponents and MoreDeeperComponents snapshots could be HUGE and provide nothing more, but noise. Uter crap!
Could we find something in between?
React Testing Recipes has a few hints about making snapshots testing better:
Itβs typically better to make more specific assertions than to use snapshots. These kinds of tests include implementation details so they break easily, and teams can get desensitized to snapshot breakages. Selectively mocking some child components can help reduce the size of snapshots and keep them readable for the code review.
By
mocking
they assumedjest.mock
, but I've got another solution for you - mocking components, not modules.
Yes, piece a cake. Let's use a finite component idea, I've explained in depth here:
import React from 'react';
import Link from 'react-router';
import { createElement, remock } from 'react-remock';
import Section from './section';
describe('Mark-finite-mount-testing', () => {
it('should match snapshot', () => {
remock.push();
// replace Link by another component
remock.mock(Link, (_, props) => createElement('router-link', props));
expect(shallow(<Section><Link>click me</Link></Section>)).toMatchSnapshot());
remock.pop();
});
});
Here we just mocked a Link
component, removing the dependency to Router
and kept the rest unchanged. Updated snapshot is:
<Section>
<section>
<SomeStuff>
<div>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
</div>
</SomeStuff>
<router-link to="#">
click me
</router-link>
</section>
</Section>
Clean and Sound. Just without some branches we cuted off, making your snapshot more shallow, but not as shallow, as using the real shallow
π€―
You might mock anything providing a variable
, like I did, or name
, or regexp
. Cut, or replace (we kept children of a Link
), as much as needed.
A good example is a FancyButton, which actually is a combination of 2 <ThemeProviders>
, a few <StyledComponents>
, and a few more HOCs
.
This is a ONE Component for you
With remock you might make it a ONE component for your snapshot.
PS
Examples were provided are in the Jest syntax, while snapshots were generated using mocha
+ chai-jest-snapshot
const wrapper = mount(<Section><Link to="#">click me</Link></Section>);
expect(wrapper.debug()).to.matchSnapshot();
// ^ yes, wrapper.debug() ^ produces the best code,
// while `.html()` or `.render` or hides some details(props)
// you might wanna use, or generates a single line of code,
// you will not able to review/merge.
So, you will not believe, but finite component and react-remock could make shallow snapshots a thing. If you use a
mount
... That was the joke :)
Mark authors best memes. I liked this one.
PS: And the other one - there is also the same joke about dependency mocking, and you know... for the things like stricter it's a fun!
Posted on May 16, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.