Change: Unify `nextTick` in our Jest Vue tests
Change pattern proposal: wrapper.vm.$nextTick() / Vue.nextTick() to one of the options
I would like to say thank you to @dmishunov for raising this concern in gitlab-org/gitlab-ui#560 (closed)
This is a broader version of this discussion
Old Pattern
In our codebase there are multiple approaches to managing nextTick:
Vue.nextTick-
wrapper.vm.$nextTick(sometimes looks ugly likevm.vm.$nextTick -
, dead, thanks to @ntepluhina and gitlab-org&2360 (closed)localVue.nextTick
New Pattern
Unify this one across our codebase
Proposal 1: Use wrapper.vm.$nextTick() everywhere
Advantages:
- No extra import of
Vue
Disadvantages:
- Sometimes usage is not obvious
Special thanks for @pslaughter for asking the right questions in the right time.
Sometimes usage of wrapper.vm.$nextTick() is not obvious. For example (from real codebase):
Is it safe to use
wrapper.vm.$nextTick()after callingwrapper.destroy()?
If I have two components (either created by
mount/shallowMountof found via.find- which one should InextTick()?
- Longer to type :)
- Accessing anything inside
wrapper.vmfeels like a code smell for me. Let me explain:
-
wrapper.vm.someState.foo- we should usewrapper.setData()instead -
wrapper.vm.someMethod()- triggering vm methods does not align with our guidelines on testing Vue components and@vue/test-utilsguidelines -
jest.spyOn(wrapper.vm, 'something') - we should treat component as black box, and spy on external activities. For example for vuex-enabled components such activity is callingdispatch` - Testing and accessing computeds is wrong way of testing Vue components - they are implementation details
The only inevitable use-case for wrapper.vm is wrapper.vm.$emit which will not be on the table with Vue3 release, since there will be no difference between trigger & emit.
I would prefer (in the future) to get rid of as many wrapper.vm.something calls as possible :)
Proposal 2: Use import { nextTick } from 'vue'; nextTick() everywhere
First of all, you should know one important thing:
wrapper.vm.$nextTick === Vue.nextTick // true
createLocalVue().nextTick === Vue.nextTick // true
So we're actually always calling the same function :) Also additional import does not add anything (tested) to tests execution time, since (obviously) @vue/test-utils also import Vue under the hood.
Advantages:
- No-brainer! No time to think, just use
nextTick()everywhere - Shorter :)
Disadvantages:
- Extra import in each file.
Summary
Why no "extra utility function" approach on the table? From my point of view, I see 0 benefits compared to nextTick() - still one import, and I really don't want to introduce new things unless really needed.
All the tests I've written were actually wrapper.vm.$nextTick(). But having a large codebase and a big FE department, I really think that we already have too many things to understand & remember - so no-brainer solution like nextTick() really shines for me
Migration effort
- We can easily migrate our entire codebase with codemod (I have them ready)
- ESLint rule for linting yet to be developed, but is pretty trivial to implement
Risks
None
Voting
- use
🚲 emoji for keepingwrapper.vm.nextTick()thing :) - use
🌐 emoji for global solution ofnextTick() - raise your voice in comments if you have other proposals