Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure setChecked() and setSelected() only trigger DOM events when state is changed (fix #1339) #1380

Merged
merged 8 commits into from
Jan 3, 2020
8 changes: 8 additions & 0 deletions packages/test-utils/src/wrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,10 @@ export default class Wrapper implements BaseWrapper {
)
}

if (this.element.checked === checked) {
vvanpo marked this conversation as resolved.
Show resolved Hide resolved
return
}

if (event !== 'click' || isPhantomJS) {
// $FlowIgnore
this.element.selected = true
Expand All @@ -400,6 +404,10 @@ export default class Wrapper implements BaseWrapper {
}

if (tagName === 'OPTION') {
if (this.element.selected) {
return
}

// $FlowIgnore
this.element.selected = true
// $FlowIgnore
Expand Down
74 changes: 73 additions & 1 deletion test/specs/wrapper/setChecked.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,43 @@ describeWithShallowAndMount('setChecked', mountingMethod => {
expect(wrapper.find('.counter').text()).to.equal('4')
})

it('should trigger a change event when called on a checkbox', () => {
vvanpo marked this conversation as resolved.
Show resolved Hide resolved
const listener = sinon.spy()

mountingMethod({
// For compatibility with earlier versions of Vue that use the `click`
// event for updating `v-model`.
template: `
<input
type="checkbox"
@change="listener"
@click="listener"
>
`,
methods: { listener }
}).setChecked()

expect(listener).to.have.been.called
})

it('should not trigger a change event if the checkbox is already checked', () => {
vvanpo marked this conversation as resolved.
Show resolved Hide resolved
const listener = sinon.spy()

mountingMethod({
template: `
<input
type="checkbox"
checked
@change="listener"
@click="listener"
>
`,
methods: { listener }
}).setChecked()

expect(listener).not.to.have.been.called
})

it('updates dom with radio v-model', async () => {
const wrapper = mountingMethod(ComponentWithInput)

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

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

it('should trigger a change event when called on a radio button', () => {
vvanpo marked this conversation as resolved.
Show resolved Hide resolved
const listener = sinon.spy()

mountingMethod({
template: `
<input
type="radio"
@change="listener"
@click="listener"
>
`,
methods: { listener }
}).setChecked()

expect(listener).to.have.been.called
})

it('should not trigger a change event if the radio button is already checked', () => {
vvanpo marked this conversation as resolved.
Show resolved Hide resolved
const listener = sinon.spy()

mountingMethod({
template: `
<input
type="radio"
checked
@change="listener"
@click="listener"
>
`,
methods: { listener }
}).setChecked()

expect(listener).not.to.have.been.called
})

it('throws error if checked param is not boolean', () => {
const message = 'wrapper.setChecked() must be passed a boolean'
const wrapper = mountingMethod(ComponentWithInput)
Expand Down
38 changes: 38 additions & 0 deletions test/specs/wrapper/setSelected.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,44 @@ describeWithShallowAndMount('setSelected', mountingMethod => {
expect(wrapper.text()).to.contain('selectA')
})

it('should trigger a change event on the parent <select>', () => {
vvanpo marked this conversation as resolved.
Show resolved Hide resolved
const change = sinon.spy()

mountingMethod({
template: `
<select @change="change">
<option />
<option value="foo" />
</select>
`,
methods: { change }
})
.findAll('option')
.at(1)
.setSelected()

expect(change).to.have.been.called
})

it('should not trigger an event if already selected', () => {
vvanpo marked this conversation as resolved.
Show resolved Hide resolved
const change = sinon.spy()

mountingMethod({
template: `
<select @change="change">
<option />
<option selected value="foo" />
</select>
`,
methods: { change }
})
.findAll('option')
.at(1)
.setSelected()

expect(change).not.to.have.been.called
})

it('throws error if element is not valid', () => {
const message = 'wrapper.setSelected() cannot be called on this element'

Expand Down