Skip to content

Commit 76aa1d8

Browse files
freakzlikecexbrayat
authored andcommitted
feat(setValue): allow array for multiselect .setValue() method
1 parent 03cfd99 commit 76aa1d8

File tree

4 files changed

+70
-9
lines changed

4 files changed

+70
-9
lines changed

docs/api/index.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1633,14 +1633,21 @@ setValue(value: unknown, prop?: string): Promise<void>
16331633

16341634
<input type="checkbox" v-model="checked" />
16351635
<div v-if="checked">The input has been checked!</div>
1636+
1637+
<select v-model="multiselectValue" multiple>
1638+
<option value="value1"></option>
1639+
<option value="value2"></option>
1640+
<option value="value3"></option>
1641+
</select>
16361642
</template>
16371643

16381644
<script>
16391645
export default {
16401646
data() {
16411647
return {
16421648
text: '',
1643-
checked: false
1649+
checked: false,
1650+
multiselectValue: []
16441651
}
16451652
}
16461653
}
@@ -1669,6 +1676,15 @@ test('setValue on input text', () => {
16691676
await wrapper.find('input[type="text"]').setValue('hello!')
16701677
expect(wrapper.find('p').text()).toBe('Text: hello!')
16711678
})
1679+
1680+
test('setValue on multi select', () => {
1681+
const wrapper = mount(Component)
1682+
1683+
// For select without multiple
1684+
await wrapper.find('select').setValue('value1')
1685+
// For select with multiple
1686+
await wrapper.find('select').setValue(['value1', 'value3'])
1687+
})
16721688
```
16731689
16741690
::: warning

src/domWrapper.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,16 +105,20 @@ export class DOMWrapper<NodeType extends Node> extends BaseWrapper<NodeType> {
105105
return this.setChecked(value)
106106
} else if (tagName === 'INPUT' && type === 'radio') {
107107
return this.setChecked(value)
108-
} else if (
109-
tagName === 'INPUT' ||
110-
tagName === 'TEXTAREA' ||
111-
tagName === 'SELECT'
112-
) {
108+
} else if (tagName === 'SELECT') {
109+
if (Array.isArray(value)) {
110+
const selectElement = element as unknown as HTMLSelectElement
111+
for (let i = 0; i < selectElement.options.length; i++) {
112+
const option = selectElement.options[i]
113+
option.selected = value.includes(option.value)
114+
}
115+
} else {
116+
element.value = value
117+
}
118+
return this.trigger('change')
119+
} else if (tagName === 'INPUT' || tagName === 'TEXTAREA') {
113120
element.value = value
114121

115-
if (tagName === 'SELECT') {
116-
return this.trigger('change')
117-
}
118122
this.trigger('input')
119123
// trigger `change` for `v-model.lazy`
120124
return this.trigger('change')

tests/components/ComponentWithInput.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,18 @@
3030
<option value="selectC"></option>
3131
</optgroup>
3232
</select>
33+
<select v-model="multiselectVal" class="multiselect" multiple>
34+
<option value="selectA"></option>
35+
<option value="selectB"></option>
36+
<option value="selectC"></option>
37+
</select>
3338
<label id="label-el"></label>
3439

3540
<span class="checkboxResult" v-if="checkboxVal">checkbox checked</span>
3641
<span class="counter">{{ counter }}</span>
3742
{{ textVal }}
3843
{{ selectVal }}
44+
{{ multiselectVal }}
3945
{{ radioVal }}
4046
{{ lazy }}
4147
</div>
@@ -55,6 +61,7 @@ export default defineComponent({
5561
textareaVal: undefined,
5662
radioVal: undefined,
5763
selectVal: undefined,
64+
multiselectVal: [],
5865
counter: 0
5966
}
6067
},

tests/setValue.spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ describe('setValue', () => {
4040

4141
expect(select.element.value).toEqual('selectB')
4242
expect(wrapper.text()).toContain('selectB')
43+
44+
expect(wrapper.emitted('change')).toHaveLength(1)
45+
expect(wrapper.emitted('input')).toBeUndefined()
4346
})
4447

4548
it('as an option of a select as selected', async () => {
@@ -82,6 +85,37 @@ describe('setValue', () => {
8285

8386
expect(handle).toHaveBeenCalledTimes(1)
8487
})
88+
89+
it('sets element of multiselect value', async () => {
90+
const wrapper = mount(ComponentWithInput)
91+
const select = wrapper.find<HTMLSelectElement>('select.multiselect')
92+
await select.setValue(['selectA', 'selectC'])
93+
94+
const selectedOptions = Array.from(select.element.selectedOptions).map(
95+
(o) => o.value
96+
)
97+
expect(selectedOptions).toEqual(['selectA', 'selectC'])
98+
expect(wrapper.vm.multiselectVal).toEqual(['selectA', 'selectC'])
99+
100+
expect(wrapper.emitted('change')).toHaveLength(1)
101+
expect(wrapper.emitted('input')).toBeUndefined()
102+
})
103+
104+
it('overrides elements of multiselect', async () => {
105+
const wrapper = mount(ComponentWithInput)
106+
const select = wrapper.find<HTMLSelectElement>('select.multiselect')
107+
await select.setValue(['selectA', 'selectC'])
108+
await select.setValue(['selectB'])
109+
110+
const selectedOptions = Array.from(select.element.selectedOptions).map(
111+
(o) => o.value
112+
)
113+
expect(selectedOptions).toEqual(['selectB'])
114+
expect(wrapper.vm.multiselectVal).toEqual(['selectB'])
115+
116+
expect(wrapper.emitted('change')).toHaveLength(2)
117+
expect(wrapper.emitted('input')).toBeUndefined()
118+
})
85119
})
86120

87121
describe('on radio and checkbox', () => {

0 commit comments

Comments
 (0)