From 90256103e79bccdfd4a373afa78efe6494cb5b70 Mon Sep 17 00:00:00 2001 From: Jess Date: Tue, 17 Dec 2019 03:10:43 -0500 Subject: [PATCH 1/4] Adding notes about async vs. sync mode. Adding placeholder for mocking transitions section --- docs/guides/common-tips.md | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/docs/guides/common-tips.md b/docs/guides/common-tips.md index 5ac100e84..939d25929 100644 --- a/docs/guides/common-tips.md +++ b/docs/guides/common-tips.md @@ -27,11 +27,11 @@ const wrapper = shallowMount(Component) wrapper.vm // the mounted Vue instance ``` -### Using `nextTick` +### Writing asynchronous tests using `nextTick` (new) -Vue batches watcher updates and runs them asynchronously on the "next tick". +By default, Vue batches updates to run asynchronously (on the next "tick"). This is to prevent unnecessary DOM re-renders, and watcher computations ([see the docs](https://vuejs.org/v2/guide/reactivity.html#Async-Update-Queue) for more details). -In practice, this means you must wait for updates to run after you set a reactive property. You can wait for updates with `Vue.nextTick()`: +This means you **must** wait for updates to run after you set a reactive property. You can wait for updates with `Vue.nextTick()`: ```js it('updates text', async () => { @@ -40,8 +40,23 @@ it('updates text', async () => { await Vue.nextTick() expect(wrapper.text()).toContain('updated') }) + +// Or if you're without async/await +it('render text', (done) => { + const wrapper = mount(TestComponent) + wrapper.trigger('click') + Vue.nextTick(() => { + wrapper.text().toContain('some text') + wrapper.trigger('click') + Vue.nextTick(() => { + wrapper.text().toContain('some different text') + done() + }) + }) +}) ``` + The following methods often cause watcher updates that require you to wait for the next tick: - `setChecked` @@ -160,6 +175,9 @@ You can also update the props of an already-mounted component with the `wrapper. _For a full list of options, please see the [mount options section](../api/options.md) of the docs._ +### Mocking Transitions + + ### Applying Global Plugins and Mixins Some of the components may rely on features injected by a global plugin or mixin, for example `vuex` and `vue-router`. From 05f77209d5f1a7d2192226fdbad29e6a3557dbad Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Tue, 17 Dec 2019 20:03:37 +1000 Subject: [PATCH 2/4] (docs): add notes on mocking transitions and run linter --- docs/guides/common-tips.md | 114 +++++++++++++++++++++++++++++++++---- 1 file changed, 104 insertions(+), 10 deletions(-) diff --git a/docs/guides/common-tips.md b/docs/guides/common-tips.md index 939d25929..6404614d3 100644 --- a/docs/guides/common-tips.md +++ b/docs/guides/common-tips.md @@ -29,7 +29,7 @@ wrapper.vm // the mounted Vue instance ### Writing asynchronous tests using `nextTick` (new) -By default, Vue batches updates to run asynchronously (on the next "tick"). This is to prevent unnecessary DOM re-renders, and watcher computations ([see the docs](https://vuejs.org/v2/guide/reactivity.html#Async-Update-Queue) for more details). +By default, Vue batches updates to run asynchronously (on the next "tick"). This is to prevent unnecessary DOM re-renders, and watcher computations ([see the docs](https://vuejs.org/v2/guide/reactivity.html#Async-Update-Queue) for more details). This means you **must** wait for updates to run after you set a reactive property. You can wait for updates with `Vue.nextTick()`: @@ -42,21 +42,20 @@ it('updates text', async () => { }) // Or if you're without async/await -it('render text', (done) => { - const wrapper = mount(TestComponent) +it('render text', done => { + const wrapper = mount(TestComponent) + wrapper.trigger('click') + Vue.nextTick(() => { + wrapper.text().toContain('some text') wrapper.trigger('click') Vue.nextTick(() => { - wrapper.text().toContain('some text') - wrapper.trigger('click') - Vue.nextTick(() => { - wrapper.text().toContain('some different text') - done() - }) + wrapper.text().toContain('some different text') + done() }) + }) }) ``` - The following methods often cause watcher updates that require you to wait for the next tick: - `setChecked` @@ -177,6 +176,101 @@ _For a full list of options, please see the [mount options section](../api/optio ### Mocking Transitions +Although calling `await Vue.nexTick()` works well for most use cases, there are some situations where additional work arounds are required. These issues will be solved before the library transitions out of beta. One such example is unit testing components with the `` wrapper provided by Vue. + +```vue + + + +``` + +You might want to write a test that verifies that Foo is shown, then when `show` is set to `false`, Foo is no longer rendered. Such a test could be written as follows: + +```js +test('should render Foo, then hide it', async () => { + const wrapper = mount(Foo) + expect(wrapper.text()).toMatch(/Foo/) + + wrapper.setData({ + show: false + }) + await wrapper.vm.$nextTick() + + expect(wrapper.text()).not.toMatch(/Foo/) +}) +``` + +In practice, although we are calling `setData` then waiting for the `nextTick` to ensure the DOM is updated, this test fails. This is an ongoing issue that we would like to solve before version 1.0. For now, there are some work arounds: + +1. Using a `transitionStub` helper + +```js +const transitionStub = () => ({ + render: function(h) { + return this.$options._renderChildren + } +}) + +test('should render Foo, then hide it', async () => { + const wrapper = mount(Foo, { + stubs: { + transition: transitionStub() + } + }) + expect(wrapper.text()).toMatch(/Foo/) + + wrapper.setData({ + show: false + }) + await wrapper.vm.$nextTick() + + expect(wrapper.text()).not.toMatch(/Foo/) +}) +``` + +This overrides the default behavior of the `` component and renders the children as soon as the relevant boolean condition changes, as opposed to applying CSS classes, which is how Vue's `` component works. + +Another alternative is to simply avoid using `setData` by writing two tests, with the required setup performed using `mount` or `shallowMount` options: + +```js +test('should render Foo', async () => { + const wrapper = mount(Foo, { + data() { + return { + show: true + } + } + }) + + expect(wrapper.text()).toMatch(/Foo/) +}) + +test('should not render Foo', async () => { + const wrapper = mount(Foo, { + data() { + return { + show: false + } + } + }) + + expect(wrapper.text()).not.toMatch(/Foo/) +}) +``` ### Applying Global Plugins and Mixins From 5269548326428fc1262825a5d29fc3af2a728feb Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Tue, 17 Dec 2019 20:06:19 +1000 Subject: [PATCH 3/4] (docs): improve guide --- docs/guides/common-tips.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/common-tips.md b/docs/guides/common-tips.md index 6404614d3..ad9ef650b 100644 --- a/docs/guides/common-tips.md +++ b/docs/guides/common-tips.md @@ -214,7 +214,7 @@ test('should render Foo, then hide it', async () => { }) ``` -In practice, although we are calling `setData` then waiting for the `nextTick` to ensure the DOM is updated, this test fails. This is an ongoing issue that we would like to solve before version 1.0. For now, there are some work arounds: +In practice, although we are calling `setData` then waiting for the `nextTick` to ensure the DOM is updated, this test fails. This is an ongoing issue related to show Vue implements the ` component, that we would like to solve before version 1.0. For now, there are some work arounds: 1. Using a `transitionStub` helper From dcfee27cdaf292b00dafe5ce75de1e9aef2e6d5c Mon Sep 17 00:00:00 2001 From: Jess Date: Tue, 17 Dec 2019 19:47:23 -0500 Subject: [PATCH 4/4] (docs): apply feedback and fix typos --- docs/guides/common-tips.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/guides/common-tips.md b/docs/guides/common-tips.md index ad9ef650b..7f4766707 100644 --- a/docs/guides/common-tips.md +++ b/docs/guides/common-tips.md @@ -176,7 +176,7 @@ _For a full list of options, please see the [mount options section](../api/optio ### Mocking Transitions -Although calling `await Vue.nexTick()` works well for most use cases, there are some situations where additional work arounds are required. These issues will be solved before the library transitions out of beta. One such example is unit testing components with the `` wrapper provided by Vue. +Although calling `await Vue.nextTick()` works well for most use cases, there are some situations where additional workarounds are required. These issues will be solved before the `vue-test-utils` library moves out of beta. One such example is unit testing components with the `` wrapper provided by Vue. ```vue