
We see a few reasons to install mock clocks in tests.
- To fake the date. This makes it possible to test components which display the current time or date related information, or do some calculation with respect to the current time.
- More frequently, to speed up time. UIs are frequently written with debounces, visible delays for users, timeouts, etc. We want to verify the state of the app after these long-running tasks complete but we don’t want the test to actually wait 30 seconds for a timeout. Instead, mock clocks can fake the progression of time without needing to modify the production code to expose some overridable timeout simply to make the test quicker.
- To prevent timers from leaking into other tests, creating action at a distance errors. Mock clocks can uninstall after each test and either dispose of or flush any pending timers.
- To execute all pending timers or stabilize the test. This allows the test to say, “wait until everything that’s supposed to happen has happened”. This can be useful for several reasons, including to verify that something isn’t going to happen. For example, consider testing Gmail’s “undo” send button. After clicking the button, you would want to verify that the RPC to send the email was never sent. We can also verify that there is no pending work. If the test finishes while there is more asynchronous work pending, we don’t want the pending work to continue executing during the next test case. (It’s hopelessly confusing.) The test should either (1) wait for the work to finish, (2) dispose() of the workers explicitly, or (3, least preferred) ask the fake clock to discard pending timers/frames.
- Much less common is to make time progress in specific increments in a unit test. One example might be a toast which appears after a known delay, and disappears after another known delay. This use of mock clocks, however, is not really a separate point from the second. We already have the ability to tick the clock specific amounts of time with timeouts. It’s just slow and mock clocks provide nice APIs to speed it up. Mock clocks can make these specific increments more predictable in tests. When using real timeouts, the ordering can sometimes depend on how quickly each task can be processed.
These are pretty good reasons to use a fake clock, and pretty broadly useful when async code is in play. We do support the idea of installing a fake clock.