Skip to content

Commit

Permalink
feat(setValue): allow array for multiselect .setValue() method
Browse files Browse the repository at this point in the history
  • Loading branch information
freakzlike authored and cexbrayat committed Oct 20, 2022
1 parent 03cfd99 commit 76aa1d8
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 9 deletions.
18 changes: 17 additions & 1 deletion docs/api/index.md
Expand Up @@ -1633,14 +1633,21 @@ setValue(value: unknown, prop?: string): Promise<void>

<input type="checkbox" v-model="checked" />
<div v-if="checked">The input has been checked!</div>

<select v-model="multiselectValue" multiple>
<option value="value1"></option>
<option value="value2"></option>
<option value="value3"></option>
</select>
</template>

<script>
export default {
data() {
return {
text: '',
checked: false
checked: false,
multiselectValue: []
}
}
}
Expand Down Expand Up @@ -1669,6 +1676,15 @@ test('setValue on input text', () => {
await wrapper.find('input[type="text"]').setValue('hello!')
expect(wrapper.find('p').text()).toBe('Text: hello!')
})

test('setValue on multi select', () => {
const wrapper = mount(Component)

// For select without multiple
await wrapper.find('select').setValue('value1')
// For select with multiple
await wrapper.find('select').setValue(['value1', 'value3'])
})
```
::: warning
Expand Down
20 changes: 12 additions & 8 deletions src/domWrapper.ts
Expand Up @@ -105,16 +105,20 @@ export class DOMWrapper<NodeType extends Node> extends BaseWrapper<NodeType> {
return this.setChecked(value)
} else if (tagName === 'INPUT' && type === 'radio') {
return this.setChecked(value)
} else if (
tagName === 'INPUT' ||
tagName === 'TEXTAREA' ||
tagName === 'SELECT'
) {
} else if (tagName === 'SELECT') {
if (Array.isArray(value)) {
const selectElement = element as unknown as HTMLSelectElement
for (let i = 0; i < selectElement.options.length; i++) {
const option = selectElement.options[i]
option.selected = value.includes(option.value)
}
} else {
element.value = value
}
return this.trigger('change')
} else if (tagName === 'INPUT' || tagName === 'TEXTAREA') {
element.value = value

if (tagName === 'SELECT') {
return this.trigger('change')
}
this.trigger('input')
// trigger `change` for `v-model.lazy`
return this.trigger('change')
Expand Down
7 changes: 7 additions & 0 deletions tests/components/ComponentWithInput.vue
Expand Up @@ -30,12 +30,18 @@
<option value="selectC"></option>
</optgroup>
</select>
<select v-model="multiselectVal" class="multiselect" multiple>
<option value="selectA"></option>
<option value="selectB"></option>
<option value="selectC"></option>
</select>
<label id="label-el"></label>

<span class="checkboxResult" v-if="checkboxVal">checkbox checked</span>
<span class="counter">{{ counter }}</span>
{{ textVal }}
{{ selectVal }}
{{ multiselectVal }}
{{ radioVal }}
{{ lazy }}
</div>
Expand All @@ -55,6 +61,7 @@ export default defineComponent({
textareaVal: undefined,
radioVal: undefined,
selectVal: undefined,
multiselectVal: [],
counter: 0
}
},
Expand Down
34 changes: 34 additions & 0 deletions tests/setValue.spec.ts
Expand Up @@ -40,6 +40,9 @@ describe('setValue', () => {

expect(select.element.value).toEqual('selectB')
expect(wrapper.text()).toContain('selectB')

expect(wrapper.emitted('change')).toHaveLength(1)
expect(wrapper.emitted('input')).toBeUndefined()
})

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

expect(handle).toHaveBeenCalledTimes(1)
})

it('sets element of multiselect value', async () => {
const wrapper = mount(ComponentWithInput)
const select = wrapper.find<HTMLSelectElement>('select.multiselect')
await select.setValue(['selectA', 'selectC'])

const selectedOptions = Array.from(select.element.selectedOptions).map(
(o) => o.value
)
expect(selectedOptions).toEqual(['selectA', 'selectC'])
expect(wrapper.vm.multiselectVal).toEqual(['selectA', 'selectC'])

expect(wrapper.emitted('change')).toHaveLength(1)
expect(wrapper.emitted('input')).toBeUndefined()
})

it('overrides elements of multiselect', async () => {
const wrapper = mount(ComponentWithInput)
const select = wrapper.find<HTMLSelectElement>('select.multiselect')
await select.setValue(['selectA', 'selectC'])
await select.setValue(['selectB'])

const selectedOptions = Array.from(select.element.selectedOptions).map(
(o) => o.value
)
expect(selectedOptions).toEqual(['selectB'])
expect(wrapper.vm.multiselectVal).toEqual(['selectB'])

expect(wrapper.emitted('change')).toHaveLength(2)
expect(wrapper.emitted('input')).toBeUndefined()
})
})

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

0 comments on commit 76aa1d8

Please sign in to comment.