Playing
07. Tapping with higher order tests

Transcript

00:00
Okay, we're going to attempt to move this over to a higher order test and see why it just won't work if we try and chain all of these methods onto each other. So once again, let's just copy this down just so we can reference the original test here
00:15
and let's just start to change this over. So we can get rid of everything inside of it and let's get rid of our callback here and then let's go down and just continue. So we want to post through to register with these details.
00:29
So let's do that now. Post to register and we'll paste that array in. Now that will work on its own. So if we just come over and rerun our register test, we can see, yeah, that already exists.
00:42
So let's just say higher order for this one. Let's run that and it works. Although we have an incompleted test because we're not making any assertions. Now if we come up, what we can also do is assert that we're redirected back to the home page.
00:54
So we can come down and continue to chain this on and we can run this and you can see that sure enough it passes. But as soon as we try and do something like assert database has, for example, on here, let's say users,
01:10
and let's just keep this simple and just look for the email address rather than the name as well. We'll see that when we run this test, it's not quite going to work. Now the reason that this doesn't work is we have an undefined assert database has method being called on our redirect response.
01:28
Now what's happening here is when we run post and assert redirect, specifically post, that's going to return to us the test response class, which we can then chain on assert redirect. But if we look at how we did this up here, we called this assert database has.
01:46
We didn't call this on the response itself. So just to demo this out, if that doesn't make sense, let's go ahead and assign a response variable to here and let's get assert redirect removed and just die dump on this response.
01:58
And we can even say get class response and go ahead and run our tests. And you can see that we get a test response back here. Let's open that test response up and let's take a look at what we can do inside of here. So let's go down to assert OK, assert created, assert no content.
02:20
So it's got all of these assertions available on this, but it doesn't have assert database has. This is a completely separate method being called to just do a completely separate check. This is nothing to do with the response itself.
02:35
So basically, we can't just chain this in in a higher order test like this. So how do we get around this? If we want to write more elegant tests with pest, what we get around this by tapping the original result of the it function,
02:52
perform this post, perform any other assertions we need on the response itself, and then continue to chain. So this is what this is going to look like. Again, let's just start this from scratch and we'll rebuild this up.
03:06
So it looks a bit nicer. So down here, what we're going to do is use Laravel's tap helper and we'll create an inline or a shorthand function in here to deal with this. In fact, we don't even need to do that.
03:18
Let's create a full one and then we'll refactor this down. So we're going to tap into this. We're then going to perform the kind of response stuff that we need to do, like posting through to register with them details.
03:30
So let's again just copy all of the details that we need in here. So let's paste this down and then go ahead and assert redirect slash. But now we've tapped into this. What we can do is continue outside of this tap to chain anything onto it.
03:52
So tap is going to go ahead and perform these, but return this to us. So then we can continue down here to assert database has users. And again, we'll just put that email address in there just to keep things simple. So Mabel at co-course dot com.
04:12
And what else do we have? Assert authenticated. So we could then chain that on down here as well. So what we basically do is perform this response stuff,
04:23
but then return the original result of this it function. So we can continue to then chain on in that higher order way. So I'm going to get rid of this original test up here. So let's get rid of all of that.
04:38
Let's change the name of that back as well. And we now have a much more clean way of defining this rather than having that closure in here. Let's go ahead and rerun our register test.
04:49
And you can see sure enough now this passes. Now, if you want to make use of PHP's shorthand functions, you can do that as well. So we could take everything that we're doing in here
04:59
and we can instead include a shorthand function and then just go ahead and paste that in. And you could pull that down and kind of configure this how you wanted to.
05:09
But I tend to just leave them like this in a bulk. So there we go. We've shortened this test down. That's still going to pass.
05:16
We've just done that by tapping into this, returning the original result of this. So we can continue to effectively do what we were doing before with this.
05:25
And again, if you had a much shorter test like this and you're just sending a really simple request down and then checking something, you're going to end up with a really short set of tests.

Episode summary

In this episode, we're exploring how to write cleaner, higher-order tests using Pest (and Laravel). We try to rewrite an existing test by chaining all the assertion methods together for a more elegant, fluent approach. However, we quickly hit a snag: methods like assertDatabaseHas can't just be chained onto the response object, because they're not available on that class.

We dig into the reason by looking at what is actually returned when we call post()—it's a TestResponse, which does let us chain response-related assertions, but not global ones like checking the database or authentication status. To get around this, we demo how to use Laravel's tap() helper function. This lets us do all our response assertions within the closure, and then outside, we can continue chaining methods like assertDatabaseHas and assertAuthenticated directly on the test context.

By the end, we refactor the test to be much cleaner and discuss a few shorthand approaches for even more concise code. The result: more readable, maintainable higher-order tests that still let you check everything you need—whether it's the response, the database, or the authentication state.

So, you'll come away understanding how to properly "tap into" your tests, mix chaining with global assertions, and generally make your test suite more elegant and fun to work with!

Episode discussion

No comments, yet. Be the first!