1
- /* eslint-disable testing-library/no-wait-for-empty-callback */
2
- import { mount } from '@vue/test-utils'
3
-
4
- import {
5
- getQueriesForElement ,
6
- prettyDOM ,
7
- waitFor ,
8
- fireEvent as dtlFireEvent ,
9
- } from '@testing-library/dom'
10
-
11
- const mountedWrappers = new Set ( )
12
-
13
- function render (
14
- Component ,
15
- {
16
- store = null ,
17
- routes = null ,
18
- container : customContainer ,
19
- baseElement : customBaseElement ,
20
- ...mountOptions
21
- } = { } ,
22
- ) {
23
- const div = document . createElement ( 'div' )
24
- const baseElement = customBaseElement || customContainer || document . body
25
- const container = customContainer || baseElement . appendChild ( div )
26
-
27
- const plugins = mountOptions . global ?. plugins || [ ]
28
-
29
- if ( store ) {
30
- const { createStore} = require ( 'vuex' )
31
- plugins . push ( createStore ( store ) )
32
- }
33
-
34
- if ( routes ) {
35
- const requiredRouter = require ( 'vue-router' )
36
- const { createRouter, createWebHistory} =
37
- requiredRouter . default || requiredRouter
38
-
39
- const routerPlugin = createRouter ( { history : createWebHistory ( ) , routes} )
40
- plugins . push ( routerPlugin )
41
- }
42
-
43
- const wrapper = mount ( Component , {
44
- ...mountOptions ,
45
- attachTo : container ,
46
- global : { ...mountOptions . global , plugins} ,
47
- } )
48
-
49
- // this removes the additional "data-v-app" div node from VTU:
50
- // https://github.com/vuejs/vue-test-utils-next/blob/master/src/mount.ts#L196-L213
51
- unwrapNode ( wrapper . parentElement )
52
-
53
- mountedWrappers . add ( wrapper )
54
-
55
- return {
56
- container,
57
- baseElement,
58
- debug : ( el = baseElement , maxLength , options ) =>
59
- Array . isArray ( el )
60
- ? el . forEach ( e => console . log ( prettyDOM ( e , maxLength , options ) ) )
61
- : console . log ( prettyDOM ( el , maxLength , options ) ) ,
62
- unmount : ( ) => wrapper . unmount ( ) ,
63
- html : ( ) => wrapper . html ( ) ,
64
- emitted : ( ) => wrapper . emitted ( ) ,
65
- rerender : props => wrapper . setProps ( props ) ,
66
- ...getQueriesForElement ( baseElement ) ,
67
- }
68
- }
69
-
70
- function unwrapNode ( node ) {
71
- node . replaceWith ( ...node . childNodes )
72
- }
73
-
74
- function cleanup ( ) {
75
- mountedWrappers . forEach ( cleanupAtWrapper )
76
- }
77
-
78
- function cleanupAtWrapper ( wrapper ) {
79
- if (
80
- wrapper . element . parentNode &&
81
- wrapper . element . parentNode . parentNode === document . body
82
- ) {
83
- document . body . removeChild ( wrapper . element . parentNode )
84
- }
85
-
86
- wrapper . unmount ( )
87
- mountedWrappers . delete ( wrapper )
88
- }
89
-
90
- // Vue Testing Library's version of fireEvent will call DOM Testing Library's
91
- // version of fireEvent plus wait for one tick of the event loop to allow Vue
92
- // to asynchronously handle the event.
93
- // More info: https://vuejs.org/v2/guide/reactivity.html#Async-Update-Queue
94
- async function fireEvent ( ...args ) {
95
- dtlFireEvent ( ...args )
96
- await waitFor ( ( ) => { } )
97
- }
98
-
99
- function suggestUpdateIfNecessary ( eventValue , eventKey ) {
100
- const changeOrInputEventCalledDirectly =
101
- eventValue && ( eventKey === 'change' || eventKey === 'input' )
102
-
103
- if ( changeOrInputEventCalledDirectly ) {
104
- console . warn (
105
- `Using fireEvent.${ eventKey } () may lead to unexpected results. Please use fireEvent.update() instead.` ,
106
- )
107
- }
108
- }
109
-
110
- Object . keys ( dtlFireEvent ) . forEach ( key => {
111
- fireEvent [ key ] = async ( ...args ) => {
112
- suggestUpdateIfNecessary ( args [ 1 ] , key )
113
- dtlFireEvent [ key ] ( ...args )
114
- await waitFor ( ( ) => { } )
115
- }
116
- } )
117
-
118
- fireEvent . touch = async elem => {
119
- await fireEvent . focus ( elem )
120
- await fireEvent . blur ( elem )
121
- }
122
-
123
- // Small utility to provide a better experience when working with v-model.
124
- // Related upstream issue: https://github.com/vuejs/vue-test-utils/issues/345#issuecomment-380588199
125
- // Examples: https://github.com/testing-library/vue-testing-library/blob/master/src/__tests__/form.js
126
- fireEvent . update = ( elem , value ) => {
127
- const tagName = elem . tagName
128
- const type = elem . type
129
-
130
- switch ( tagName ) {
131
- case 'OPTION' : {
132
- elem . selected = true
133
-
134
- const parentSelectElement =
135
- elem . parentElement . tagName === 'OPTGROUP'
136
- ? elem . parentElement . parentElement
137
- : elem . parentElement
138
-
139
- return fireEvent . change ( parentSelectElement )
140
- }
141
-
142
- case 'INPUT' : {
143
- if ( [ 'checkbox' , 'radio' ] . includes ( type ) ) {
144
- elem . checked = true
145
- return fireEvent . change ( elem )
146
- } else if ( type === 'file' ) {
147
- return fireEvent . change ( elem )
148
- } else {
149
- elem . value = value
150
- return fireEvent . input ( elem )
151
- }
152
- }
153
-
154
- case 'TEXTAREA' : {
155
- elem . value = value
156
- return fireEvent . input ( elem )
157
- }
158
-
159
- case 'SELECT' : {
160
- elem . value = value
161
- return fireEvent . change ( elem )
162
- }
163
-
164
- default :
165
- // do nothing
166
- }
167
-
168
- return null
169
- }
1
+ import { cleanup } from './render'
170
2
171
3
// If we're running in a test runner that supports afterEach then we'll
172
- // automatically run cleanup after each test. This ensures that tests run in
173
- // isolation from each other.
4
+ // automatically run cleanup after each test.
5
+ // This ensures that tests run in isolation from each other.
174
6
// If you don't like this, set the VTL_SKIP_AUTO_CLEANUP variable to 'true'.
175
7
if ( typeof afterEach === 'function' && ! process . env . VTL_SKIP_AUTO_CLEANUP ) {
176
8
afterEach ( ( ) => {
@@ -179,4 +11,5 @@ if (typeof afterEach === 'function' && !process.env.VTL_SKIP_AUTO_CLEANUP) {
179
11
}
180
12
181
13
export * from '@testing-library/dom'
182
- export { cleanup , render , fireEvent }
14
+ export { cleanup , render } from './render'
15
+ export { fireEvent } from './fire-event'
0 commit comments