vue-test-utils-compat
v0.0.15
Published
Compat layer for @vue/[email protected]
Downloads
411,677
Readme
vue-test-utils-compat
Upgrade your Vue components first, deal with tests later
A migration tool to help you with migration from Vue 2 to Vue3
Vue 3 introduced migration build to help teams with gradual migration. vue-test-utils-next is playing well with migration build, but there are many differences between v1 vue-test-utils and v2.
This package provides a compatibility layer, which allows you to run old v1 test suites on vue-test-utils v2 and Vue 3
Table of Contents
🏁 Compatibility flags
- EXPORT_CREATE_LOCAL_VUE
- EXPORT_CREATE_WRAPPER
- EXPORT_ERROR_WRAPPER
- MOUNT_ARGS_COMPONENTS
- MOUNT_ARGS_CONTEXT_*
- MOUNT_ARGS_DIRECTIVES
- MOUNT_ARGS_LISTENERS
- MOUNT_ARGS_MOCKS
- MOUNT_ARGS_PROVIDE
- MOUNT_ARGS_SCOPED_SLOTS
- MOUNT_ARGS_SCOPED_SLOTS_THIS
- MOUNT_ARGS_STUBS
- WRAPPER_ATTRIBUTES_DISABLED
- WRAPPER_ATTRIBUTES_VALUE
- WRAPPER_ATTRIBUTES_FROM_ATTRS
- WRAPPER_UNWRAP_PROPS
- WRAPPER_UNWRAP_EMITTED
- WRAPPER_DESTROY
- WRAPPER_DO_NOT_INCLUDE_NATIVE_EVENTS_IN_EMITTED
- WRAPPER_DO_NOT_INCLUDE_HOOK_EVENTS_IN_EMITTED
- WRAPPER_FIND_ALL
- WRAPPER_FIND_BY_CSS_SELECTOR_RETURNS_COMPONENTS
- WRAPPER_FIND_COMPONENT_BY_REF_RETURNS_DOM
- WRAPPER_SET_VALUE_DOES_NOT_TRIGGER_CHANGE
- WRAPPER_VUE_SET_VALUE_USES_DOM
- WRAPPER_EXCLUDE_LISTENERS_FROM_PROPS
⚠️ Known issues
⏩ Quickstart
npm install --save-dev vue-test-utils-compat
Vue 3:
const VueTestUtils = require("vue@/test-utils");
const { h } = require("vue");
const { installCompat: installVTUCompat, fullCompatConfig } = require("vue-test-utils-compat");
installVTUCompat(VueTestUtils, fullCompatConfig, h);
Vue 3 migration build (in Vue 2 mode):
const VueTestUtils = require("vue@/test-utils");
const Vue = require("vue");
const { installCompat: installVTUCompat, fullCompatConfig } = require("vue-test-utils-compat");
let compatH;
Vue.createApp({
compatConfig: {
MODE: 3,
RENDER_FUNCTION: "suppress-warning",
},
render(h) {
compatH = h;
},
}).mount(document.createElement("div"));
installVTUCompat(VueTestUtils, fullCompatConfig, compatH);
✔️ Upgrade workflow
This upgrade workflow is demonstrated in bootstrap-vue migration to Vue 3.
- Before you start make sure you are using latest version of
@vue/test-utils
v1 in your project and fix all deprecations reported - Follow Vue3 migration build upgrade workflow to set up Vue build infrastructure [example commit]
- Make sure your test infrastructure uses
@vue/compat
asvue
alias. Example (using jest -jest.config.js
):
module.exports = {
// ...
moduleNameMapper: {
"^vue$": "@vue/compat",
},
// ...
};
Hint: it might be a good idea to set up your environment to use Vue 2 or Vue 3 conditionally. It greatly simplifies the migration process.
- Install
vue-test-utils-compat
. Please take a note that your test environment might reset modules between files (jest
do this), so make sure to do this in the proper place (we're usingsetupFilesAfterEnv
in jest):
const compatH = new Vue({}).$createElement;
installVTUCompat(VTU, fullCompatConfig, compatH);
Run your tests and fix failing ones. Typical failures usually include:
- using private Vue API (like
__vue__
) [example commit] - wrong usage of
find
vs.findComponent
[example commit] - snapshots (they might differ between Vue 2 and Vue 3)
- using private Vue API (like
At this point, you (theoretically) have a green suite and can start working on upgrading your code to Vue 3
Replace
fullCompatConfig
from step 3 with the detailed list of compat flags. You can copy-paste the full list of flags below or take a look at the source code to figure all flags:
const compatConfig = {
EXPORT_CREATE_LOCAL_VUE: true,
EXPORT_CREATE_WRAPPER: true,
GLOBAL_STUBS: true,
MOUNT_ARGS_CONTEXT_ATTRS: true,
MOUNT_ARGS_CONTEXT_CHILDREN: true,
MOUNT_ARGS_CONTEXT_CLASS: true,
MOUNT_ARGS_CONTEXT_ON: true,
MOUNT_ARGS_CONTEXT_PROPS: true,
MOUNT_ARGS_LISTENERS: true,
MOUNT_ARGS_MOCKS: true,
MOUNT_ARGS_PROVIDE: true,
MOUNT_ARGS_SCOPED_SLOTS: true,
MOUNT_ARGS_SCOPED_SLOTS_THIS: true,
MOUNT_ARGS_STUBS: true,
WRAPPER_ATTRIBUTES_DISABLED: true,
WRAPPER_ATTRIBUTES_VALUE: true,
WRAPPER_DESTROY: true,
WRAPPER_DO_NOT_INCLUDE_NATIVE_EVENTS_IN_EMITTED: true,
WRAPPER_FIND_ALL: true,
};
- 🔁 Turn off one compatibility flag. Fix failing tests. Repeat.
- As soon as you turn off the last compatibility flag - throw away and uninstall this package. You are awesome! 🎉
🌐 Global API
installCompat(VueTestUtilsModule, compatConfig, vueH)
VueTestUtilsModule
- module, which will be patchedcompatConfig: Record<string, boolean>
- list of compatibility flagsvueH
- function which will be used to create Vue VNodes. Required only ifMOUNT_ARGS_SCOPED_SLOTS_THIS
compatibility flag is used, could be omitted otherwise
compatFlags
- object with all available compatibilityfullCompatConfig
- config object with all compatibility flags enabled
🏁 Compatibility flags
Tests cover all compatibility flags. If the flag description is unclear, check the relevant test in tests
folder.
EXPORT_CREATE_LOCAL_VUE
Adds createLocalVue
to @vue/test-utils
module and support for { localVue }
mount option.
⚠️
localVue
provides.extend
, which is no-op operation. It is sufficient for most of the code but might require special handling
➡️ Migration strategy: available in @vue/test-utils v2 docs
EXPORT_CREATE_WRAPPER
Adds createWrapper
to @vue/test-utils
module
➡️ Migration strategy: replace createWrapper
with new DOMWrapper()
, new VueWrapper()
which are available as exports in @vue/test-utils
v2
EXPORT_ERROR_WRAPPER (added in v0.0.11)
Adds ErrorWrapper
class to @vue/test-utils
module
➡️ Migration strategy: replace new ErrorWrapper()
calls to createWrapperError
MOUNT_ARGS_COMPONENTS (added in v0.0.3)
Enable support for components
field in mount
args of @vue/test-utils
➡️ Migration strategy: Move components
mount arg to global.components
MOUNT_ARGS_CONTEXT_*
Flags:
MOUNT_ARGS_CONTEXT_ATTRS
MOUNT_ARGS_CONTEXT_CHILDREN
MOUNT_ARGS_CONTEXT_CLASS
MOUNT_ARGS_CONTEXT_ON
MOUNT_ARGS_CONTEXT_PROPS
Enable support for context
field in mount
args of @vue/test-utils
(used to test functional components)
⚠️
MOUNT_ARGS_CONTEXT_CHILDREN
convertscontext.children
to the default slot of the component. It is not a complete implementation of oldcontext.children
behavior but should be sufficient for most cases.
➡️ Migration strategy: rewrite your mount args as follows:
context.props
,context.attrs
, andcontext.class
go directly toprops
children
are replaced withslots.default
context.on
become correspondingprops
: (click
→onClick
, etc.)
MOUNT_ARGS_DIRECTIVES (added in v0.0.3)
Enable support for components
field in mount
args of @vue/test-utils
➡️ Migration strategy: Move directives
mount arg to global.directives
MOUNT_ARGS_LISTENERS
Allow passing { listeners }
field in mount
arguments
➡️ Migration strategy: replace listeners
with props
: (click
→ onClick
, etc.)
MOUNT_ARGS_MOCKS
Enable passing mocks
to the component from mount
arguments
➡️ Migration strategy: move mocks
mount arg to global.mocks
MOUNT_ARGS_PROVIDE
Allow passing relevant provide
to the component
⚠️
@vue/test-utils
v2 does not support passingprovide
as function. It means that yourprovide()
function might be invoked earlier than you think
➡️ Migration strategy: move provide
mount arg to global.provide
. If your provide
is a function - replace it with an object.
MOUNT_ARGS_SCOPED_SLOTS
Enable scopedSlots
support in mount args
➡️ Migration strategy: merge scopedSlots
mount arg to slots
. If your scoped slot is using raw string - wrap it with <template #default="props">${your string here}</template>
MOUNT_ARGS_SCOPED_SLOTS_THIS
Allows scopedSlots
declared as functions to receive this
which contains $createElement
and $set
⚠️⚠️⚠️ Requires
MOUNT_ARGS_SCOPED_SLOTS
to be enabled and third argument (vueH
) a forinstallCompat
call
️⚠️
$createElement
provided by this flag is not context-aware and will not be able to render components as a string. Refer to Vue docs for details
➡️ Migration strategy: ❌ rewrite such slots in your tests
MOUNT_ARGS_STUBS
Enable stubs
to be passed to mount arguments
➡️ Migration strategy: move stubs
mount arg to global.stubs
WRAPPER_ATTRIBUTES_DISABLED
Adds special handling when retrieving the disabled
attribute on wrapper
. Previously Vue always normalized such values (Vue 3 migration guide has more details on this)
➡️ Migration strategy: update your .attributes("disabled")
assertions to relevant values
WRAPPER_ATTRIBUTES_VALUE
Adds special handling when retrieving the value
attribute on wrapper
. Previously Vue always set value
as DOM node attribute, which is no more the case
➡️ Migration strategy: ❌ rewrite your value retrieval in another way
WRAPPER_ATTRIBUTES_FROM_ATTRS (added in v0.0.12)
Add $attrs
lookup when looking for .attributes('something')
call. Previously test-utils were looking into $attrs, now only attributes of root element are considered
➡️ Migration strategy: ❌ rewrite your value retrieval in another way
WRAPPER_UNWRAP_PROPS (added in v0.0.11)
Unwraps props from reactive()
container to allow strict checks like .toBe
pass
➡️ Migration strategy: when asserting props of the component use relaxed check (like .toStrictEqual
) instead strict ===
equality
WRAPPER_UNWRAP_EMITTED (added in v0.0.12)
Unwraps emitted objects to allow strict checks like .toBe
pass
➡️ Migration strategy: when asserting emitted() of the component use relaxed check (like .toStrictEqual
) instead strict ===
equality
WRAPPER_DESTROY
Enables wrapper.destroy
calls and enableAutoDestroy
calls
➡️ Migration strategy: replace all wrapper.destroy
calls with wrapper.unmount
and enableAutoDestroy
with `enableAutoUnmount
WRAPPER_DO_NOT_INCLUDE_NATIVE_EVENTS_IN_EMITTED
Makes sure that native events will not be captured in .emitted()
➡️ Migration strategy: rewrite your event-related assertions to take into account that native events are also captured, or (preferred) use emits option on your components
WRAPPER_DO_NOT_INCLUDE_HOOK_EVENTS_IN_EMITTED (added in v0.0.3)
Makes sure that hook:
events (which happen when using @vue/compat
) will not be captured in .emitted()
➡️ Migration strategy: rewrite your event-related assertions to take into account that such events are also captured, or just upgrade to Vue 3 build without compat
WRAPPER_FIND_ALL
Implements old behavior of .findAll
/ .findAllComponents
when results were wrapped with special object with .wrappers
field and various methods (.at
, .filter
, .trigger
, etc.)
➡️ Migration strategy: rewrite your tests, assuming that .findAll
and .findAllComponents
return a simple array instead
WRAPPER_FIND_BY_CSS_SELECTOR_RETURNS_COMPONENTS (added in v0.0.2)
Implements old behavior of .find
/ .findAll
when results will be Vue components if they matches. So potentially, you can receive mixed array of DOM/Vue wrappers when using .findAll
with this compat flag
➡️ Migration strategy: replace .find
with .findComponent
and .findAll
with .findAllComponents
where appropriate. Please take a note that if your tests rely on having a mixed array of DOM/Vue wrappers - you need to rewrite them
WRAPPER_FIND_COMPONENT_BY_REF_RETURNS_DOM (added in v0.0.3)
Implements old behavior when using .findComponent
with ref
will return DOM wrapper if ref is pointing to one.
➡️ Migration strategy: replace .findComponent
with .find
by ref (when https://github.com/vuejs/vue-test-utils-next/pull/1110 will be merged)
WRAPPER_SET_VALUE_DOES_NOT_TRIGGER_CHANGE (added in v0.0.3)
Implements old behavior when using .trigger
on DOM Wrapper did not trigger change
event, so you should trigger it manually (important for lazy v-models)
➡️ Migration strategy: rewrite relevant tests
WRAPPER_VUE_SET_VALUE_USES_DOM (added in v0.0.3)
Implements old VTU v1 behavior when using .setValue
on Vue component actually used same logic, as setting value on DOM node (checking element type of Vue component, etc.)
➡️ Migration strategy: fix your components to use new setValue
(which respects v-model
) or rewrite relevant tests
WRAPPER_EXCLUDE_LISTENERS_FROM_PROPS (added in v0.0.14)
Removes all props starting with on
from .props()
call to hide attached event listeners
➡️ Migration strategy: fix your tests not to rely on exact list of props returned by .props()
Known issues
This package monkey-patches @vue/test-utils
package. Depending on your setup this might not work (for example you are using real imports). In that case you can create a mutable wrapper around VTU and replace all your imports from @vue/test-utils
to this helper module:
import * as VueTestUtils from '@vue/test-utils';
import { h } from 'vue';
import { installCompat, fullCompatConfig } from 'vue-test-utils-compat'
const PatchedVTU = { ...VueTestUtils };
installCompat(PatchedVTU, fullCompatConfig, h);
export PatchedVTU;