WEBVTT

1
00:00:00.370 --> 00:00:03.730
Testing asynchronous functions
can be a unique challenge.

2
00:00:03.730 --> 00:00:07.070
Our battleship game doesn't have
any asynchronous elements but

3
00:00:07.070 --> 00:00:08.640
we might want it to.

4
00:00:08.640 --> 00:00:12.990
For example, If it were played across
an Internet connection on two computers,

5
00:00:12.990 --> 00:00:15.820
one player would have to wait for
the other's turn.

6
00:00:15.820 --> 00:00:17.440
If we wanted to save
our game somewhere and

7
00:00:17.440 --> 00:00:22.160
start again later we'd need to connect to
a database that stored our game state.

8
00:00:22.160 --> 00:00:25.840
Those processes would probably
be synchronous for efficiency.

9
00:00:25.840 --> 00:00:30.560
Mocha allows us to say that a test back or
test suite is asynchronous.

10
00:00:30.560 --> 00:00:35.480
So passing an argument to the internal
function of a describe or it block,

11
00:00:35.480 --> 00:00:40.360
we'll tell Mocha to wait on running our
expectations until we specifically say so.

12
00:00:40.360 --> 00:00:41.760
Let me show you how it works.

13
00:00:41.760 --> 00:00:46.591
I'll create the function inside the main
GAME INSTANCE FUNCTIONS suite right below

14
00:00:46.591 --> 00:00:47.824
the takeTurn suite.

15
00:00:55.481 --> 00:00:59.865
Now, in this function we'd normally have
to write some code to communicate with

16
00:00:59.865 --> 00:01:00.964
a remote database.

17
00:01:00.964 --> 00:01:05.241
But instead, I'll simulate that
idea with a setTimeout function.

18
00:01:17.007 --> 00:01:21.557
So setTimeout will perform whatever
function we describe after a specified

19
00:01:21.557 --> 00:01:23.650
number of milliseconds.

20
00:01:23.650 --> 00:01:27.070
If our game really communicated
with a database the seTimeout

21
00:01:27.070 --> 00:01:31.830
function would be replaced with something
that sent a request to our database.

22
00:01:31.830 --> 00:01:38.050
So I'll set the function to run after one
second has passed, or, 1000 milliseconds.

23
00:01:38.050 --> 00:01:42.560
So after one second the database function
would finish and perform some callback,

24
00:01:42.560 --> 00:01:45.280
like telling the player that
the game was saved successfully.

25
00:01:47.160 --> 00:01:52.487
So let's pass callback as
a parameter of saveSame.

26
00:01:52.487 --> 00:01:57.450
Then we'll call callback
inside setTimeout.

27
00:01:57.450 --> 00:02:01.030
All right, so now we can create
the test suite for saveGame.

28
00:02:01.030 --> 00:02:04.556
So right below the saveGame function,
as always,

29
00:02:04.556 --> 00:02:08.256
we'll create a new test suite by typing,
describe.

30
00:02:08.256 --> 00:02:10.730
And we're going to name this one,
saveGame.

31
00:02:17.578 --> 00:02:20.895
And then I'll open my first spec for
this function inside the suite.

32
00:02:20.895 --> 00:02:25.098
So we'll say,
it('should update save status').

33
00:02:37.418 --> 00:02:40.047
And now I have a space to
write some expectations

34
00:02:40.047 --> 00:02:41.910
about how saveGame should work.

35
00:02:41.910 --> 00:02:44.500
So to test synchronous functions
like the ones we've written

36
00:02:44.500 --> 00:02:49.070
before now in the course, I would run
the function inside of my spec and

37
00:02:49.070 --> 00:02:52.920
then write an expectation about
something that changed as a result.

38
00:02:52.920 --> 00:02:57.119
So to use that strategy in this case, I
might try running saveGame with a callback

39
00:02:57.119 --> 00:03:01.340
and writing an expectation at the end of
the callback to capture the new results.

40
00:03:04.860 --> 00:03:09.245
So let's do that, at the top of the spec
I'll save the string, game not saved,

41
00:03:09.245 --> 00:03:11.025
in a new variable named status.

42
00:03:20.967 --> 00:03:26.690
Then I want saveGame to change the status
to, game saved, when it finishes.

43
00:03:26.690 --> 00:03:30.430
Again, in reality, that would mean
the database responded successfully.

44
00:03:30.430 --> 00:03:33.440
But in this example it's just
going to wait one second and

45
00:03:33.440 --> 00:03:37.180
then use my callback function
to update the status favorable.

46
00:03:37.180 --> 00:03:42.869
So inside saveSame we'll say,
status = game saved.

47
00:03:46.923 --> 00:03:51.523
Finally, I'll try expecting
the status to equal game

48
00:03:51.523 --> 00:03:54.628
saved after I've called saveGame.

49
00:03:54.628 --> 00:04:03.311
So right below saveGame, we'll say
expect(status).to.equal('game saved').

50
00:04:08.730 --> 00:04:13.412
So now if I bring up the console and
run my tests,

51
00:04:17.732 --> 00:04:21.630
We can see that the test
reveals a failure.

52
00:04:21.630 --> 00:04:26.545
The expectation runs before the saveGame
function is called because saveGame is

53
00:04:26.545 --> 00:04:31.720
waiting 1000 milliseconds to fire
the callback that updates status.

54
00:04:31.720 --> 00:04:35.770
So that means status will
still equal game not saved

55
00:04:35.770 --> 00:04:38.720
until an entire second has passed,
which we can see it's

56
00:04:38.720 --> 00:04:43.097
much longer than our test suite takes
to reach the expect(status) line.

57
00:04:49.990 --> 00:04:56.570
So to fix this problem, I need to move my
expectation inside the saveGame callback.

58
00:04:56.570 --> 00:05:01.118
So that it only happens after saveGame
has finished updating status.

59
00:05:05.097 --> 00:05:09.715
So now if I go back to the console and
run my test at this point

60
00:05:13.331 --> 00:05:15.470
It looks like the tests pass.

61
00:05:15.470 --> 00:05:17.780
But that's kind of tricky.

62
00:05:17.780 --> 00:05:22.590
Mocha is just running through the test
function before saveGame finishes.

63
00:05:22.590 --> 00:05:25.701
And then reports that the test spec
passes because they didn't see any

64
00:05:25.701 --> 00:05:26.818
expectations written.

65
00:05:33.197 --> 00:05:37.580
So for example, even if I write
a definitely failing expectation into

66
00:05:37.580 --> 00:05:41.905
the saveGame callback,
like expect(true).to.be.false;.

67
00:05:50.941 --> 00:05:53.380
Mocha still passes our tests.

68
00:05:53.380 --> 00:05:58.040
So we need a way to tell Mocha to wait
until saveGame has finished running

69
00:05:58.040 --> 00:06:00.000
in order to check our expectations.

70
00:06:04.650 --> 00:06:10.200
To do that, I can pass a special argument
to our test specs callback function.

71
00:06:10.200 --> 00:06:15.265
By convention we call the argument done so
that we know the argument is signaling

72
00:06:15.265 --> 00:06:20.340
Mocha that our test code is ready to be
run after some a synchronous operation.

73
00:06:20.340 --> 00:06:24.050
We normally just use the test spec
callback to contain our test code and

74
00:06:24.050 --> 00:06:26.840
expectations, but
by passing it an argument

75
00:06:26.840 --> 00:06:29.960
we signal to Mocha that we want
this test to run asynchronously.

76
00:06:31.420 --> 00:06:34.645
So now I'll delete this
example expectation.

77
00:06:37.984 --> 00:06:42.421
Then run, npm test.

78
00:06:42.421 --> 00:06:46.139
And now we see that the test
gives me a new error that says,

79
00:06:46.139 --> 00:06:48.789
saveGame should update save status:.

80
00:06:48.789 --> 00:06:52.670
Then the error says,
timeout of 2000ms exceeded.

81
00:06:52.670 --> 00:06:56.180
Ensure the done() callback is
being called in this test.

82
00:06:56.180 --> 00:07:00.950
So it looks like the error is asking for
me to call the done() callback.

83
00:07:00.950 --> 00:07:05.770
Passing the done argument to our test spec
tells Mocha that it's supposed to wait for

84
00:07:05.770 --> 00:07:08.940
instructions before
checking our expectations.

85
00:07:08.940 --> 00:07:11.910
So we passed the done argument but

86
00:07:11.910 --> 00:07:16.610
we haven't used it to tell Mocha
when our code is ready to be tested.

87
00:07:16.610 --> 00:07:18.761
So, in the saveGame callback,

88
00:07:18.761 --> 00:07:22.513
I'll add done() after
the changes I expect to occur.

89
00:07:22.513 --> 00:07:25.374
And now Mocha will wait for

90
00:07:25.374 --> 00:07:30.716
done to fire before
checking the expectations.

91
00:07:30.716 --> 00:07:32.550
So when we run the tests now.

92
00:07:36.156 --> 00:07:38.110
Great, everything works.

93
00:07:38.110 --> 00:07:42.440
And notice that there's a short
pause while the tests are running.

94
00:07:42.440 --> 00:07:44.508
That's Mocha waiting one second for

95
00:07:44.508 --> 00:07:48.321
the setTimeout function to run
before checking the expectations.

96
00:07:55.361 --> 00:07:59.018
Writing asynchronous code and
testing it correctly is a big topic.

97
00:07:59.018 --> 00:08:03.860
Usually you'll write mocks and stubs for
your database or AJAX calls because

98
00:08:03.860 --> 00:08:08.400
those are big external systems that you
don't wanna mix into your test unit.

99
00:08:08.400 --> 00:08:11.360
Just know that Mocha gives you
a way to deal with these problems.

100
00:08:11.360 --> 00:08:15.620
So, you might need to research the best
way to capture the test results you want

101
00:08:15.620 --> 00:08:16.390
when you encounter them.

102
00:08:17.600 --> 00:08:21.240
So congratulations getting started
with JavaScript unit testing.

103
00:08:21.240 --> 00:08:23.240
Good unit testing takes practice.

104
00:08:23.240 --> 00:08:27.730
And there's a lot more you can learn and
do to improve the quality of your test and

105
00:08:27.730 --> 00:08:30.220
also to make writing tests easier.

106
00:08:30.220 --> 00:08:34.059
If you've never written any tests this
testing first approach is different from

107
00:08:34.059 --> 00:08:35.141
what you're used to.

108
00:08:35.141 --> 00:08:37.580
And at first it can feel
like a lot more work.

109
00:08:38.880 --> 00:08:42.970
As you get better writing unit tests
really will improve your code.

110
00:08:42.970 --> 00:08:45.279
It will also save you lots
of time fixing bugs and

111
00:08:45.279 --> 00:08:47.780
explaining things to other developers.

112
00:08:47.780 --> 00:08:49.490
So dig into Mocha and chai and

113
00:08:49.490 --> 00:08:53.020
let us know in the community when
you find useful tips and tricks.

114
00:08:53.020 --> 00:08:54.290
Good luck and happy testing.
