Skip to content

Commit 916b07f

Browse files
authored
Merge pull request #1380 from vvanpo/set-selected
fix: Ensure setChecked() and setSelected() only trigger DOM events when state is changed (fix #1339)
2 parents 56573b1 + cdc0762 commit 916b07f

File tree

3 files changed

+119
-1
lines changed

3 files changed

+119
-1
lines changed

packages/test-utils/src/wrapper.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,10 @@ export default class Wrapper implements BaseWrapper {
375375
)
376376
}
377377

378+
if (this.element.checked === checked) {
379+
return
380+
}
381+
378382
if (event !== 'click' || isPhantomJS) {
379383
// $FlowIgnore
380384
this.element.selected = true
@@ -400,6 +404,10 @@ export default class Wrapper implements BaseWrapper {
400404
}
401405

402406
if (tagName === 'OPTION') {
407+
if (this.element.selected) {
408+
return
409+
}
410+
403411
// $FlowIgnore
404412
this.element.selected = true
405413
// $FlowIgnore

test/specs/wrapper/setChecked.spec.js

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,43 @@ describeWithShallowAndMount('setChecked', mountingMethod => {
5555
expect(wrapper.find('.counter').text()).to.equal('4')
5656
})
5757

58+
it('triggers a change event when called on a checkbox', () => {
59+
const listener = sinon.spy()
60+
61+
mountingMethod({
62+
// For compatibility with earlier versions of Vue that use the `click`
63+
// event for updating `v-model`.
64+
template: `
65+
<input
66+
type="checkbox"
67+
@change="listener"
68+
@click="listener"
69+
>
70+
`,
71+
methods: { listener }
72+
}).setChecked()
73+
74+
expect(listener).to.have.been.called
75+
})
76+
77+
it('does not trigger a change event if the checkbox is already checked', () => {
78+
const listener = sinon.spy()
79+
80+
mountingMethod({
81+
template: `
82+
<input
83+
type="checkbox"
84+
checked
85+
@change="listener"
86+
@click="listener"
87+
>
88+
`,
89+
methods: { listener }
90+
}).setChecked()
91+
92+
expect(listener).not.to.have.been.called
93+
})
94+
5895
it('updates dom with radio v-model', async () => {
5996
const wrapper = mountingMethod(ComponentWithInput)
6097

@@ -67,7 +104,7 @@ describeWithShallowAndMount('setChecked', mountingMethod => {
67104
expect(wrapper.text()).to.contain('radioFooResult')
68105
})
69106

70-
it('changes state the right amount of times with checkbox v-model', async () => {
107+
it('changes state the right amount of times with radio v-model', async () => {
71108
const wrapper = mountingMethod(ComponentWithInput)
72109
const radioBar = wrapper.find('#radioBar')
73110
const radioFoo = wrapper.find('#radioFoo')
@@ -89,6 +126,41 @@ describeWithShallowAndMount('setChecked', mountingMethod => {
89126
expect(wrapper.find('.counter').text()).to.equal('4')
90127
})
91128

129+
it('triggers a change event when called on a radio button', () => {
130+
const listener = sinon.spy()
131+
132+
mountingMethod({
133+
template: `
134+
<input
135+
type="radio"
136+
@change="listener"
137+
@click="listener"
138+
>
139+
`,
140+
methods: { listener }
141+
}).setChecked()
142+
143+
expect(listener).to.have.been.called
144+
})
145+
146+
it('does not trigger a change event if the radio button is already checked', () => {
147+
const listener = sinon.spy()
148+
149+
mountingMethod({
150+
template: `
151+
<input
152+
type="radio"
153+
checked
154+
@change="listener"
155+
@click="listener"
156+
>
157+
`,
158+
methods: { listener }
159+
}).setChecked()
160+
161+
expect(listener).not.to.have.been.called
162+
})
163+
92164
it('throws error if checked param is not boolean', () => {
93165
const message = 'wrapper.setChecked() must be passed a boolean'
94166
const wrapper = mountingMethod(ComponentWithInput)

test/specs/wrapper/setSelected.spec.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,44 @@ describeWithShallowAndMount('setSelected', mountingMethod => {
3939
expect(wrapper.text()).to.contain('selectA')
4040
})
4141

42+
it('triggers a change event on the parent select', () => {
43+
const change = sinon.spy()
44+
45+
mountingMethod({
46+
template: `
47+
<select @change="change">
48+
<option />
49+
<option value="foo" />
50+
</select>
51+
`,
52+
methods: { change }
53+
})
54+
.findAll('option')
55+
.at(1)
56+
.setSelected()
57+
58+
expect(change).to.have.been.called
59+
})
60+
61+
it('does not trigger an event if called on already selected option', () => {
62+
const change = sinon.spy()
63+
64+
mountingMethod({
65+
template: `
66+
<select @change="change">
67+
<option />
68+
<option selected value="foo" />
69+
</select>
70+
`,
71+
methods: { change }
72+
})
73+
.findAll('option')
74+
.at(1)
75+
.setSelected()
76+
77+
expect(change).not.to.have.been.called
78+
})
79+
4280
it('throws error if element is not valid', () => {
4381
const message = 'wrapper.setSelected() cannot be called on this element'
4482

0 commit comments

Comments
 (0)