1
00:00:06,120 --> 00:00:08,110
Hey everybody came here with slopes.

2
00:00:08,130 --> 00:00:15,360
And in this video we're going to continue testing particularly UI testing after async calls like downloading

3
00:00:15,360 --> 00:00:19,970
an image or you know doing a complex sort algorithm.

4
00:00:19,970 --> 00:00:20,640
I don't know.

5
00:00:21,060 --> 00:00:24,570
But basically we're going to add a few things to our app we're going to move a little quickly at the

6
00:00:24,570 --> 00:00:27,650
beginning but then the UI testing part will come right at the end.

7
00:00:27,660 --> 00:00:32,710
So let's go ahead and open our project and we're actually going to just add some things to argue here.

8
00:00:32,730 --> 00:00:36,240
We're going to add a button right here.

9
00:00:36,450 --> 00:00:40,610
We're going to add an image view right here.

10
00:00:41,030 --> 00:00:42,050
OK.

11
00:00:42,210 --> 00:00:44,210
We're going to add what else.

12
00:00:44,220 --> 00:00:46,540
A label right here.

13
00:00:46,620 --> 00:00:49,290
Now let's go ahead and constrain these.

14
00:00:49,290 --> 00:00:51,330
Let's pin this 20 from the bottom.

15
00:00:51,330 --> 00:00:53,210
Let's make it horizontal.

16
00:00:53,610 --> 00:01:00,780
Let's go ahead and pin this 8 from the button looks good and we're going to pin that horizontal as well.

17
00:01:00,780 --> 00:01:01,200
And you know what.

18
00:01:01,200 --> 00:01:06,630
Let's actually give this a fixed width and height and you know what while we're here let's set the image

19
00:01:06,630 --> 00:01:07,530
to aspect.

20
00:01:07,880 --> 00:01:14,280
Fill the label we're going to go ahead and pin let's do 20 from the bottom and pin it horizontally as

21
00:01:14,280 --> 00:01:15,140
well.

22
00:01:15,150 --> 00:01:18,810
Again I apologize for moving so quickly but I did say we were going to.

23
00:01:18,810 --> 00:01:24,160
So anyway this label is going to say what a beautiful image.

24
00:01:24,600 --> 00:01:24,860
OK.

25
00:01:24,870 --> 00:01:26,270
That's what it's going to say.

26
00:01:26,610 --> 00:01:32,320
And this button will say load image.

27
00:01:32,580 --> 00:01:33,150
OK.

28
00:01:33,420 --> 00:01:38,340
Now let's go ahead and let's head into the assistant editor here and let's link this up to the view

29
00:01:38,340 --> 00:01:41,520
controller interface visi.

30
00:01:41,610 --> 00:01:48,190
So for the image loading button we're actually going to use an IB Action K and it's going to be called

31
00:01:48,210 --> 00:01:52,180
load image button was pressed.

32
00:01:52,650 --> 00:01:55,170
OK there we go.

33
00:01:55,170 --> 00:02:04,650
Then we're going to need an outlet for image view so we'll just say pretty image view because it's going

34
00:02:04,650 --> 00:02:10,720
to load a pretty image and then this label is going to be the caption label.

35
00:02:11,080 --> 00:02:11,870
OK.

36
00:02:12,180 --> 00:02:24,030
So by default let's go ahead and let's set our caption label k to be hidden awesome and we'll set that

37
00:02:24,030 --> 00:02:26,020
to be true.

38
00:02:26,220 --> 00:02:27,510
Very cool.

39
00:02:27,510 --> 00:02:36,270
Then we're going to actually go ahead and move on because we have everything that we need here.

40
00:02:36,300 --> 00:02:37,200
Cool it's linked.

41
00:02:37,200 --> 00:02:39,320
The button has an IB action.

42
00:02:39,330 --> 00:02:42,630
The image has been linked to the caption has been linked.

43
00:02:42,630 --> 00:02:48,550
And so now I guess we can just write a quick function that will download an image from the internet.

44
00:02:48,810 --> 00:02:49,980
Pretty straightforward stuff.

45
00:02:49,980 --> 00:02:53,880
Let's go ahead and actually give us some space so we can see what we're doing here.

46
00:02:54,330 --> 00:02:59,800
Let's go ahead and write this function phunk download image for.

47
00:02:59,880 --> 00:03:07,530
From I guess from you r l with a u r l string K using that internal parameter there and we are going

48
00:03:07,530 --> 00:03:12,900
to be using u r l session which involves a closure so we're going to need a completion handler that

49
00:03:12,900 --> 00:03:18,900
can escape from that so just call completion here and it's going to be escaping because we want it to

50
00:03:18,900 --> 00:03:21,690
be able to escape from the closure inside our function.

51
00:03:22,080 --> 00:03:26,670
And of course our completion handler here is basically going to just return void.

52
00:03:26,670 --> 00:03:28,250
We don't need to return anything.

53
00:03:28,470 --> 00:03:33,600
But we are going to pass a UI image into that completion handler.

54
00:03:33,600 --> 00:03:41,160
So inside our function we're going to actually use your session shared dot data task with you l and

55
00:03:41,160 --> 00:03:42,770
completion handler.

56
00:03:42,780 --> 00:03:44,040
We're going to pass an R U r l.

57
00:03:44,040 --> 00:03:48,600
But first we should create an instance of u r l and not just string so type.

58
00:03:48,600 --> 00:03:57,630
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

59
00:03:57,630 --> 00:04:02,520
to say otherwise if that doesn't work we're going to call fatal error which basically means hey if R

60
00:04:02,520 --> 00:04:06,870
U R L is invalid or should not continue because that could cause a really nasty crash.

61
00:04:06,870 --> 00:04:10,580
So once r u r l has been created we can actually pass it in here.

62
00:04:10,660 --> 00:04:16,770
U r l and the completion handler we can just push enter on and we can give it a property here of data

63
00:04:17,400 --> 00:04:19,980
response and error k.

64
00:04:20,010 --> 00:04:29,460
Now if we have an error meaning if error is not equal to nil K we're going to go ahead and call fatal

65
00:04:29,460 --> 00:04:29,960
error.

66
00:04:30,100 --> 00:04:34,260
Ok it's going to print out an error response and it's going to halt the application.

67
00:04:34,320 --> 00:04:40,770
Now if we are good to go right if we don't have any problems we're going to need to basically encapsulate

68
00:04:40,770 --> 00:04:42,930
data in a way that is safe.

69
00:04:42,930 --> 00:04:46,130
So we're going to use guard let guard let data.

70
00:04:46,350 --> 00:04:48,200
It's going to be equal to data.

71
00:04:48,420 --> 00:04:54,000
And we also need to create an image from that data that is downloaded so we can actually do a second

72
00:04:54,330 --> 00:04:55,170
constant here.

73
00:04:55,170 --> 00:04:59,240
Let image equals image from data.

74
00:04:59,250 --> 00:05:02,130
And the cool thing is that both of these are optional.

75
00:05:02,220 --> 00:05:05,160
But when we use guard let we can create them as if they're not.

76
00:05:05,190 --> 00:05:07,190
So it will pass in our data here.

77
00:05:07,320 --> 00:05:11,850
Otherwise we're going to go ahead and call fatal error because that will be a fatal error if we don't

78
00:05:11,850 --> 00:05:14,080
have a successful image download.

79
00:05:14,220 --> 00:05:20,310
Then at the very end we can call completion and it's asking us to pass in a new image which we now have

80
00:05:20,310 --> 00:05:21,420
is called image.

81
00:05:21,600 --> 00:05:22,940
So pass it in.

82
00:05:23,220 --> 00:05:29,020
Then of course at the end of a data task you need to call DOT resume in order for that task to continue.

83
00:05:29,040 --> 00:05:32,450
And now we have a function that can successfully download an image.

84
00:05:32,460 --> 00:05:39,390
So what we're going to do is we're basically going to say hey if the pretty image view image is nil

85
00:05:39,420 --> 00:05:44,670
meaning if there's no image in the image view we're going to go ahead and basically you know download

86
00:05:44,670 --> 00:05:45,000
our image.

87
00:05:45,000 --> 00:05:47,730
So type download image from you URL.

88
00:05:47,820 --> 00:05:53,820
And this is where we're going to have to basically create a constant that has a file in it.

89
00:05:53,820 --> 00:06:01,050
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

90
00:06:01,050 --> 00:06:02,230
going to be a string.

91
00:06:02,580 --> 00:06:07,110
What you can do is you can go find any image on the Internet you can copy and it's you are all like

92
00:06:07,110 --> 00:06:10,460
I have done here this downloads from a Web site called pixel's dot com.

93
00:06:10,460 --> 00:06:16,830
They have non-attribute and royalty free images you can use in any project even commercial projects.

94
00:06:16,830 --> 00:06:18,800
So there's my image you are l.

95
00:06:19,000 --> 00:06:26,400
Now I'm going to go back whoops to interface Visi I believe it was interface Visi and I can pass in

96
00:06:26,400 --> 00:06:30,330
my image you Arel which I have to build in order to find.

97
00:06:30,330 --> 00:06:36,360
There it is boom and the completion handler of course is going to be just named image because that's

98
00:06:36,360 --> 00:06:39,710
what's returned and passed out of the escaping closure.

99
00:06:39,900 --> 00:06:44,520
Then what we're going to do is we're basically going to say hey if we have successfully downloaded our

100
00:06:44,520 --> 00:06:49,540
image we're going to set the image view so self pretty imagery image.

101
00:06:49,560 --> 00:06:53,790
Now of course we're calling self because we are within a closure we need to make a reference to what

102
00:06:53,790 --> 00:06:55,600
view controller we're referring to.

103
00:06:56,010 --> 00:07:00,670
But we're going to set the image property to the image that is downloaded very easy.

104
00:07:00,750 --> 00:07:07,650
But what we're going to test is to make sure that our caption properly shows when our sync code has

105
00:07:07,650 --> 00:07:08,370
finished.

106
00:07:08,400 --> 00:07:09,100
OK.

107
00:07:09,270 --> 00:07:14,040
So in order to do that remember we said it to be hidden from the beginning because there is no image

108
00:07:14,400 --> 00:07:20,870
what we can do is after it's downloaded self damn caption label dot is hidden.

109
00:07:21,230 --> 00:07:22,730
Is false.

110
00:07:22,770 --> 00:07:23,340
OK.

111
00:07:23,640 --> 00:07:25,400
That way it's hidden from the beginning.

112
00:07:25,530 --> 00:07:30,720
After we download our image it can be false meaning it's showing very very easy.

113
00:07:30,720 --> 00:07:36,680
But one thing to note we are going to run into a problem or else session happens on a background thread

114
00:07:36,690 --> 00:07:39,110
when we pass this image through.

115
00:07:39,120 --> 00:07:42,050
This is also happening on a background thread.

116
00:07:42,060 --> 00:07:50,540
So we need to actually set UI elements on the main thread so we can call dispatch queue up Main async

117
00:07:50,850 --> 00:07:56,550
and then we can actually just go ahead and cut and paste this into there and then it can properly update

118
00:07:56,610 --> 00:07:57,450
on the main thread.

119
00:07:57,450 --> 00:08:03,660
That's just a requirement of iOS UI elements must update on the main thread so that will cause that

120
00:08:03,660 --> 00:08:05,610
will prevent us from having problems.

121
00:08:05,610 --> 00:08:11,090
So let's go ahead and head into our tests here and let's open the assistant editor with our interface

122
00:08:11,090 --> 00:08:12,630
Visi right next door.

123
00:08:13,070 --> 00:08:18,820
OK so controller interface Visi and now we're going to go ahead and write a test.

124
00:08:18,870 --> 00:08:25,980
So go ahead and write phunk test and we're going to test that when an image download completes that

125
00:08:26,010 --> 00:08:27,450
the caption label is presented.

126
00:08:27,450 --> 00:08:33,990
So we're going to test image download when download complete

127
00:08:37,220 --> 00:08:45,050
caption label showing K that's what we're testing that the caption label is showing when our download

128
00:08:45,050 --> 00:08:45,770
is complete.

129
00:08:45,800 --> 00:08:51,910
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.

130
00:08:52,040 --> 00:08:58,550
But now what we're going to do is we're basically going to set up an instance of our static text which

131
00:08:58,550 --> 00:08:59,670
we've used in the past.

132
00:08:59,690 --> 00:09:03,700
Right we have checked for static text in labels on our screen.

133
00:09:03,800 --> 00:09:06,110
We've checked for things like that.

134
00:09:06,120 --> 00:09:07,810
K right here here it is.

135
00:09:07,910 --> 00:09:10,190
We've checked for certain labels using static text.

136
00:09:10,250 --> 00:09:14,840
And so we're going to basically just use a constant here to store that.

137
00:09:14,840 --> 00:09:25,400
So let image caption equals app dot static texts K and the label that shows says what a beautiful image

138
00:09:25,400 --> 00:09:26,730
with an exclamation mark.

139
00:09:26,810 --> 00:09:27,510
Right.

140
00:09:27,590 --> 00:09:33,470
So now we have an instance of image caption which basically we can use to call you know image caption

141
00:09:33,500 --> 00:09:37,250
dot exist and we could call it here but it wouldn't make sense to use it there.

142
00:09:37,260 --> 00:09:39,120
So let's continue.

143
00:09:39,150 --> 00:09:44,300
We now have an instance of our image caption and now we're going to make is something called an N S

144
00:09:44,360 --> 00:09:45,140
predicate.

145
00:09:45,140 --> 00:09:46,670
Let me create it and then we'll talk about it.

146
00:09:46,670 --> 00:09:54,320
So Type let exists let exists equals an s predicate K and actually you know what I want you to see that

147
00:09:54,320 --> 00:09:55,200
definition there.

148
00:09:55,210 --> 00:10:02,150
N n s predicate is a definition of logical conditions used to constrain a search either for a fetch

149
00:10:02,420 --> 00:10:04,610
or for in-memory filtering.

150
00:10:04,640 --> 00:10:05,200
OK.

151
00:10:05,420 --> 00:10:08,780
Now if that's making your brain go well that's fine.

152
00:10:08,780 --> 00:10:12,620
But we're going to use the one with a format and actually get rid of the arguments because we don't

153
00:10:12,620 --> 00:10:14,590
need any arguments necessarily.

154
00:10:14,660 --> 00:10:20,960
But what this is going to do is it's basically going to set up a logical condition to where if the exists

155
00:10:20,960 --> 00:10:25,240
property on image caption get set to true.

156
00:10:25,430 --> 00:10:30,530
This is going to help us basically trigger hey it's done and now we can call our test.

157
00:10:30,530 --> 00:10:33,000
So in the format K right here.

158
00:10:33,020 --> 00:10:35,380
Go ahead and type exists.

159
00:10:35,380 --> 00:10:42,480
Equals with two equals true case we're using the logical equivalence symbol basically saying hey if

160
00:10:42,540 --> 00:10:45,940
exists is ever equal to true.

161
00:10:45,950 --> 00:10:47,100
We're going to continue.

162
00:10:47,270 --> 00:10:53,150
Now what we need to do is we actually need to wait for our async code to happen and let's say we had

163
00:10:53,150 --> 00:10:58,330
really slow internet K.R. our code might take longer or let's say we were downloading multiple images

164
00:10:58,340 --> 00:11:01,910
not every single image is going to download in the exact same time.

165
00:11:01,910 --> 00:11:04,470
So this is where expectations come into place.

166
00:11:04,490 --> 00:11:10,190
We're going to create an expectation that accepts an end as predicate and it's going to accept one of

167
00:11:10,190 --> 00:11:14,960
our queries which is what we're doing here we're searching for this label using image caption.

168
00:11:14,960 --> 00:11:22,070
And then as soon as exists becomes true it's going to go ahead and basically say hey it's done we have

169
00:11:22,070 --> 00:11:26,900
evaluated whether or not something exists so it's just it's almost like we're creating a way for it

170
00:11:26,900 --> 00:11:31,510
to tell when a certain condition of our image caption becomes true or false.

171
00:11:31,520 --> 00:11:38,270
So go ahead and just type expectation for and as predicate we can pass and exist because we're checking

172
00:11:38,270 --> 00:11:41,410
we're predicating that exist is true.

173
00:11:41,750 --> 00:11:44,450
And we are evaluating it with the image caption.

174
00:11:44,450 --> 00:11:49,520
So we're checking to see if it's if it exists and from the beginning of course that's false because

175
00:11:49,930 --> 00:11:51,150
it doesn't exist.

176
00:11:51,170 --> 00:11:54,820
So the handler is going to be nil because we don't care what happens at the end of this.

177
00:11:54,920 --> 00:11:59,650
But now what we need to do is we need to remember our app is launching from a fresh state.

178
00:11:59,660 --> 00:12:04,580
So we're going to need to actually go ahead and do exactly what we do for our There are other apps that

179
00:12:04,580 --> 00:12:09,460
get through the onboarding experience first by swiping left twice and tapping done.

180
00:12:09,470 --> 00:12:11,600
OK so I just copied that and pasted it.

181
00:12:11,840 --> 00:12:18,830
Then of course when our pop up appears right our little alert Visi we're going to go ahead and just

182
00:12:18,830 --> 00:12:26,960
call app dot alerts and the alert title is you did it so we can find it using its title then we can

183
00:12:26,960 --> 00:12:31,280
look through the buttons on that alert and tap the awesome button if you remember.

184
00:12:31,280 --> 00:12:32,210
That's how we did it.

185
00:12:32,210 --> 00:12:33,950
So we found the button.

186
00:12:33,950 --> 00:12:39,710
Now we call tap and then it dismisses which is very cool but now we have a new image in our interface

187
00:12:39,710 --> 00:12:39,980
right.

188
00:12:39,980 --> 00:12:41,480
We have a load image button.

189
00:12:41,480 --> 00:12:45,330
And when it's pressed it downloads our image right.

190
00:12:45,380 --> 00:12:52,670
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

191
00:12:52,670 --> 00:12:53,050
button.

192
00:12:53,060 --> 00:12:53,360
Whoops.

193
00:12:53,360 --> 00:12:54,350
Make sure that you type it.

194
00:12:54,350 --> 00:12:56,580
Case sensitive and push tap.

195
00:12:56,600 --> 00:12:58,630
So now our button has been tapped.

196
00:12:58,760 --> 00:13:06,200
But now if we were to go ahead and type LCT assert and then just basically we're asserting that a certain

197
00:13:06,200 --> 00:13:07,760
element exists in this case.

198
00:13:07,760 --> 00:13:13,850
Image caption exists if we were to assert that it would instantly fail because we still have to download

199
00:13:13,850 --> 00:13:18,620
the image and to prove that check it out we're going to go ahead and run our test to see how we do.

200
00:13:18,620 --> 00:13:20,730
Of course like I just told you it is going to fail.

201
00:13:20,930 --> 00:13:25,580
But we are definitely moving in the right direction.

202
00:13:25,610 --> 00:13:26,890
So here we go.

203
00:13:27,050 --> 00:13:29,000
Our apps going to open up it's going to launch.

204
00:13:29,090 --> 00:13:31,030
We're going to swipe left twice.

205
00:13:31,040 --> 00:13:32,830
Here we go one to tap.

206
00:13:32,830 --> 00:13:36,790
Done dun tap the awesome button tap load image and fails.

207
00:13:36,800 --> 00:13:37,070
Right.

208
00:13:37,070 --> 00:13:38,450
Because we need to wait.

209
00:13:38,510 --> 00:13:41,760
We need to tell it to wait before running the assertion.

210
00:13:41,960 --> 00:13:49,460
And so what we're going to do is we're going to go ahead and call wait for expectations and this expectation

211
00:13:49,640 --> 00:13:53,440
that image caption exists we need to wait to actually check that.

212
00:13:53,440 --> 00:13:57,270
So let's wait five seconds and the handler no one cares.

213
00:13:57,340 --> 00:13:58,860
Or at least I hope so.

214
00:13:58,950 --> 00:14:04,520
We're going to go ahead and run this one more time and see if waiting five seconds impacts whether or

215
00:14:04,520 --> 00:14:06,430
not the test passes or fails.

216
00:14:06,490 --> 00:14:10,120
And we're checking to see if image caption exists right.

217
00:14:10,160 --> 00:14:11,790
So here we go.

218
00:14:11,810 --> 00:14:19,270
Going to go ahead and open our test here swipe through one to tap dun tap the awesome button tap load

219
00:14:19,270 --> 00:14:21,020
image wait five seconds.

220
00:14:21,810 --> 00:14:26,890
And our test passes the image was there meaning the image caption was there as well.

221
00:14:26,970 --> 00:14:31,250
And so we have now verified that our label shows up exactly as we are hoping.

222
00:14:31,260 --> 00:14:32,370
Very very cool stuff.

223
00:14:32,370 --> 00:14:37,960
So this is how you can perform UI testing after a particular asynchronous call.

224
00:14:37,980 --> 00:14:39,210
Very very good work.

225
00:14:39,210 --> 00:14:40,230
Amazing job guys.

226
00:14:40,290 --> 00:14:42,800
Let's head on over to our exorcized now.
