Let's start this lesson out by adding a few dependency. I'll run yarn, add, enzyme, enzyme-to-json, react-addons-test-utils.
The next thing we need to do is include a couple of test helper utilities. I'm going to make a new file, and I'll call it intl-enzyme.js.
I've included a link to this helper file in the description of this video. Go ahead, and copy and paste this file into your project. What this helper will do is wrap the component being tested with all of the correct parent components, contexts, and props required by react-intl.
It also gives us the ability to use Enzyme's shallow rendering, or full mount rendering. With our dependencies installed, and our test helper utility added, let's start writing some tests. I'll add the test file in a tests folder inside of components.
I'll add a new file called bookdetail.test.js. First, we'll important React. I'll import mountWithIntl and shallowWithIntl from our intl-enzyme helper file.
Next, I'll import toJson from enzyme-to-json. Finally, I'll import the book detail component that we want to test.
I'll set up a wrapper variable. This is going to hold the rendered component in each test assertion. Now, we can write our first describe block. We will say describe book detail. We'll write our first assertion. We'll say it renders expected markup.
Inside of this it block, we'll set wrapper equal to an instance of mountWithIntl. I'll create a book detail component. We also have to provide the match prop that's coming from React Router, so that's expecting an object. We'll pass it params.
That's an object that has book ID. We'll just provide it one. We'll write expect toJson. That's a method, so we'll pass our wrapper to that method.
We're going to expect that that will match the snapshot. I'll run yarn test to start Jest.
That's it. We've got our first test. However, there's one problem with this test. Jest's docs correctly say that tests should be deterministic, meaning that running the same test multiple times on a component that has not changed should produce the same result.
Let's hop over to the book detail component for a second. The problem with our test lies with this formatted relative component. It takes a date, and renders the human-readable string representation of that date.
If we open up the generated snapshot from Jest, I've found that formatted relative component. You can see that it output a span with a text of last month. If we were to run this test again without touching any of the tests or component code -- say, next month -- this snapshot test would fail because this string being created would be different.
In order to fix this, we need to mock date.now inside of our test to return the same date every time it's run. Let's go back to our test. After our imports, I'm going to write date.now. I'm going to set that equal to jest.fn.
Inside of that mock function, I'm going to immediately return a timestamp. No matter when this is run, any date.now method will always return this timestamp, ensuring that the date will always be the same. Now that we've seen a snapshot, let's take a look at using Enzyme to assert specific things with regards to react-intl components.
Let's set up a nested describe block. For this, I'll just write Intl messages. Inside of here, I'll add a before each. This means that before every test inside of this describe block is run, execute the code inside of the body of this before each function.
I'm going to set wrapper equal to shallowWithIntl. I'll pass book detail. Again, we need the same match prop here. Since our component is wrapped with the inject-intl higher-order component, calling shallowWithIntl will just provide the instance of Intl instead of our book detail component.
Once shallowWithIntl executes book detail, we need to call .first, which gets the first child of the component, which is our book detail component. Then we need to add .shallow to that in order to shallow render our book detail component.
Now, let's add an it block. We'll test that it renders a single purchase message. Our expectation will read expect wrapper.find.
I'm actually going to search for an object. I'm going to say find an object with a key of ID and a value of detail.purchase. I expect that to have length of one. That test passes as well.
Finally, let's test that this component passes the number of merchants to a new window message. Our expectation will read expect wrapper.find. Again, I'm looking for an object. I'll look for an ID with a value of detail.window.
Once that's found, I want to look at the values prop of that component. I'll say prop, and I'll look for values. I expect that values prop to match object, and I expect that to match an object of num merchants. I expect there to be three of them.
There we go. We've got another passing test.