Transcript
00:00 Because a grid function introduces a side effect by constructing a new date, it needs a proper setup to run. The setup phase is the most important part of any test, because it prepares the environment for the tested code to run.
00:12 For example, by handling side effects and dependencies introduced by the code, making those variable and unpredictable parts fixed and given. Because the setup phase is tightly coupled to how tests are run, you will often find testing frameworks giving you the APIs to implement the setup,
00:28 such as functions like before_all and after_all that are called hooks. I will start by adding those functions, those hooks, to our testing framework. Much like expect and test, those functions will be available globally, so I will head to setup.ts and make them global. First, I will declare them on a type level.
00:46 So, before_all function will accept a callback, which is another function, and then return nothing. And similar to this, we will have an after_all function that does quite the same. Remember that this is just the type part of the globals, and now we have to provide the actual implementation for before_all and after_all. So, let's do that.
01:05 We're going to head here and assign a new key to the global list object called before_all, which is a function that accepts the callback, the one we just described. And inside this function, we will just call this callback immediately. So, this stands for executing the callback as soon as the before_all function, this hook, is called in our test. Let's do the after_all function now.
01:25 In the same way, we will assign it to the global object, but here we cannot really call callback straight away. It would be awesome to call it when the tests are done. To listen to this, we will rely on the before_exit event on the process, which is a global object in Node.js,
01:39 and this event will emit whenever the process of the test is about to exit, which indicates that the tests are done. And we will call the callback then. So, the before_all hook will be responsible for introducing any logic to handle side effects,
01:53 and after_all hook will run when the tests are done to clean up whatever logic we introduced in the before_all hook. With these hooks in place, let's head to our test and now mock the date to make it more predictable. So, first I will store the original implementation of the date from the global list of date constructor on the original date object.
02:12 Then I will add the before_all hook, and here I will mock this global date constructor by introducing a proxy. Proxy is a global API in JavaScript that will allow me to spy on this class and know when it's being constructed, so whenever any tested code calls new date.
02:31 And instead of constructing it for real, we will return a fixed date using the original date constructor that will point to the 1st of January 2024, which happened to be Monday. Now, with this in place, we can mock and control the date whenever it's called, so it's no longer unpredictable. But we need to clean up ourselves so this proxy doesn't leak to unrelated tests.
02:50 To do that, we have the after_all hook. So, inside this hook, we are going to reassign the global_date variable to the original date that we stored before, introducing any kind of mocking. Now, let's try running these tests.
03:07 So, both tests are now passing reliably, even though I'm recording on Friday. The greeting for the John will still mention Monday, because we introduced the mock for the date constructor that will always return Monday. And now, our test for the greet function passes the golden rule of assertion,
03:24 which states that the test should only fail when the intention behind the tested code is not met. This means that even if the actual greeting message includes "Happy Friday", that's still a perfectly functional code. It's just an indication that our testing setup is not efficient and doesn't handle a side effect in this case.
03:42 I encourage you to refer to the golden rule of assertions often when writing tests, because it can help you tell apart good tests for bad ones, for example, those that miss the testing setup.