Testing Contact Creation0:00
Let's take a look at the create contact flow in PinkCRM. The first thing I need to do is fill this form out with data. Once the form is filled out I can click the create contact button, which takes me back to the contacts root, it gives me a success session message saying the contact was created, and if I search for Luke Downing, yes I have indeed been created as a contact. So I'd like to test this in PEST. Let's jump over to our IDE, and as always our test will start with it can store a contact. We'll have our test closure, and then we need to log in in order to access this root. So something like this, actingAs, user, factory, create. Now we've already done this logic in previous tests and we're probably going to have to log in in many different tests in the future, so it would be nice to abstract this logic into a more declarative helper, something like
Understanding pest.php Setup0:54
and we're probably going to have to log in in many different tests in the future, so it would be nice to abstract this logic into a more declarative helper, something like login. But we're able to do this by defining a test helper in the pest.php configuration file. Seeing as it's the first time we've really looked at this file, allow me to just quickly explain what it does by default. You'll see we have on line 14, users, TestCase, in feature. What that means is that any PEST test you define in the feature directory of your test suite, will use this PHPUnit test case as the underlying class. If I take a look at that test case you'll see that it creates the Laravel application, and it lazily refreshes our database. So in other words, any PEST test inside the feature directory is going to have access to Laravel features. Let's jump back into our pest.php file, and
Creating a Login Helper1:40
refreshes our database. So in other words, any PEST test inside the feature directory is going to have access to Laravel features. Let's jump back into our pest.php file, and let's scroll down a little bit. You'll see we're extending this expectation API here. We'll leave that for now. And we'll come down to this function section where we can define custom helper functions for our tests. In this case, let's create a function called login, and I'll allow login to be passed a User, which can be nullable. And what we'll say is we want to return the result of this acting as the Laravel helper method. And we'll say pass the user, or if you haven't given a user, we'll create one for you using UserFactory::create. I can then import that model. And you'll note that we have a syntax error under this. That's obviously the case because we're not inside a class, so we don't have
factory create. I can then import that model. And you'll note that we have a syntax error under this. That's obviously the case because we're not inside a class, so we don't have access to this. But PEST allows us to access a test case outside of a class by simply referencing test without any parameters. And this is going to return to us the current test case from wherever you've called the login function. So if we jump back into our store test now, you'll see I can call login, and I can then make a POST request. I'll make a POST request to contacts, and then we need to pass an array of data. Let's go ahead and fill out some data to use. So I've gone ahead and added all of the properties that we'll need to fill for this to be a valid request. Now we could hard code the values, but I like to be a little more random than that and make use of FAKER in my tests. You can make use of FAKER by
Generating Request Data3:12
for this to be a valid request. Now we could hard code the values, but I like to be a little more random than that and make use of Faker in my tests. You can make use of Faker by using the WithFaker trait that ships with Laravel. So we'll use the user function from PEST along with the Faker fully qualified class name to import Faker into our test case. Once we've done that, I can start using Faker with the $faker property. So I'll say $faker->firstName. Here I could say $faker->lastName. The email could be $faker->email, and the phone could be $faker->phoneNumber. I think the E164 phone number is the international version, which is better for our use case. Let's hard code address. I'll say one test street, and the city could be Testerfield. The region, let's say Derbyshire, my home county. And the country, well we could say
Let's hard code address. I'll say one test street, and the city could be Testerfield. The region, let's say Derbyshire, my home county. And the country, well we could say this FAKER random element, and let's say either the US or Canada. For the postcode I can say this FAKER postal code or postcode. Brilliant. So that is all the data needed to actually hit the contacts endpoint. So in order to make sure that works I could say assert a redirect to the contacts page, and let's also assert that the session has a success message, which is contact created. Let's jump back into our terminal and run php artisan test, and here is our store test. It works and it's passing. Ok, this is well and good, but we've never actually checked that a new Contact model has been created with this data. We should probably do that because otherwise we don't really know that that's the case.
Verifying Database Records4:58
but we've never actually checked that a new Contact model has been created with this data. We should probably do that because otherwise we don't really know that that's the case. All we know is that we successfully had a redirect and the session said that contact was created. So in order to do that we'll first of all pull out the latest contact from the database. $contact equals Contact::latest(), and give me the first of the latest contacts. Once we have the Contact model we need to perform some form of check. So let's say we want to make sure that the firstName is a string. Well you could do something like if not is_string($contact->firstName) throw new Exception('The test failed.'); That is a check that would fail if the contact's firstName doesn't meet our expectations. However, this is not a very nice way to write tests. So any testing framework worth its
Using PEST Expectations5:54
That is a check that would fail if the contact's first name doesn't meet our expectations. However, this is not a very nice way to write tests. So any testing framework worth its salt will give you a way to write these form of exception checks in a much more declarative style. PhpUnit for example ships with the assertion API, and you can use the assertion API in PEST. So you could say something like this assertEquals and let's say testField which should be the contact city. And if we jump back into our terminal and run php artisan and test again you can see our test passes. However, PEST also ships with an expectation API. The expectation API provides a very clean way to define all of these checks in a declarative and extensible manner. Allow me to demonstrate. You start using the expectation API by declaring a new expect call. And in the expect call you basically pass it any value you want to.
and extensible manner. Allow me to demonstrate. You start using the expectation API by declaring a new expect call. And in the expect call you basically pass it any value you want to make checks on. So we could say expect(true) and then you can chain on any number of methods which are the checks you want to make on that value. So in this case to be true. We jump into our terminal run php artisan and test you'll see it passes. But if I change this to be false for example, jump back into our terminal and run the same again, you'll see we get a failure and it's going to say well it failed asserting that true is false. We actually get the line number that failed as well along with a stack trace if it's deeper than this. Brilliant. Okay. Let's jump back into our IDE and replace this with an actually useful call. Something like expect($contact->firstName). What do we
Brilliant. Okay. Let's jump back into our IDE and replace this with an actually useful call. Something like expect contact and we'll expect the contact firstName. What do we want to actually check? Well it should be a string right? Well there's a toBeString method on the expectation API and we don't want it to be empty. So first you might search for something like notToBeEmpty but that method doesn't exist. If I attempt to run that it's going to fail. It's going to say the function notToBeEmpty doesn't exist basically. If we jump back into the IDE you'll note that there is a toBeEmpty method. So how do we get the opposite of toBeEmpty? Well in PEST and the expectation API you can prepend any expectation call with the not property and when you do that it's basically going to flip the expectation on its head. If I jump back into the terminal run php artisan
prepend any expectation call with the not property and when you do that it's basically going to flip the expectation on its head. If I jump back into the terminal run php artisan and test you'll see everything is passing. Brilliant. So with that information we can begin to expand our expectations. We can use the last name for example and we can obviously call the same expectation methods. I could say expect contactEmail to be string and maybe I want to say to contain the @ symbol. So it has to be a string and it has to contain the @ symbol to be a valid email. Let's jump into our terminal. Let's make sure that works using php artisan and test. It does. So let's continue. Let's say expect contactPhone to be string again and maybe to start with a + symbol because it's an international number. Again let's run php artisan and test and everything still passes. What about some
be string again and maybe to start with a plus symbol because it's an international number. Again let's run php artisan and test and everything still passes. What about some of these hard coded values? What if you want to do a strict equality check? Well it's very easy to do that. We just say expect contact and we could say city and then the method you're looking for is toBe which is a strict equality check. So toBe in our case test a field and we could do the same thing with let's say region which we'd expect to be Derbyshire. Go back into our terminal run php artisan and test and everything still passes. Another example we could look at is our country. So our country could be one of two things. It could either be the US or Canada. So in order to define this why don't we say expect that the contacts country toBe in and then we pass an array and that array is just the
It could either be the US or Canada. So in order to define this why don't we say expect that the contacts country to be in and then we pass an array and that array is just the values that this could possibly be. So it could be the US or it could be Canada. And if we jump back in and run php artisan and test again you'll see everything still passes. So that's the basics of the expectation API. There are so many methods that you can chain on to expect in order to perform as many checks as you'd like. And there's even room for being able to extend the expectation API which we'll look at in the next video.
