Hey everybody came here with slopes.
And in this video we're going to continue testing particularly UI testing after async calls like downloading
an image or you know doing a complex sort algorithm.
I don't know.
But basically we're going to add a few things to our app we're going to move a little quickly at the
beginning but then the UI testing part will come right at the end.
So let's go ahead and open our project and we're actually going to just add some things to argue here.
We're going to add a button right here.
We're going to add an image view right here.
OK.
We're going to add what else.
A label right here.
Now let's go ahead and constrain these.
Let's pin this 20 from the bottom.
Let's make it horizontal.
Let's go ahead and pin this 8 from the button looks good and we're going to pin that horizontal as well.
And you know what.
Let's actually give this a fixed width and height and you know what while we're here let's set the image
to aspect.
Fill the label we're going to go ahead and pin let's do 20 from the bottom and pin it horizontally as
well.
Again I apologize for moving so quickly but I did say we were going to.
So anyway this label is going to say what a beautiful image.
OK.
That's what it's going to say.
And this button will say load image.
OK.
Now let's go ahead and let's head into the assistant editor here and let's link this up to the view
controller interface visi.
So for the image loading button we're actually going to use an IB Action K and it's going to be called
load image button was pressed.
OK there we go.
Then we're going to need an outlet for image view so we'll just say pretty image view because it's going
to load a pretty image and then this label is going to be the caption label.
OK.
So by default let's go ahead and let's set our caption label k to be hidden awesome and we'll set that
to be true.
Very cool.
Then we're going to actually go ahead and move on because we have everything that we need here.
Cool it's linked.
The button has an IB action.
The image has been linked to the caption has been linked.
And so now I guess we can just write a quick function that will download an image from the internet.
Pretty straightforward stuff.
Let's go ahead and actually give us some space so we can see what we're doing here.
Let's go ahead and write this function phunk download image for.
From I guess from you r l with a u r l string K using that internal parameter there and we are going
to be using u r l session which involves a closure so we're going to need a completion handler that
can escape from that so just call completion here and it's going to be escaping because we want it to
be able to escape from the closure inside our function.
And of course our completion handler here is basically going to just return void.
We don't need to return anything.
But we are going to pass a UI image into that completion handler.
So inside our function we're going to actually use your session shared dot data task with you l and
completion handler.
We're going to pass an R U r l.
But first we should create an instance of u r l and not just string so type.
Guard let u r l is going to be of type u r l from string k pass in r u r l string and then we're going
to say otherwise if that doesn't work we're going to call fatal error which basically means hey if R
U R L is invalid or should not continue because that could cause a really nasty crash.
So once r u r l has been created we can actually pass it in here.
U r l and the completion handler we can just push enter on and we can give it a property here of data
response and error k.
Now if we have an error meaning if error is not equal to nil K we're going to go ahead and call fatal
error.
Ok it's going to print out an error response and it's going to halt the application.
Now if we are good to go right if we don't have any problems we're going to need to basically encapsulate
data in a way that is safe.
So we're going to use guard let guard let data.
It's going to be equal to data.
And we also need to create an image from that data that is downloaded so we can actually do a second
constant here.
Let image equals image from data.
And the cool thing is that both of these are optional.
But when we use guard let we can create them as if they're not.
So it will pass in our data here.
Otherwise we're going to go ahead and call fatal error because that will be a fatal error if we don't
have a successful image download.
Then at the very end we can call completion and it's asking us to pass in a new image which we now have
is called image.
So pass it in.
Then of course at the end of a data task you need to call DOT resume in order for that task to continue.
And now we have a function that can successfully download an image.
So what we're going to do is we're basically going to say hey if the pretty image view image is nil
meaning if there's no image in the image view we're going to go ahead and basically you know download
our image.
So type download image from you URL.
And this is where we're going to have to basically create a constant that has a file in it.
So I'm going to go ahead and say Mark image you are Elle's and let image you are all equals and it's
going to be a string.
What you can do is you can go find any image on the Internet you can copy and it's you are all like
I have done here this downloads from a Web site called pixel's dot com.
They have non-attribute and royalty free images you can use in any project even commercial projects.
So there's my image you are l.
Now I'm going to go back whoops to interface Visi I believe it was interface Visi and I can pass in
my image you Arel which I have to build in order to find.
There it is boom and the completion handler of course is going to be just named image because that's
what's returned and passed out of the escaping closure.
Then what we're going to do is we're basically going to say hey if we have successfully downloaded our
image we're going to set the image view so self pretty imagery image.
Now of course we're calling self because we are within a closure we need to make a reference to what
view controller we're referring to.
But we're going to set the image property to the image that is downloaded very easy.
But what we're going to test is to make sure that our caption properly shows when our sync code has
finished.
OK.
So in order to do that remember we said it to be hidden from the beginning because there is no image
what we can do is after it's downloaded self damn caption label dot is hidden.
Is false.
OK.
That way it's hidden from the beginning.
After we download our image it can be false meaning it's showing very very easy.
But one thing to note we are going to run into a problem or else session happens on a background thread
when we pass this image through.
This is also happening on a background thread.
So we need to actually set UI elements on the main thread so we can call dispatch queue up Main async
and then we can actually just go ahead and cut and paste this into there and then it can properly update
on the main thread.
That's just a requirement of iOS UI elements must update on the main thread so that will cause that
will prevent us from having problems.
So let's go ahead and head into our tests here and let's open the assistant editor with our interface
Visi right next door.
OK so controller interface Visi and now we're going to go ahead and write a test.
So go ahead and write phunk test and we're going to test that when an image download completes that
the caption label is presented.
So we're going to test image download when download complete
caption label showing K that's what we're testing that the caption label is showing when our download
is complete.
So what we need to do is we first need to launch our app k just like we've done with all the other tests.
But now what we're going to do is we're basically going to set up an instance of our static text which
we've used in the past.
Right we have checked for static text in labels on our screen.
We've checked for things like that.
K right here here it is.
We've checked for certain labels using static text.
And so we're going to basically just use a constant here to store that.
So let image caption equals app dot static texts K and the label that shows says what a beautiful image
with an exclamation mark.
Right.
So now we have an instance of image caption which basically we can use to call you know image caption
dot exist and we could call it here but it wouldn't make sense to use it there.
So let's continue.
We now have an instance of our image caption and now we're going to make is something called an N S
predicate.
Let me create it and then we'll talk about it.
So Type let exists let exists equals an s predicate K and actually you know what I want you to see that
definition there.
N n s predicate is a definition of logical conditions used to constrain a search either for a fetch
or for in-memory filtering.
OK.
Now if that's making your brain go well that's fine.
But we're going to use the one with a format and actually get rid of the arguments because we don't
need any arguments necessarily.
But what this is going to do is it's basically going to set up a logical condition to where if the exists
property on image caption get set to true.
This is going to help us basically trigger hey it's done and now we can call our test.
So in the format K right here.
Go ahead and type exists.
Equals with two equals true case we're using the logical equivalence symbol basically saying hey if
exists is ever equal to true.
We're going to continue.
Now what we need to do is we actually need to wait for our async code to happen and let's say we had
really slow internet K.R. our code might take longer or let's say we were downloading multiple images
not every single image is going to download in the exact same time.
So this is where expectations come into place.
We're going to create an expectation that accepts an end as predicate and it's going to accept one of
our queries which is what we're doing here we're searching for this label using image caption.
And then as soon as exists becomes true it's going to go ahead and basically say hey it's done we have
evaluated whether or not something exists so it's just it's almost like we're creating a way for it
to tell when a certain condition of our image caption becomes true or false.
So go ahead and just type expectation for and as predicate we can pass and exist because we're checking
we're predicating that exist is true.
And we are evaluating it with the image caption.
So we're checking to see if it's if it exists and from the beginning of course that's false because
it doesn't exist.
So the handler is going to be nil because we don't care what happens at the end of this.
But now what we need to do is we need to remember our app is launching from a fresh state.
So we're going to need to actually go ahead and do exactly what we do for our There are other apps that
get through the onboarding experience first by swiping left twice and tapping done.
OK so I just copied that and pasted it.
Then of course when our pop up appears right our little alert Visi we're going to go ahead and just
call app dot alerts and the alert title is you did it so we can find it using its title then we can
look through the buttons on that alert and tap the awesome button if you remember.
That's how we did it.
So we found the button.
Now we call tap and then it dismisses which is very cool but now we have a new image in our interface
right.
We have a load image button.
And when it's pressed it downloads our image right.
So what we're going to do is we're going to tap app buttons and we're going to search for the load image
button.
Whoops.
Make sure that you type it.
Case sensitive and push tap.
So now our button has been tapped.
But now if we were to go ahead and type LCT assert and then just basically we're asserting that a certain
element exists in this case.
Image caption exists if we were to assert that it would instantly fail because we still have to download
the image and to prove that check it out we're going to go ahead and run our test to see how we do.
Of course like I just told you it is going to fail.
But we are definitely moving in the right direction.
So here we go.
Our apps going to open up it's going to launch.
We're going to swipe left twice.
Here we go one to tap.
Done dun tap the awesome button tap load image and fails.
Right.
Because we need to wait.
We need to tell it to wait before running the assertion.
And so what we're going to do is we're going to go ahead and call wait for expectations and this expectation
that image caption exists we need to wait to actually check that.
So let's wait five seconds and the handler no one cares.
Or at least I hope so.
We're going to go ahead and run this one more time and see if waiting five seconds impacts whether or
not the test passes or fails.
And we're checking to see if image caption exists right.
So here we go.
Going to go ahead and open our test here swipe through one to tap dun tap the awesome button tap load
image wait five seconds.
And our test passes the image was there meaning the image caption was there as well.
And so we have now verified that our label shows up exactly as we are hoping.
Very very cool stuff.
So this is how you can perform UI testing after a particular asynchronous call.
Very very good work.
Amazing job guys.
Let's head on over to our exorcized now.