Change: Unify `nextTick` in our Jest Vue tests
wrapper.vm.$nextTick() / Vue.nextTick()
to one of the options
Change pattern proposal: 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
wrapper.vm.$nextTick()
everywhere
Proposal 1: Use 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
/shallowMount
of found via.find
- which one should InextTick()
?
- Longer to type :)
- Accessing anything inside
wrapper.vm
feels 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-utils
guidelines -
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 calling
dispatch` - 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 :)
import { nextTick } from 'vue'; nextTick()
everywhere
Proposal 2: Use 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