Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f462051

Browse files
authored
Merge pull request #75 from testing-library/immutable-fireevent
Use and expose a local copy of fireEvent
2 parents 0e2aa0a + c6a231f commit f462051

File tree

3 files changed

+201
-7
lines changed

3 files changed

+201
-7
lines changed

‎src/vue-testing-library.js

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
getQueriesForElement,
55
logDOM,
66
wait,
7-
fireEvent
7+
fireEventasdtlFireEvent
88
} from '@testing-library/dom'
99

1010
const mountedWrappers = new Set()
@@ -91,10 +91,18 @@ function cleanupAtWrapper(wrapper) {
9191
mountedWrappers.delete(wrapper)
9292
}
9393

94-
Object.keys(fireEvent).forEach(fn => {
95-
fireEvent[`_${fn}`] = fireEvent[fn]
96-
fireEvent[fn] = async (...params) => {
97-
fireEvent[`_${fn}`](...params)
94+
// Vue Testing Library's version of fireEvent will call DOM Testing Library's
95+
// version of fireEvent plus wait for one tick of the event loop to allow Vue
96+
// to asynchronously handle the event.
97+
// More info: https://vuejs.org/v2/guide/reactivity.html#Async-Update-Queue
98+
async function fireEvent(...args) {
99+
dtlFireEvent(...args)
100+
await wait()
101+
}
102+
103+
Object.keys(dtlFireEvent).forEach(key => {
104+
fireEvent[key] = async (...args) => {
105+
dtlFireEvent[key](...args)
98106
await wait()
99107
}
100108
})
@@ -104,6 +112,9 @@ fireEvent.touch = async elem => {
104112
await fireEvent.blur(elem)
105113
}
106114

115+
// Small utility to provide a better experience when working with v-model.
116+
// Related upstream issue: https://github.com/vuejs/vue-test-utils/issues/345#issuecomment-380588199
117+
// Examples: https://github.com/testing-library/vue-testing-library/blob/master/tests/__tests__/form.js
107118
fireEvent.update = async (elem, value) => {
108119
const tagName = elem.tagName
109120
const type = elem.type
@@ -143,4 +154,4 @@ fireEvent.update = async (elem, value) => {
143154
}
144155

145156
export * from '@testing-library/dom'
146-
export { cleanup, render }
157+
export { cleanup, render,fireEvent }

‎tests/__tests__/components/Button.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export default {
77
props: {
88
text: {
99
type: String,
10-
required:true
10+
default:'Button Text'
1111
}
1212
},
1313
methods: {

‎tests/__tests__/fire-event.js

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import { render, fireEvent } from '@testing-library/vue'
2+
import Button from './components/Button'
3+
4+
const eventTypes = [
5+
{
6+
type: 'Clipboard',
7+
events: ['copy', 'paste']
8+
},
9+
{
10+
type: 'Composition',
11+
events: ['compositionEnd', 'compositionStart', 'compositionUpdate']
12+
},
13+
{
14+
type: 'Keyboard',
15+
events: ['keyDown', 'keyPress', 'keyUp'],
16+
init: { keyCode: 13 }
17+
},
18+
{
19+
type: 'Focus',
20+
events: ['focus', 'blur']
21+
},
22+
{
23+
type: 'Form',
24+
events: ['focus', 'blur']
25+
},
26+
{
27+
type: 'Focus',
28+
events: ['input', 'invalid']
29+
},
30+
{
31+
type: 'Focus',
32+
events: ['submit'],
33+
elementType: 'form'
34+
},
35+
{
36+
type: 'Mouse',
37+
events: [
38+
'click',
39+
'contextMenu',
40+
'drag',
41+
'dragEnd',
42+
'dragEnter',
43+
'dragExit',
44+
'dragLeave',
45+
'dragOver',
46+
'dragStart',
47+
'drop',
48+
'mouseDown',
49+
'mouseEnter',
50+
'mouseLeave',
51+
'mouseMove',
52+
'mouseOut',
53+
'mouseOver',
54+
'mouseUp'
55+
],
56+
elementType: 'button'
57+
},
58+
{
59+
type: 'Selection',
60+
events: ['select']
61+
},
62+
{
63+
type: 'Touch',
64+
events: ['touchCancel', 'touchEnd', 'touchMove', 'touchStart'],
65+
elementType: 'button'
66+
},
67+
{
68+
type: 'UI',
69+
events: ['scroll'],
70+
elementType: 'div'
71+
},
72+
{
73+
type: 'Wheel',
74+
events: ['wheel'],
75+
elementType: 'div'
76+
},
77+
{
78+
type: 'Media',
79+
events: [
80+
'abort',
81+
'canPlay',
82+
'canPlayThrough',
83+
'durationChange',
84+
'emptied',
85+
'encrypted',
86+
'ended',
87+
'error',
88+
'loadedData',
89+
'loadedMetadata',
90+
'loadStart',
91+
'pause',
92+
'play',
93+
'playing',
94+
'progress',
95+
'rateChange',
96+
'seeked',
97+
'seeking',
98+
'stalled',
99+
'suspend',
100+
'timeUpdate',
101+
'volumeChange',
102+
'waiting'
103+
],
104+
elementType: 'video'
105+
},
106+
{
107+
type: 'Image',
108+
events: ['load', 'error'],
109+
elementType: 'img'
110+
},
111+
{
112+
type: 'Animation',
113+
events: ['animationStart', 'animationEnd', 'animationIteration'],
114+
elementType: 'div'
115+
},
116+
{
117+
type: 'Transition',
118+
events: ['transitionEnd'],
119+
elementType: 'div'
120+
}
121+
]
122+
123+
// For each event type, we assert that the right events are being triggered
124+
// when the associated fireEvent method is called.
125+
eventTypes.forEach(({ type, events, elementType = 'input', init }) => {
126+
describe(`${type} Events`, () => {
127+
events.forEach(eventName => {
128+
it(`triggers ${eventName}`, async () => {
129+
const testId = `${type}-${eventName}`
130+
const spy = jest.fn()
131+
132+
// Render an element with a listener of the event under testing and a
133+
// test-id attribute, so that we can get the DOM node afterwards.
134+
const { getByTestId } = render({
135+
render(h) {
136+
return h(elementType, {
137+
on: {
138+
[eventName.toLowerCase()]: spy
139+
},
140+
attrs: {
141+
'data-testid': testId
142+
}
143+
})
144+
}
145+
})
146+
147+
const elem = getByTestId(testId)
148+
149+
await fireEvent[eventName](elem, init)
150+
expect(spy).toHaveBeenCalledTimes(1)
151+
})
152+
})
153+
})
154+
})
155+
156+
// The event is called `dblclick`, but fireEvent exposes a "doubleClick" method
157+
test('triggers dblclick on doubleClick', async () => {
158+
const spy = jest.fn()
159+
160+
const { getByRole } = render({
161+
render(h) {
162+
return h('input', {
163+
on: { dblclick: spy }
164+
})
165+
}
166+
})
167+
168+
const elem = getByRole('textbox')
169+
170+
await fireEvent.doubleClick(elem)
171+
expect(spy).toHaveBeenCalledTimes(1)
172+
})
173+
174+
// fireEvent(node, event) is also a valid API
175+
test('calling `fireEvent` directly works too', async () => {
176+
const { getByRole, emitted } = render(Button)
177+
178+
const button = getByRole('button')
179+
180+
await fireEvent(button, new Event('click'))
181+
182+
expect(emitted()).toHaveProperty('click')
183+
})

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /