1
00:00:00,180 --> 00:00:06,720
Now we had a basic introduction to testing now, to the core types of tests but thus far we always tested

2
00:00:07,050 --> 00:00:13,770
relatively simple code, synchronous code where nothing special was happening, where no side effects

3
00:00:13,770 --> 00:00:18,840
were involved like a HttpRequest going out when a function is called.

4
00:00:18,840 --> 00:00:24,810
Now things like that can cause problems when you're trying to run tests because your tests will also

5
00:00:24,810 --> 00:00:31,620
trigger that code which might send a HttpRequest or which might do something which makes the test take

6
00:00:31,620 --> 00:00:34,670
longer, might hit a backend API

7
00:00:34,740 --> 00:00:37,170
or might towards results.

8
00:00:37,170 --> 00:00:43,830
So now we'll have a look at what we can do to make our test simpler and focus on the core things and

9
00:00:43,830 --> 00:00:46,640
really only test what matters to us.

10
00:00:46,650 --> 00:00:51,950
So for this, again I prepared a starting project which you find attached to this lecture here so that

11
00:00:51,960 --> 00:00:58,560
you can follow along and if you start the project by double clicking the index.html file, you'll see

12
00:00:58,560 --> 00:01:04,110
a button there, if you click that button, you will eventually see an all uppercase text being printed

13
00:01:04,110 --> 00:01:04,680
here.

14
00:01:04,680 --> 00:01:08,120
Now responsible for that output is this code here,

15
00:01:08,130 --> 00:01:10,870
I got a very simple setup here using webpack

16
00:01:11,100 --> 00:01:14,280
and here I'm getting access to a button in my DOM,

17
00:01:14,370 --> 00:01:20,100
I'm adding a listener to print the title. In print title, I call load title which is this function here,

18
00:01:20,390 --> 00:01:26,480
in that function I reach out to fetch data which is provided in a different file also created by me.

19
00:01:26,640 --> 00:01:33,330
There, I seem to get some data object of which I extract the title, I then transform this title to

20
00:01:33,330 --> 00:01:35,190
be all uppercase and I return that

21
00:01:35,190 --> 00:01:36,980
hence I can print it here.

22
00:01:36,990 --> 00:01:42,450
Now if we have a look in this HTTP file, into this http.js file, here I'm using a third-party

23
00:01:42,450 --> 00:01:43,710
package, axios,

24
00:01:43,710 --> 00:01:44,900
so this is not written by me,

25
00:01:44,900 --> 00:01:50,960
this is another third-party package and here in fetch data, I make a get request to a dummy API,

26
00:01:51,000 --> 00:01:54,930
so this is a real API in the web, a real request is made here,

27
00:01:54,960 --> 00:01:57,060
this API is not maintained by me,

28
00:01:57,180 --> 00:02:04,020
it's just an API we can use for playing around, for testing and there, I get back a response object, axios

29
00:02:04,050 --> 00:02:09,360
gives me such a response object which happens to have a couple of properties, like the status code for

30
00:02:09,360 --> 00:02:13,550
example but also the data property which I'm extracting here.

31
00:02:13,590 --> 00:02:15,320
This is essentially what I do,

32
00:02:15,420 --> 00:02:17,350
now let's write some tests.

33
00:02:17,460 --> 00:02:26,610
I already installed the jest package here and I also already configured my test command here to use

34
00:02:26,610 --> 00:02:27,590
jest,

35
00:02:27,600 --> 00:02:34,500
I also have a project where I use Node.js import export syntax because jest uses that by default

36
00:02:34,710 --> 00:02:40,350
and just as with my other testing video where I gave you an introduction to testing with jest, there

37
00:02:40,350 --> 00:02:45,870
I explained that jest uses that syntax, that setting it up to understand a different syntax would be

38
00:02:45,870 --> 00:02:51,300
more complex and I still don't want to do that here because here, I want to focus on testing async code.

39
00:02:51,810 --> 00:02:54,420
So we got everything set up to write some tests, so

40
00:02:54,480 --> 00:03:01,970
let's do that. You learned in that last video that you can create a new file with .test.js at

41
00:03:01,980 --> 00:03:06,400
the end to have Jest.js pick it up and execute it automatically.

42
00:03:06,510 --> 00:03:12,410
So this will be the testing file for app.js and let's say we want a test print title.

43
00:03:12,420 --> 00:03:15,610
Conveniently I'm already exporting it here at the bottom,

44
00:03:15,810 --> 00:03:16,980
so what can we do?

45
00:03:17,010 --> 00:03:22,980
Well in app-test.js, we can use the test function which is globally available when we run that

46
00:03:22,980 --> 00:03:30,270
file with jest, there we give it a description, some text, yes some description of what should be tested

47
00:03:30,270 --> 00:03:39,690
here and there I have should print an uppercase text for example. I have my arrow function then that

48
00:03:39,690 --> 00:03:45,550
should execute or that contains the testing logic and in there we define our expectations.

49
00:03:45,720 --> 00:03:52,740
Now we could expect uppercase text with the help of some regex magic or anything like that but here

50
00:03:53,040 --> 00:03:59,100
because we'll change that anyways, I just want to expect this text because right now I will always get

51
00:03:59,100 --> 00:04:06,090
the text for the API endpoint I'm hitting. So I expect and now I need to import that function which

52
00:04:06,090 --> 00:04:07,360
I want to test,

53
00:04:07,560 --> 00:04:18,040
so that will be print title, I am pulling that out of my exported object in the app.js file,

54
00:04:18,050 --> 00:04:27,100
so I expect a print title, the result of that function call to be equal to my all uppercase text here,

55
00:04:27,100 --> 00:04:28,830
this is my expectation.

56
00:04:28,960 --> 00:04:36,650
We can now run that test by running npm test and this executes all test.js files and this actually

57
00:04:36,650 --> 00:04:41,660
fails because it fails to execute add event listener null.

58
00:04:41,690 --> 00:04:48,850
Now the reason for that actually is that app.js contains some code that will always run when this file

59
00:04:48,860 --> 00:04:55,580
gets executed and it does get executed when I import from that file and it tries to access the DOM here

60
00:04:55,640 --> 00:04:57,980
which just doesn't work in this environment

61
00:04:57,980 --> 00:05:00,410
here, the real DOM is not loaded here,

62
00:05:00,410 --> 00:05:06,520
so an easy way around that is to take that function and export it into a separate file,

63
00:05:06,530 --> 00:05:08,790
maybe a util.js file,

64
00:05:08,870 --> 00:05:15,030
this is also something we did in the last video already, export print title here

65
00:05:16,880 --> 00:05:22,340
and what this allows us to do is it allows us to import something from that file only without executing

66
00:05:22,370 --> 00:05:29,190
app.js and therefore without hitting the real DOM. So we can rename that testing file here to

67
00:05:29,230 --> 00:05:37,310
utiltest.js and we import print title from ./util and in app.js since I removed

68
00:05:37,340 --> 00:05:38,800
print title from there,

69
00:05:38,810 --> 00:05:48,950
we also need to import print title by requiring it from the ./util file here

70
00:05:49,080 --> 00:05:54,750
and now for that to work, I'll also have to move load title over to util.js because print title

71
00:05:54,750 --> 00:05:56,370
depends on that,

72
00:05:56,370 --> 00:05:59,670
so let's move load title into that file as well.

73
00:05:59,670 --> 00:06:02,310
That means that fetch data also needs to move in there,

74
00:06:02,550 --> 00:06:09,900
so from app.js let's grab the fetch data import and move that to the util.js file

75
00:06:09,900 --> 00:06:18,240
and now with that setup, if we rerun npm test here, now it should be able to run our test here and it

76
00:06:18,240 --> 00:06:18,680
does

77
00:06:18,690 --> 00:06:24,920
but I get an error that essentially it expected a string but it received undefined

78
00:06:25,320 --> 00:06:31,100
and now this already shows us a problem we have with asynchronous code testing.

79
00:06:31,140 --> 00:06:34,690
Well actually in print title, I am indeed returning nothing,

80
00:06:34,710 --> 00:06:37,560
so getting undefined as a result makes perfect sense

81
00:06:38,100 --> 00:06:43,410
but even if I would return something, like for example in here, if I not only log the title but I also

82
00:06:43,410 --> 00:06:50,390
returned the title here, if I do that and I rerun, I will still get that error,

83
00:06:50,400 --> 00:06:55,260
I can already say that. The reason for that is that and that has nothing to do with testing, that's normal

84
00:06:55,260 --> 00:07:00,640
Javascript behavior, return statements inside of callbacks or inside of promise

85
00:07:00,660 --> 00:07:06,990
then calls are not executed or are executed but Javascript does not wait for them,

86
00:07:07,020 --> 00:07:11,940
it does not return this value as a return value for this overall function,

87
00:07:11,940 --> 00:07:15,170
instead this is the return value of that inner function here

88
00:07:15,300 --> 00:07:17,220
and we're not testing this inner function,

89
00:07:17,280 --> 00:07:19,950
we're testing that overall function.

90
00:07:20,040 --> 00:07:27,030
So in our case here, one simple solution would be to test load title. Here we return something in the inner

91
00:07:27,030 --> 00:07:27,870
function

92
00:07:27,870 --> 00:07:30,390
and we also return something in the main function,

93
00:07:30,450 --> 00:07:32,870
we returned the whole promise.

94
00:07:32,910 --> 00:07:38,610
So chances are that we get back a promise here to which we then can listen and that might allow us to

95
00:07:38,610 --> 00:07:40,650
expect something helpful.

96
00:07:40,680 --> 00:07:47,740
So let's change something, let's export load title here so that we can test it,

97
00:07:47,760 --> 00:07:54,450
let's go to utiltest.js and there, I will not expect something like that but I'll get my title

98
00:07:55,050 --> 00:08:03,410
but instead, I will import load title here and I will execute load title and this gives us a promise

99
00:08:03,410 --> 00:08:09,510
so I will add then here and in there, I know I'll get my title because that's exactly the way I use

100
00:08:09,510 --> 00:08:10,800
it in print title right,

101
00:08:10,800 --> 00:08:13,710
I have load title and then I get my title.

102
00:08:13,890 --> 00:08:21,030
So now I have the exact same usage here in utiltest.js and now here I want to expect something, that

103
00:08:21,030 --> 00:08:25,930
my title should be equal to that uppercase title I got here.

104
00:08:26,040 --> 00:08:35,410
So we can grab that title here, copy it and that is what I expect as a value. Now if I rerun npm test,

105
00:08:36,880 --> 00:08:40,760
it actually passes because now this test succeeds.

106
00:08:40,810 --> 00:08:41,690
So this is better,

107
00:08:41,700 --> 00:08:46,750
this is how we could test our asynchronous code but we still have a problem here,

108
00:08:46,840 --> 00:08:50,290
the problem is we're still hitting our API.

109
00:08:50,950 --> 00:08:56,170
So here in util.js, I'm using fetch data and if you remember, we're defining that in the HTTP

110
00:08:56,170 --> 00:09:00,530
file, so here and there we're making a real API request.

111
00:09:00,580 --> 00:09:07,300
We typically don't want to do that in testing, we might exceed certain API quotas if we do that, if we're

112
00:09:07,300 --> 00:09:08,800
testing post requests,

113
00:09:08,830 --> 00:09:14,410
we might even edit something on the API which we certainly don't want to do as part of testing,

114
00:09:14,440 --> 00:09:17,180
certainly not with our production API at least.

115
00:09:17,320 --> 00:09:20,590
So hitting the API is typically not something we want to do,

116
00:09:20,590 --> 00:09:22,950
there also are other reasons against it,

117
00:09:22,990 --> 00:09:29,860
what would we achieve by really making that HttpRequest? Do you want to test if your API works correctly?

118
00:09:30,190 --> 00:09:35,090
If you're building that API, you should do these tests during the API development,

119
00:09:35,170 --> 00:09:37,050
not when working on your frontend,

120
00:09:37,150 --> 00:09:39,100
these two should be separated,

121
00:09:39,340 --> 00:09:41,400
so that is certainly not something you want to test.

122
00:09:41,500 --> 00:09:48,170
If the API works or not is not something you test in your frontend code, you might test error fallbacks

123
00:09:48,190 --> 00:09:51,770
or anything like that but not if the API works correctly.

124
00:09:51,940 --> 00:09:57,880
You also don't want to test if the get method exposed by axios works correctly.

125
00:09:57,880 --> 00:10:03,270
That is a method provided by a third-party package and we rely on that package doing its job,

126
00:10:03,310 --> 00:10:06,930
so we also don't test third-party package functionalities.

127
00:10:07,060 --> 00:10:14,140
We want to test our own code and our own code here for example is that we extract data and that here,

128
00:10:14,200 --> 00:10:17,740
that we transform this to uppercase and that we pull out the title.
