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 8871d2f

Browse files
authored
feat: Warn using fireEvent.input() or .change() and suggest fireEvent.update() (#166)
* Add warning message to fireEvent input and change when called directly #83 * Add user event test case * Reword warning message to include used event key * Fix template literal for warning messages
1 parent 04932ce commit 8871d2f

File tree

6 files changed

+189
-73
lines changed

6 files changed

+189
-73
lines changed

‎package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"@babel/plugin-transform-runtime": "^7.11.5",
5252
"@testing-library/jest-dom": "^5.11.6",
5353
"@types/estree": "0.0.45",
54+
"@testing-library/user-event": "^12.1.10",
5455
"apollo-boost": "^0.4.9",
5556
"apollo-cache-inmemory": "^1.6.6",
5657
"axios": "^0.20.0",

‎src/__tests__/components/Form.vue

Lines changed: 73 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,73 @@
1-
<template>
2-
<div>
3-
<h1>Movie Review</h1>
4-
<form @submit.prevent="submit">
5-
<label for="movie-input">Title of the movie</label>
6-
<input id="movie-input" v-model="title" name="title" />
7-
8-
<label id="review-textarea">Your review</label>
9-
<textarea
10-
v-model="review"
11-
name="review-textarea"
12-
placeholder="Write an awesome review"
13-
aria-labelledby="review-textarea"
14-
/>
15-
16-
<label>
17-
<input v-model="rating" type="radio" value="3" />
18-
Wonderful
19-
</label>
20-
<label>
21-
<input v-model="rating" type="radio" value="2" />
22-
Average
23-
</label>
24-
<label>
25-
<input v-model="rating" type="radio" value="1" />
26-
Awful
27-
</label>
28-
29-
<label id="recommend-label">Would you recommend this movie?</label>
30-
<input
31-
id="recommend"
32-
v-model="recommend"
33-
type="checkbox"
34-
name="recommend"
35-
/>
36-
37-
<button:disabled="submitDisabled"type="submit">
38-
Submit
39-
</button>
40-
</form>
41-
</div>
42-
</template>
43-
44-
<script>
45-
export default {
46-
data() {
47-
return {
48-
title: '',
49-
review: '',
50-
rating: '1',
51-
recommend: false,
52-
}
53-
},
54-
computed: {
55-
submitDisabled() {
56-
return !this.title || !this.review
57-
},
58-
},
59-
60-
methods: {
61-
submit() {
62-
if (this.submitDisabled) return
63-
64-
this.$emit('submit', {
65-
title: this.title,
66-
review: this.review,
67-
rating: this.rating,
68-
recommend: this.recommend,
69-
})
70-
},
71-
},
72-
}
73-
</script>
1+
<template>
2+
<div>
3+
<h1>Movie Review</h1>
4+
<form @submit.prevent="submit">
5+
<label for="movie-input">Title of the movie</label>
6+
<input id="movie-input" v-model="title" name="title" />
7+
8+
<label id="review-textarea">Your review</label>
9+
<textarea
10+
v-model="review"
11+
name="review-textarea"
12+
placeholder="Write an awesome review"
13+
aria-labelledby="review-textarea"
14+
/>
15+
16+
<label>
17+
<input v-model="rating" type="radio" value="3" />
18+
Wonderful
19+
</label>
20+
<label>
21+
<input v-model="rating" type="radio" value="2" />
22+
Average
23+
</label>
24+
<label>
25+
<input v-model="rating" type="radio" value="1" />
26+
Awful
27+
</label>
28+
29+
<label id="recommend-label"for="recommend">
30+
Would you recommend this movie?
31+
</label>
32+
<input
33+
id="recommend"
34+
v-model="recommend"
35+
type="checkbox"
36+
name="recommend"
37+
/>
38+
39+
<button:disabled="submitDisabled"type="submit">Submit</button>
40+
</form>
41+
</div>
42+
</template>
43+
44+
<script>
45+
export default {
46+
data() {
47+
return {
48+
title: '',
49+
review: '',
50+
rating: '1',
51+
recommend: false,
52+
}
53+
},
54+
computed: {
55+
submitDisabled() {
56+
return !this.title || !this.review
57+
},
58+
},
59+
60+
methods: {
61+
submit() {
62+
if (this.submitDisabled) return
63+
64+
this.$emit('submit', {
65+
title: this.title,
66+
review: this.review,
67+
rating: this.rating,
68+
recommend: this.recommend,
69+
})
70+
},
71+
},
72+
}
73+
</script>

‎src/__tests__/fire-event.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,13 @@ const eventTypes = [
119119
elementType: 'div',
120120
},
121121
]
122+
beforeEach(() => {
123+
jest.spyOn(console, 'warn').mockImplementation(() => {})
124+
})
125+
126+
afterEach(() => {
127+
console.warn.mockRestore()
128+
})
122129

123130
// For each event type, we assert that the right events are being triggered
124131
// when the associated fireEvent method is called.
@@ -181,6 +188,32 @@ test('calling `fireEvent` directly works too', async () => {
181188

182189
expect(emitted()).toHaveProperty('click')
183190
})
191+
const typingEvents = ['input', 'change']
192+
typingEvents.forEach(event => {
193+
test(`fireEvent.${event} prints a warning message to use fireEvent.update instead`, async () => {
194+
const {getByTestId} = render({
195+
template: `<input type="text" data-testid=test-${event}></input>`,
196+
})
197+
198+
await fireEvent[event](getByTestId(`test-${event}`), 'hello')
199+
200+
expect(console.warn).toHaveBeenCalledTimes(1)
201+
expect(console.warn).toHaveBeenCalledWith(
202+
expect.stringContaining(
203+
`Using "fireEvent.${event} may lead to unexpected results. Please use fireEvent.update() instead.`,
204+
),
205+
)
206+
})
207+
})
208+
test('fireEvent.update does not trigger warning messages', async () => {
209+
const {getByTestId} = render({
210+
template: `<input type="text" data-testid=test-update></input>`,
211+
})
212+
213+
await fireEvent.update(getByTestId('test-update'), 'hello')
214+
215+
expect(console.warn).not.toHaveBeenCalled()
216+
})
184217

185218
test('fireEvent.update does not crash if non-input element is passed in', async () => {
186219
const {getByText} = render({
@@ -194,4 +227,5 @@ test('fireEvent.update does not crash if non-input element is passed in', async
194227
Hi
195228
</div>
196229
`)
230+
expect(console.warn).not.toHaveBeenCalled()
197231
})

‎src/__tests__/form.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Form from './components/Form'
88
// Read 'What queries should I use?' for additional context:
99
// https://testing-library.com/docs/guide-which-query
1010
test('Review form submits', async () => {
11+
jest.spyOn(console, 'warn').mockImplementation(() => {})
1112
const fakeReview = {
1213
title: 'An Awesome Movie',
1314
review: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
@@ -61,4 +62,5 @@ test('Review form submits', async () => {
6162
// Assert the right event has been emitted.
6263
expect(emitted()).toHaveProperty('submit')
6364
expect(emitted().submit[0][0]).toMatchObject(fakeReview)
65+
expect(console.warn).not.toHaveBeenCalled()
6466
})

‎src/__tests__/user-event.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import '@testing-library/jest-dom'
2+
import {render} from '@testing-library/vue'
3+
import userEvent from '@testing-library/user-event'
4+
import Form from './components/Form'
5+
import Select from './components/Select'
6+
7+
beforeEach(() => {
8+
jest.spyOn(console, 'warn').mockImplementation(() => {})
9+
})
10+
11+
afterEach(() => {
12+
console.warn.mockRestore()
13+
})
14+
15+
test('User events in a form', async () => {
16+
const fakeReview = {
17+
title: 'An Awesome Movie',
18+
review: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
19+
rating: '3',
20+
}
21+
const {getByText, getByLabelText, emitted} = render(Form)
22+
23+
const submitButton = getByText('Submit')
24+
expect(submitButton).toBeDisabled()
25+
26+
const titleInput = getByLabelText(/titleofthemovie/i)
27+
await userEvent.type(titleInput, fakeReview.title)
28+
expect(titleInput.value).toEqual(fakeReview.title)
29+
30+
const textArea = getByLabelText(/Yourreview/i)
31+
await userEvent.type(textArea, 'The t-rex went insane!')
32+
expect(textArea.value).toEqual('The t-rex went insane!')
33+
34+
await userEvent.clear(textArea)
35+
expect(textArea.value).toEqual('')
36+
await userEvent.type(textArea, fakeReview.review)
37+
expect(textArea.value).toEqual(fakeReview.review)
38+
39+
const initialSelectedRating = getByLabelText(/Awful/i)
40+
const wonderfulRadioInput = getByLabelText(/Wonderful/i)
41+
expect(initialSelectedRating).toBeChecked()
42+
expect(wonderfulRadioInput).not.toBeChecked()
43+
44+
await userEvent.click(wonderfulRadioInput)
45+
expect(wonderfulRadioInput).toBeChecked()
46+
expect(initialSelectedRating).not.toBeChecked()
47+
48+
const recommendInput = getByLabelText(/Wouldyourecommendthismovie?/i)
49+
await userEvent.click(recommendInput)
50+
expect(recommendInput).toBeChecked()
51+
52+
userEvent.tab()
53+
expect(submitButton).toHaveFocus()
54+
expect(submitButton).toBeEnabled()
55+
await userEvent.type(submitButton, '{enter}')
56+
expect(emitted().submit[0][0]).toMatchObject(fakeReview)
57+
58+
expect(console.warn).not.toHaveBeenCalled()
59+
})
60+
61+
test('selecting option with user events', async () => {
62+
const {getByDisplayValue} = render(Select)
63+
const select = getByDisplayValue('Tyrannosaurus')
64+
expect(select.value).toBe('dino1')
65+
66+
await userEvent.selectOptions(select, 'dino2')
67+
expect(select.value).toBe('dino2')
68+
69+
await userEvent.selectOptions(select, 'dino3')
70+
expect(select.value).not.toBe('dino2')
71+
expect(select.value).toBe('dino3')
72+
})

‎src/vue-testing-library.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,16 @@ async function fireEvent(...args) {
112112
dtlFireEvent(...args)
113113
await waitFor(() => {})
114114
}
115+
const changeOrInputEventCalledDirectly = (eventValue, eventKey) =>
116+
eventValue && (eventKey === 'change' || eventKey === 'input')
115117

116118
Object.keys(dtlFireEvent).forEach(key => {
117119
fireEvent[key] = async (...args) => {
120+
if (changeOrInputEventCalledDirectly(args[1], key)) {
121+
console.warn(
122+
`Using "fireEvent.${key} may lead to unexpected results. Please use fireEvent.update() instead.`,
123+
)
124+
}
118125
dtlFireEvent[key](...args)
119126
await waitFor(() => {})
120127
}

0 commit comments

Comments
(0)

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