Testing slug redirects bug0:00
You may be wondering, how did you find these books? And the honest answer is, I didn't find these books. You did. See, no matter how good you are at programming, no matter how much experience you have, whether you use TDD, whether you refactor, whether you spend all day staring at the code, you will not find every book. Which is why the PR review process is so vital. Of course, for a series like this, there is no PR review process, but we do have LaraCass comments. So, for example, Dylan brings up a great problem here with our SEO slug redirects. Thanks Dylan for contributing. He says, for example, posts/1/hello would not get redirected to the correct slug of hello world. Let's test this. So, post 245, singing in the rain, a timeless classic. Let's go ahead and remove everything after the word singing and I'll hit enter. Yeah, you see, it's not redirecting to the correct slug. I think we have a test in place for this. So, we could actually extend that to prove that this is a problem in the backend code and then we could fix it. Let's find that test. Here it is. It will redirect if the slug is incorrect inside showtest.php. And if I run this, sure enough, it passes. But if I was to change the slug here to hello, which is obviously just the first part of hello world and run the test again, now it fails. Yeah, there is definitely a problem here. Rather than changing the test, I'm going to introduce a data set here to run multiple tests. So, I'll run with foobar and I'll run with hello.
Fixing redirect slug match1:28
But if I was to change the slug here to hello, which is obviously just the first part of hello world and run the test again, now it fails. Yeah, there is definitely a problem here. Rather than changing the test, I'm going to introduce a data set here to run multiple tests. So, I'll run with foobar and I'll run with hello. And then we'll accept that data here. So, string and we'll call it incorrectSlug. We'll pass the incorrectSlug here. And then when we run this test again, now note that we have two tests. And of course, the hello slug is still failing. Let's jump into our PostController. And the fix for this is pretty straightforward. We'll just change notStringContains to notStringEndsWith. Rerun the tests and now they both pass. Let's test it in the browser. So, we should be able to refresh this page and it should now redirect us to the correct slug. Refresh and it works. Thank you so much Dylan for that bug report. But guess what? Dylan's not done because he brings up the second issue in our app. Flight bug toasts reappear after clicking pagination links because the pagination component only reloads comments, not the flash prop. And he gives us a possible fix. You're on fire Dylan. Thank you so much. Let's fix this one. Let's verify this bug in the browser. So, post 245. We'll need to create some comments. But just before we do, why is this editor so tall? I'm pretty sure. Yeah, we did give it a class of min-height 160. This must be a tailwind specificity issue. So, basically the default inside markdown editor is overriding this class that we add here. In tailwind you can actually prefix any class with an exclamation mark and it will make it important.
Fixing editor height CSS2:56
But just before we do, why is this editor so tall? I'm pretty sure. Yeah, we did give it a class of min-height 160. This must be a tailwind specificity issue. So, basically the default inside markdown editor is overriding this class that we add here. In tailwind you can actually prefix any class with an exclamation mark and it will make it important. It will add the important modifier in CSS. So, now if we do that and go back to the browser and refresh, there we go. The editor is the height we'd expect. A bug inside a bug. Alright, now we need to generate some comments. We'll do that using php artisan tinker. First of all we'll need to grab the post. So, $post = Post::find(245). Then we'll grab the user. I need to assign it to my $user so that I can edit and delete these comments. So, $user = User::where(email, 'test@example.com')->first(); There we go, our $user. And now finally I can say well I want to create some comments. So, Comment::factory()->count(12)->create([ 'post_id' => $post->id, 'user_id' => $user->id ]); Hopefully, there we go. Yep, two pages of comments. So, let's first of all cause a toast to appear which we can do by just posting a new comment. Hello world. Add the comment and the toast appears at the top. Comment added. If we wait for it to disappear then I'll go ahead and move to page two. Yeah, there's the bug. The toast reappears which is definitely not what we want. Now, Dylan does more than tell us that there is a problem. He explains why the problem exists. The pagination component only reloads comments, not the flash prop. So, inside this little jetstream object that's passed down between requests, it includes a flash array which will include our toast information for example.
Fixing toast pagination reload4:41
If we wait for it to disappear then I'll go ahead and move to page two. Yeah, there's the book. The toast reappears which is definitely not what we want. Now, Dylan does more than tell us that there is a problem. He explains why the problem exists. The pagination component only reloads comments, not the flash prop. So, inside this little jetstream object that's passed down between requests, it includes a flash array which will include our toast information for example. And obviously in our code base at the moment we say actually when you reload a page or when you change page only include comments, not jetstream. So, our front end has old flash data which is why it's showing a previous toast. So, we could of course go ahead and change this. Let's add jetstream to this array as Dylan suggested. We'll go back to the front end and let's delete this comment. There we go, now we have the toast pop up comment deleted. And once it's disappeared I'm going to move to the next page and sure enough that does fix our issue. I think we could clean it up a little more though because I don't want to have to remember to include jetstream every time I'm using the only prop on pagination. Instead, pagination could just do that for me. We'll dive into the pagination component and here we have the only prop. Let's introduce a computed property for this. So, const only equals computed and first of all why don't we check whether the only array has anything in it. So, we'll say props.only.length. Well, is that equal to zero? If it's equal to zero that actually means we want to load every prop. So, I'm just going to return an empty array. But if it's not equal to zero then what I actually want to do is spread out what's been passed in props.only but I'll also add jetstream to that list. Does that make sense? Let's just go over it again. So, we receive the only array which by default is just an empty array which actually indicates we want to load everything if it is empty. So, in the computed property we'll check the length of that array. If it is empty we will say we'll just have an empty array and load everything. Otherwise we'll pass in whatever's been given from the front end. So, in this case it would be comments and we'll automatically add jetstream to that array. Because we called the computed property the same as the prop we actually don't need to update our HTML at all because it will reference the new computed property instead. Let's test it from the front end. We'll come down and we'll go ahead and add ourselves a new comment. Hello world. And add the comment. Comment added. We'll wait for it to disappear. And then we'll move to page two. Nice. That works. So, I think that's a pretty clean refactor and because we've added it to the pagination component we don't have to worry about it again.
Redirecting after last comment7:09
Because we called the computed property the same as the prop we actually don't need to update our HTML at all because it will reference the new computed property instead. Let's test it from the front end. We'll come down and we'll go ahead and add ourselves a new comment. Hello world. And add the comment. Comment added. We'll wait for it to disappear. And then we'll move to page two. Nice. That works. So, I think that's a pretty clean refactor and because we've added it to the pagination component we don't have to worry about it again. Our final bug was mentioned by Lars and he says there is a problem in your code. How dare you Lars. There is never a problem with my code. When you delete the last comment of the last page it should redirect to the page before that as it is the last page. Now, let me show you what Lars means. So, here we have two pages of comments, right? I go to page two and here's three comments. Let's delete them. So, I'll delete this comment. I'll delete this comment. And when I delete the last comment on page two, what would you expect? You'd expect that we go back to page one. But when I go ahead and delete this, no, we're still stuck on page two. Let's update our view component because that actually contains all the information necessary to determine which page it should redirect to. So, here we are back in our show.view component and here's where we delete the comment. But this is the parameter we're actually interested in. The page to redirect to which currently is always the current page. But we could just take a look at how many comments are in the page we're on. props.comments.data.length. Is that greater than one? If it is greater than one, then we can safely redirect to the current page. But if it's not, then we actually need to go back a page, right? So, we could copy this and we could say props.comments.meta.current_page minus one. So, redirect to the previous page if this is the last comment on the page. Of course, there is a slight edge case bug here because if you're already on page one, we don't want to try and redirect to page zero. So, we could use a little Math.max for that. Math.max either the page minus one or one. Let's test this in the browser. So, first of all, we'll add some comments. Hello world. Let's add another one. Hello again. And then we'll go to page two. And on page two, I'm first of all going to delete this comment here. And I would expect that we still stay on page two, which we do. But now I'm going to delete the last comment on page two and there we go. I'm redirected to page one. Awesome. So, that fixes that issue. Thank you, Lars, for bringing it to our attention. Aside from bugs, there were also some really cool features that a number of you suggested that would improve the readability of a couple of parts of our code base. Let's tackle that in our next episode.
Awesome. So, that fixes that issue. Thank you, Lars, for bringing it to our attention. Aside from bugs, there were also some really cool features that a number of you suggested that would improve the readability of a couple of parts of our code base. Let's tackle that in our next episode.
