Jump to content
Development

InertiaJS and testing deferred props.

We’re big fans of InertiaJS here at Jump 24, InertiaJS allows us to combine a fully featured, interactive front end written in Vue or React, with the full power of a Laravel back end, without any messy or complex API layers between them.

InertiaJS 2.0 was released late last year, and with it came some fantastic new features such as prefetching, deferred props, lazy loading, and much more.

One of our favourites here is the new deferred props feature, this powerful little feature allows us to return any vital information for our page first, but defer anything that isn’t immediately required, such as something further down the page, or even hidden in a modal or sidebar.

I immediately started implementing deferred props in a few Controllers in a project, and in the browser, everything worked as expected, but then suddenly, the developers curse hit, and I had some failing tests in my test suite, the problem, the props that I had just changed to deferred, were now missing from responses that I was asserting against, which when you think about it, is expected, but at first, I didn’t know what I could do to fix this, the InertiaJS docs didn’t mention anything around testing the new features, so I had to take a step back and investigate this myself, but first, let’s have a look at where we are.

The Setup

I have this simple Laravel controller that is returning three blogs, and all the tags in the system, with a count of how many blogs they are attached to, this is a many to many relationship using a pivot table, the blogs are obviously vital to our page, but the tags are hidden away in a sidebar, and a prime candidate for getting deferred.

Here’s our page as it stands, showing the tags in their own sidebar

The Laravel controller that powers this page is super simple, and it defers to Actions to get our Blogs and Tags, the actions are just simple Eloquent queries that map to resources.

And the relative part of our Vue component just loops round each tag within a Sidebar component

Finally, our test class has four methods, one that make sure the page returns an HTTP OK, another that ensures the expected component is rendered by Inertia, one that checks the Inertia props has the blogs, and that they are in the expected order, and finally, a test that ensures that it has tags, and again in the expected order.

Implementing Deferred Props

To update our Controller to use deferred props, we simply have to wrap it in Inertia::defer(), now when we refresh the page in the browser, we’ve got two HTTP request, one for the page it self, which returns everything Inertia needs, including our blogs, and then a second AJAX request for the tags, which internally Inertia calls a partial request, this means that if those tags took a few seconds to return, the actual main page isn’t impacted, and the tags come separately in a partial request. Inertia even offers components on the front end to automatically hide anything using deferred props until they have been resolved, but that isn’t required in this example.

Now, if we rerun our test suite, we have that one failing test I mentioned

Investigating the failing test

If we look at the output from the test in PHPStorm, its telling us that Property [tags] does not exist this makes sense because its now deferred, as we saw in the browser, tags isn’t being sent in the original request, it’s only sent the subsequent (partial) request for the deferred props, so how do we tell Inertia that we want to treat this as a deferred, or partial request?

Source Diving Inertia

As I said before, there was nothing mentioning this in the Inertia documentation, so I started source diving into the Inertia Response class on GitHub, this is the class responsible for taking our controller that returns an Inertia component, and transforming it into a response that Inertia can recognise on the front end. Way down on line 120, there is a call to a method resolveDeferredProps() at first glance, this sounds like what we’re looking for, but when looking at that method, it is only instructing the front end about the deferred props, not actual evaluating them, so let’s step back.

On line 108 Inertia is working out all the props needed for this request, it calls a few different methods, including one that sounds like what we’re looking for, resolvePartialProperties()let’s check out what this method does.

The first thing it does, is check if the request is a partial request, by checking if a component name passed through the headers, matches the component name from the Controller – so that’s the first piece of the puzzle, notice Inertia is using a constant from a Header class, rather than the hard coded header X-Inertia-Partial-Component, keep that in mind as we’ll be able to use it later in our updated test.

Next, Inertia is looking in another header to see what props the partial request has asked for, so in our case, that is the tags prop.

Fixing our test

From source diving the Inertia Response class, we now know we need to add two headers to our request from our test, one for the component name, and one for the prop name, which will then cause Inertia’s response handler to treat this as a partial request and evaluate the deferred props we ask for, so let’s implement those two headers, remember we need for that contains our component name, and one for which props we need, and to keep things simple, we’ll use the constants on the Header class Inertia provides.

That should do it, so lets rerun our tests in PHPStorm, and this time, all of our tests are passing again

For me, the headers in the $this-get() call look a little messy, so I extracted these out into a method, I could then add this method to a base TestCase class, or into a trait used in the Test suite, making the test more readable.

If we go back to the browser, and have a look at the request headers for that partial request Inertia made, we can see those two headers we’ve just added to our request, which shows that what we identified in the Inertia Response class is exactly what Inertia is doing behind the scenes when the front end is requesting a deferred prop from the back end.

Summary

So, in summary, if you’re making use of the new Inertia deferred props in your app, and you’ve encountered some failing tests due to the now deferred props not being in your initial response (Which makes sense right?) – we simply need to update those failing tests to instruct Inertia to handle the request as a partial request, and to do that, we just need update the test to add those two headers, the first tells Inertia that it is a deferred partial request, and the second what deferred props you want in the response.

If in your test your currently asserting against ‘normal’ and deferred props in the same test, then this approach wont work, as you’ll now have the opposite problem, your ‘base’ props won’t be there (For example the blogs prop), but the deferred prop will be, so you’ll have to extract your current test into two tests, one that asserts against the base props, in my case the blogs, and another that asserts against the deferred props, in my case the tags.

But I’m using Pest for testing

While I wrote the tests for this in PHPUnit, you can easily use this trick in Pest, rather than extracting a class method you can extract a function in your Pest file (Or again, potentially in a trait) and using it as a second argument when calling the get() method in your test.

Laravel Partner

Since 2014, we’ve built, managed and upgraded Laravel applications of all types and scales with clients from across the globe. We are one of Europe’s leading Laravel development agencies and proud to support the framework as an official Laravel Partner.

Get in touch

Vue Experts

We use Vue alongside Laravel on many of our projects. We have grown our team of experts and invested heavily in our knowledge of Vue over the last five years.

Get in touch
Top