Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add async guide #282

Merged
merged 14 commits into from
Dec 26, 2017
25 changes: 21 additions & 4 deletions docs/en/guides/testing-async-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

To simplify testing, `vue-test-utils` applies updates _synchronously_. However, there are some techniques you need to be aware of when testing a component with asynchronous behavior such as callbacks or promises.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applies updates synchronously

to

applies DOM updates synchronously


One of the most common asynchronous behaviors is API calls and Vuex actions. The following examples shows how to test a method that makes an API call. This example is using Jest to run the test and to mock the HTTP library `axios`.
One of the most common asynchronous behaviors is API calls and Vuex actions. The following examples shows how to test a method that makes an API call. This example uses Jest to run the test and to mock the HTTP library `axios`. More about Jest manual mocks can be found [here](https://facebook.github.io/jest/docs/en/manual-mocks.html#content).

The implementation of the `axios` mock looks like this:

Expand All @@ -23,6 +23,7 @@ The below component makes an API call when a button is clicked, then assigns the

<script>
import axios from 'axios'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a line break after the import statement


export default {
data () {
return {
Expand All @@ -39,6 +40,7 @@ The below component makes an API call when a button is clicked, then assigns the
}
</script>
```

A test can be written like this:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a link to the Jest manual mocks page—https://facebook.github.io/jest/docs/en/manual-mocks.html#content


``` js
Expand All @@ -55,9 +57,24 @@ test('Foo', () => {
})
```

This test currently fails, because the assertion is called before the promise resolves. One solution is to use the npm package, `flush-promises`. which immediately resolve any unresolved promises. This test is also asynchronous, so like the previous example, we need to let the test runner know to wait before making any assertions.
This test currently fails because the assertion is called before the promise in `fetchResults` resolves. Most unit test libraries provide a callback to let the runner know when the test is complete. Jest and Karma both use `done`. We can use `done` in combination with `$nextTick` or `setTimeout` to ensure any promises resolve before the assertion is made.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jest and Karma both use

should be

Jest and Mocha both use


``` js
test('Foo', () => {
it('fetches async when a button is clicked', (done) => {
const wrapper = shallow(Foo)
wrapper.find('button').trigger('click')
wrapper.vm.$nextTick(() => {
expect(wrapper.vm.value).toEqual('value')
done()
})
})
})
```

The reason `$nextTick` or `setTimeout` allow the test to pass is because the microtask queue where promise callbacks are processed run efore the task queue, where `$nextTick` and `setTimeout` are processed. This means by the time the `$nexTick` and `setTimeout` run, any promise callbacks on the microtask queue will have been executed. See [here](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/) for a more detailed explanation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small typo — efore


If you are using Jest, there are a few options, such as passing a `done` callback, as shown above. Another is to prepend the test with the ES7 'async' keyword. We can now use the the ES7 `await` keyword with `flushPromises`, to immediately resolve the API call.
Another solution is to use the npm package, `flush-promises`, which can be used to flush all pending resolved promise handlers, and prepend the test with the ES7 'async' keyword. The ES7 `await` keyword with `flushPromises` can now be used to immediately resolve the API call.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we reword this:

Another solution is to use the npm package, flush-promises, which can be used to flush all pending resolved promise handlers, and prepend the test with the ES7 'async' keyword. The ES7 await keyword with flushPromises can now be used to immediately resolve the API call.

To something like this:

Another solution is to use an async function and the npm package flush-promises. flush-promises flushes all pending resolved promise handlers. You can await the call of flushPromises to flush the promises and improve the readability of your test.


The updated test looks like this:

Expand All @@ -68,7 +85,7 @@ import Foo from './Foo'
jest.mock('axios')

test('Foo', () => {
it('fetches async when a button is clicked', () => {
it('fetches async when a button is clicked', async () => {
const wrapper = shallow(Foo)
wrapper.find('button').trigger('click')
await flushPromises()
Expand Down