8000 Time travelling and testing setTimeout section · mcibique/vue-testing-examples@b08d641 · GitHub
[go: up one dir, main page]

Skip to content

Commit b08d641

Browse files
committed
Time travelling and testing setTimeout section
1 parent 24fa8ea commit b08d641

File tree

1 file changed

+15
-14
lines changed

1 file changed

+15
-14
lines changed

README.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,7 @@ it('should navigate to new url', function () {
868868

869869
## Time travelling and testing setTimeout
870870

871-
There are several ways how to test `setTimeout` functions in your code. For all solutions, we are going to use LoginView component which displays some helpful links after 5s. Please don't judge the UX, it's for demonstration purposes:
871+
There are several ways on how to test `setTimeout` functions in your code. For all of them, we are going to use the LoginView component which displays some helpful links after 5s. Please don't judge the UX, it's for demonstration purposes:
872872

873873
```js
874874
class LoginView extends Vue {
@@ -884,11 +884,11 @@ class LoginView extends Vue {
884884

885885
What we need to test:
886886

887-
1. The initial status of the component (displaying help links should be off)
888-
2. Time travel to 2s after the component was created (check help links are still not being displayed)
889-
3. Time travel beyond 5s after the component was created (check help links are finally being displayed)
887+
1. The initial status of the component (displaying help links should be false)
888+
2. Time travel to 2s after the component was created (check if help links are still not being displayed)
889+
3. Time travel beyond 5s after the component was created (check if help links are being displayed)
890890

891-
Let's start with easiest, but not very robust test solution:
891+
Let's start with the easiest, but not very robust test solution:
892892

893893
```js
894894
import { expect } from 'chai';
@@ -904,29 +904,29 @@ afterEach(function () {
904904
});
905905

906906
it('should not display help links when a component was just created', function () {
907-
let wrapper = mount(LoginView);
907+
const wrapper = mount(LoginView);
908908
expect(wrapper.vm.displayHelp).to.be.false;
909909
});
910910

911911
it('should display help links only after 5s', function () {
912-
let wrapper = mount(LoginView);
912+
const wrapper = mount(LoginView);
913913
expect(window.setTimeout).to.have.been.calledWith(sinon.match.any, 5000);
914914
});
915915
```
916916

917-
Simple, huh? Yes, it technically does test what was specified, but it's not very convincing. We did lots of shortcuts and we actually never checked whether `displayHelp` became true or not. The callback in `setTimeout` is part of the component's logic but it wasn't called at all. What if there is a logic somewhere in the code canceling the timeout? We also cannot check what is the state after 2s. Let's add a little more logic to our test:
917+
Simple, huh? Yes, it technically does test what was specified, but it's not very convincing. We did lots of shortcuts and we actually never checked whether `displayHelp` became true or not. The callback in `setTimeout` is part of the component's logic but it wasn't called at all. What if there is a logic somewhere in the code canceling the timeout? Besides we can't check what is the state after 2s. Let's add a little more logic to our test:
918918

919919
```js
920920
it('should display help links only after 5s', function () {
921921
window.setTimeout = sinon.stub().callsFake(fn => fn()); // any function that is passed to setTimeout is immediately executed
922922

923-
let wrapper = mount(LoginView);
923+
const wrapper = mount(LoginView);
924924
expect(window.setTimeout).to.have.been.calledWith(sinon.match.any, 5000);
925925
expect(wrapper.vm.displayHelp).to.be.true;
926926
});
927927
```
928928

929-
This time callback is executed and our flag is set to true, but we created another problem. The callback is executed synchronously instead. That changes the order of execution which means we are not testing how code runs in production. And we still cannot test a state of our component after 2s and we are still unsure about timeout cancellation. Let's involve library which was built-in for this and has better control over `setTimeout` and it's execution: [lolex](https://github.com/sinonjs/lolex). Lolex has an API which can mock `setTimeout` and allows us to jump in time by 100ms, by 1s, by 1 day while our test is still executing a synchronous way (that means the test execution is not paused for 2s).
929+
This time the callback is executed and our flag is set to true, but we created another problem. The callback is executed synchronously instead. That changes the order of execution which means we are not testing how code runs in production. And we still cannot test a state of our component after 2s and we are still unsure about timeout cancellation. Let's involve a library that was built-in for this and has a better control over `setTimeout` and it's execution: [lolex](https://github.com/sinonjs/lolex). Lolex has an API which can mock `setTimeout` and allow us to jump in time by 100ms, by 1s, by 1 day while our test is executing (that means the test execution is not paused for 2s).
930930

931931
```js
932932
import { expect } from 'chai';
@@ -941,12 +941,12 @@ afterEach(function () {
941941
});
942942

943943
it('should not display help links when a component was just created', function () {
944-
let wrapper = mount(LoginView);
944+
const wrapper = mount(LoginView);
945945
expect(wrapper.vm.displayHelp).to.be.false;
946946
});
947947

948948
it('should not display help links before 5s elapsed', function () {
949-
let wrapper = mount(LoginView);
949+
const wrapper = mount(LoginView);
950950

951951
this.clock.tick(2000);
952952
expect(wrapper.vm.displayHelp).to.be.false;
@@ -959,7 +959,8 @@ it('should not display help links before 5s elapsed', function () {
959959
});
960960
```
961961

962-
It's looking really nice now. The clock was able to move our test 2s ahead, checked the state, moved another 2s, checked, moved another 2s and did a final check. The callback was executed after multiple calls to `this.clock.tick()` and not synchronously during `created()` lifecycle event. Lolex also supports mocking of other global functions manipulating time, see their [API reference](https://github.com/sinonjs/lolex#api-reference).
962+
It's looking really nice now. The clock was able to move our test 2s ahead, checked the state, moved another 2s, checked, moved another 2s and did a final check. The callback was executed after multiple calls to `this.clock.tick()` and not synchronously during `created()` lifecycle event. Lolex also supports mocking other functions that manipulate time, see their [API reference](https://github.com/sinonjs/lolex#api-reference) for more information.
963+
963964
Lolex is also capable to work with mocked global objects. Let's consider a scenario from [Mocking global objects](#mocking-global-objects):
964965

965966
```js
@@ -971,7 +972,7 @@ import container { WINDOW_ID } from './di';
971972
beforeEach(function () {
972973
container.snapshot();
973974

974-
let windowMock = {};
975+
const windowMock = {};
975976
this.clock = lolex.install({ target: windowMock, toFake: ['setTimeout', 'clearTimeout'] }); // only fake timeout methods, don't waste time on other functions
976977
container.rebind(WINDOW_ID).toConstantValue(windowMock);
977978
});

0 commit comments

Comments
 (0)
0