I've been setting up a new Ionic Framework (with React) project from scratch.  I want it to be the baseline for all my future projects.  I'm configuring it to have the development workflow I prefer including testing with React Testing Library.

In one of my tests, I take a snapshot of each route.  This may not be a great idea, and I may remove it later.  However, for now, it works.  Unfortunately, after making a few modifications to the structure of the project, my snapshots started failing.  This was due to adding a ViewManager.

My snapshots began failing like this:

At first, I just went ahead and updated my snapshot because that's the new norm.  Unfortunately, all the subseqent test runs also started failing with issues like this:

Clearly the IonRouterOutlet is generating a unique id on every render.  So, how to solve?  After some digging, the solution turned out to be a custom Jest snapshot serializer.

At first, I had no idea what a serializer was doing under the hood; so, I resorted to the console log:

expect.addSnapshotSerializer({
  test: val => typeof val === 'string',
  print: val => {
    console.log(`val="${val}"`);
    return val;
  },
});

The serializer has a test that lets you decide if you're going to modify the value.  In my case, I wanted to edit strings only.  Next, I just logged out the value so I could see it in the terminal.  It looked like this:

That string 8R2L6TJCYP seemed to be the culprit.  So, I just decided to rewrite to always be a consistent string:

expect.addSnapshotSerializer({
  test: val => typeof val === 'string',
  print: val => {
    console.log(`val="${val}"`);
    const newVal = val.replace(/^[A-Z0-9]{10}$/g, 'ABC123');
    console.log(`newVal="${newVal}"`);
    return `"${newVal}"`;
  },
});

Basically, the regex looks for any 10 character string that has any combination of uppercase letters and numbers and replaces it with ABC123.  

Now, there is some risk to this approach.  Some other string in the code could match that pattern.  However, I feel pretty comfortable with it.  I don't know any developers that use class names or properties with uppercase letters.  If this ever became a problem, I could look at hardening this serializer.

Now, the logging looks like this:

One odd thing about the replacement string is that I had to wrap it in quotes.  I don't know why exactly, but not doing so led to all quotes throughout the snapshot being replaced like this:

Now, my snapshots are no longer different between runs because they always look this:

You can do a lot more with serializers.  For example, you can format test strings or modify objects as well.  Checkout this example by Kent C. Dodds.