تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Reproducing the Bug0:00

Okay, let's work on fixing a bug here. So we have pretty good test coverage, but I usually still like to click around my app to make sure everything is working correctly. So that's how I discovered this bug. So let me reproduce it here. We're logged in. This Idea is voted for. We go to the show page. We unvote this. So it's 19 and we haven't voted for it.

So it's going to show 19, go back, and it's showing 20. And remember, it's 19 and we haven't voted. So when I click this, it's going to try and delete a vote that doesn't exist. And there's error. Call to member function delete on null. So that's happening here in the Idea model right here. Can't find anything. So it shows this error here. So let's go ahead and fix that. And then we'll work on the other case as well.

Handling Missing Vote1:05

So let's go ahead and fix that. And then we'll work on the other case as well. So it looks like we have to make sure that the vote exists. So let's do voteToDelete equals this. And then we can check if it exists. Now we can check if there is one. So we can just do if voteToDelete, then delete it. So voteToDelete delete. Okay. Now this will actually work, but I also want to throw an exception here.

Okay. Now this will actually work, but I also want to throw an exception here. So let me remove this and say else. And I'm going to make a new exception here. So let's do php artisan make:exception. And let's call it VoteNotFoundException. Okay. And we can throw that exception here. So say throw new VoteNotFoundException. Okay.

Catching VoteNotFound Exception2:00

So say throw new VoteNotFoundException. Okay. So now in our Livewire component, so I'm just going to fix it on the IdeaIndex, and then I'll paste it to the IdeaShow page. I want to do a try catch here. Actually before I do that, let's just see if we get the exception now instead of this error. So I'm going to refresh. Let's do the same thing. Actually, just start at 20, refresh, do the same thing.

Let's do the same thing. Actually, just start at 20, refresh, do the same thing. So on vote here, go back, shows 20, click it. And now we get this new exception. Okay. So now we can try and catch it in here. So say try this and catch the exception we just created. And this will only happen in this specific case. So when we try to remove a vote and it doesn't exist. So let's catch that exception.

So when we try to remove a Vote and it doesn't exist. So let's catch that exception. So VoteNotFoundException. Okay. Say E. And we actually don't have to do anything in here. So let's just do nothing. And we still want to do this to update the state. And this will bring us back to the correct state. So let's try that again. And it should work now.

So let's try that again. And it should work now. We shouldn't get an error. Refresh, put it back to 20, refresh again. And let's try that again. So we're here on vote, go back, still going to show 20. But if I hit vote, it's going to go down to 19 and fix the state. But I won't try to actually it will try to it's going to catch the exception, but I won't do anything else. And it does work.

And actually, you know, let's bring back to 19. Let's go to the show page. Let's bring it up to 20. So the correct state is 20 now. But if I go back, it's still going to show 19. So that seemed to work for some reason. Let's try again. So I'm going to hard refresh a few times 19, let me refresh again. So 19 and go to the show page. We upvoted 2020 is the correct state.

Fixing Duplicate Vote Case4:15

So 19 and go to the show page. We upvoted 2020 is the correct state. If I hit back, it's showing 19. Okay. So now if I try to vote, this already exists in the database. So it's gonna throw some QueryException, I think. Yes. So we get duplicate key, and we get a QueryException. So let's go ahead and fix this as well. So back to our Idea model.

So let's go ahead and fix this as well. So back to our Idea model. And instead of just creating the vote, we also have to check if that vote exists. And if it does, we can throw a new Exception. So let's do that. So we already have that method we created a few videos ago called isVotedByUser right here. So we can make use of that. So if it's already voted by this User, then throw a new Exception. So if this is voted by User, and we're passing in a User here, then we can throw a new Exception.

So if it's already voted by this User, then throw a new Exception. So if this is voted by User, and we're passing in a User here, then we can throw a new Exception. So let's make a new one. Again, let's call it DuplicateVoteException. Okay. And let's throw that here. Throw new DuplicateVoteException. Okay. So again, if we try the same case, we should get this new Exception now. So let me just remove this, bring it back down to 19.

So again, if we try the same case, we should get this new exception now. So let me just remove this, bring it back down to 19. Okay. Refresh. 20. Go back. Should show 19. Okay. When I upvote, it's going to throw that new exception. It does.

When I upvote, it's going to throw that new exception. It does. Cool. So we can do the same thing here. Let's just try and catch in the Livewire component for this case right here. So let's do that as well. try this. catch that new exception. catch DuplicateVoteException $e and do nothing. And the state should update itself, and everything should be back to the correct state.

Catch duplicate vote exception E and do nothing. And the state should update itself, and everything should be back to the correct state. Okay. So let's try that one more time. So back to 20. Let's go back down to 19. Let's hard refresh here. Upvote back should show 19. But now when I click vote, it should update the state, but not try to perform that. Actually, it does try to perform it, but we're catching it and doing nothing.

But now when I click vote, it should update the state, but not try to perform that. Actually, it does try to perform it, but we're catching it and doing nothing. And it does work. Cool. So let's just keep clicking it. It should work now. Okay. Cool. So let's just make sure that we have the same in our idea show, because it can happen there as well.

So let's just make sure that we have the same in our IdeaController show, because it can happen there as well. So it's pretty much the same thing. Let me just copy all of this. Go to our idea.show, and we can replace all of this. Okay. You have to import these, and it should work there too. So let's just make sure it still works normally, and it does. Cool. Okay.

Writing Unit Tests7:23

Cool. Okay. So let's write a test to make sure we handle this case. So I'm just going to write a unit test in this case. You can write a feature test if you want to, but I'm okay with just a unit test. So let's go to our IdeaTest, and let's add one here after the voting test here. So let me duplicate this, and let's call it, let's see, voting for an Idea that's already voted for the RolesException. Okay. So we have to make sure that we voted for it already.

Okay. So we have to make sure that we voted for it already. So we need a vote here. I'm going to grab this one. Okay. Let's paste it here. Now when we call ideaVote User, this should throw an Exception. So this right here should throw an Exception. So we can do this expectsException, and we can pass it the Exception it's expecting. So DuplicateVoteException class.

So we can do this expectsException, and we can pass it the exception it's expecting. So DuplicateVoteException class. Okay. Sorry. It's expectsException. Okay. And let's run that. Hopefully it passes. And it does. Cool.

And it does. Cool. So let's make sure that it fails if I remove this. So I won't throw an exception if a vote already doesn't exist. It does fail. Cool. So let's put that back. So let's do the same for the remove case. So I'm going to grab this, paste it down here underneath the remove test. Let's call it removing a vote that doesn't exist, throws exception.

So I'm going to grab this, paste it down here underneath the removeTest. Let's call it removingAVoteThatDoesNotExist, throws exception. Okay. So this time we're not starting with a Vote, so we can remove this. The exception that we're expecting is VoteNotFoundException. So let's import that VoteNotFoundException. Okay. Pass. And we want to call the removeVote method. So that exception is thrown.

And we want to call the removeVote method. So that exception is thrown. Okay. So that should work, hopefully. It does. Cool. So just to make sure, let's add that vote here. So this should fail when they have an existing vote. Okay. Let's run that again.

Committing the Fix10:38

Add. This is episode 21. Okay. Commit. Episode 21. Fix back button bug when voting.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟