2
0
mirror of https://github.com/tenrok/vue-select.git synced 2026-06-22 10:30:34 +03:00

merge master, resolve upstream conflicts

This commit is contained in:
Jeff
2020-02-08 11:32:44 -08:00
14 changed files with 338 additions and 101 deletions
+2
View File
@@ -0,0 +1,2 @@
github: [sagalbot]
+4
View File
@@ -0,0 +1,4 @@
*
!src/**/*
!dist/**/*
.DS_Store
+30 -4
View File
@@ -1,8 +1,28 @@
<template> <template>
<div id="app" class="font-sans px-5 py-5"> <div id="app" class="font-sans px-5 py-5">
<v-select :options="countries"/> <v-select v-bind="jest" />
<!-- <ListSelect :options="countries" />--> <!-- <ListSelect :options="countries" />-->
<!-- <paginated />--> <!-- <paginated />-->
<!-- <v-select multiple :options="books" label="title">-->
<!-- <template #selected-option="selected">-->
<!-- <span :class="selected.bindings.class">-->
<!-- {{ selected.title }} {{ selected.author.firstName }} {{ selected.author.lastName }}-->
<!-- <component-->
<!-- ref="deselectButtons"-->
<!-- :is="selected.deselect.component"-->
<!-- v-if="selected.deselect.bindings.multiple"-->
<!-- v-bind="selected.deselect.bindings"-->
<!-- v-on="selected.deselect.events"-->
<!-- />-->
<!-- </span>-->
<!-- </template>-->
<!-- <template #option="{ title, author, attributes, events }">-->
<!-- <li v-bind="attributes" v-on="events">{{ title }} {{ author.firstName }} {{-->
<!-- author.lastName }}-->
<!-- </li>-->
<!-- </template>-->
<!-- </v-select>-->
</div> </div>
</template> </template>
@@ -15,11 +35,17 @@ import Sandbox from '../docs/.vuepress/components/Sandbox';
import countries from '../docs/.vuepress/data/countryCodes'; import countries from '../docs/.vuepress/data/countryCodes';
import books from '../docs/.vuepress/data/books'; import books from '../docs/.vuepress/data/books';
const randomBook = (id) => {
const rand = Math.floor(Math.random() * Math.floor(books.length - 1));
return {...books[rand], id};
}
export default { export default {
components: {vSelect, Sandbox, ListSelect, Paginated}, components: {vSelect, Sandbox, ListSelect, Paginated},
computed: { computed: {
countries: () => countries, countries: () => countries,
books: () => books, books: () => Array(100).fill(0).map((num, index) => randomBook(index)),
jest: () => ({value: [{label: "one"}], options: [{label: "one"}]}),
}, },
}; };
</script> </script>
@@ -0,0 +1,21 @@
<template>
<v-select
multiple
placeholder="Choose up to 3 books!"
label="title"
v-model="selected"
:options="books"
:selectable="() => selected.length < 3"
/>
</template>
<script>
import books from '../data/books';
export default {
data() {
return { selected: [] }
},
computed: {
books: () => books,
}
}
</script>
@@ -0,0 +1,16 @@
<template>
<v-select
placeholder="Choose a book to read"
label="title"
:options="books"
:selectable="option => ! option.author.lastName.includes('Woodhouse')"
/>
</template>
<script>
import books from '../data/books';
export default {
computed: {
books: () => books,
}
}
</script>
+1
View File
@@ -118,6 +118,7 @@ module.exports = {
collapsable: false, collapsable: false,
children: [ children: [
['guide/validation', 'Validation'], ['guide/validation', 'Validation'],
['guide/selectable', 'Limiting Selections'],
['guide/vuex', 'Vuex'], ['guide/vuex', 'Vuex'],
['guide/ajax', 'AJAX'], ['guide/ajax', 'AJAX'],
['guide/loops', 'Using in Loops'], ['guide/loops', 'Using in Loops'],
+13 -3
View File
@@ -339,12 +339,22 @@ createOption: {
## resetOnOptionsChange ## resetOnOptionsChange
When false, updating the options will not reset the select value When false, updating the options will not reset the selected value.
Since `v3.4+` the prop accepts either a `boolean` or `function` that returns a `boolean`.
If defined as a function, it will receive the params listed below.
```js ```js
/**
* @type {Boolean|Function}
* @param {Array} newOptions
* @param {Array} oldOptions
* @param {Array} selectedValue
*/
resetOnOptionsChange: { resetOnOptionsChange: {
type: Boolean, default: false,
default: false validator: (value) => ['function', 'boolean'].includes(typeof value)
}, },
``` ```
+44
View File
@@ -0,0 +1,44 @@
## Selectable Prop <Badge text="v3.3.0+" />
The `selectable` prop determines if an option is selectable or not. If `selectable` returns false
for a given option, it will be displayed with a `vs__dropdown-option--disabled` class. The option
will be disabled and unable to be selected.
```js
selectable: {
type: Function,
/**
* @param {Object|String} option
* @return {boolean}
*/
default: option => true,
},
```
### Example
Here `selectable` is used to prevent books by a certain author from being chosen. In this case,
the options passed to the component are objects:
```json
{
title: "Right Ho Jeeves",
author: { firstName: "P.D", lastName: "Woodhouse" },
}
```
This object will be passed to `selectable`, so we can check if the author should be selectable or not.
<UnselectableExample />
<<< @/.vuepress/components/UnselectableExample.vue{6}
## Limiting the Number of Selections
`selectable` can also be used a bit more creatively to limit the number selections that can be made
within the component. In this case, the user can select any author, but may only select a maximum
of three books.
<LimitSelectionQuantity />
<<< @/.vuepress/components/LimitSelectionQuantity.vue{8}
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "vue-select", "name": "vue-select",
"version": "3.2.0", "version": "3.4.0",
"description": "Everything you wish the HTML <select> element could do, wrapped up into a lightweight, extensible Vue component.", "description": "Everything you wish the HTML <select> element could do, wrapped up into a lightweight, extensible Vue component.",
"author": "Jeff Sagal <sagalbot@gmail.com>", "author": "Jeff Sagal <sagalbot@gmail.com>",
"homepage": "https://vue-select.org", "homepage": "https://vue-select.org",
+47 -39
View File
@@ -7,10 +7,11 @@
<span :class="selected.bindings.class"> <span :class="selected.bindings.class">
{{ selected.label }} {{ selected.label }}
<component <component
:is="selected.deselect.component" ref="deselectButtons"
v-if="selected.deselect.bindings.multiple" :is="selected.deselect.component"
v-bind="selected.deselect.bindings" v-if="selected.deselect.bindings.multiple"
v-on="selected.deselect.events" v-bind="selected.deselect.bindings"
v-on="selected.deselect.events"
/> />
</span> </span>
</slot> </slot>
@@ -22,6 +23,7 @@
<div class="vs__actions" ref="actions"> <div class="vs__actions" ref="actions">
<slot name="clear"> <slot name="clear">
<component <component
ref="clearButton"
:is="scope.clear.component" :is="scope.clear.component"
v-bind="scope.clear.bindings" v-bind="scope.clear.bindings"
v-on="scope.clear.events" v-on="scope.clear.events"
@@ -66,6 +68,8 @@
import ajax from '../mixins/ajax' import ajax from '../mixins/ajax'
import childComponents from './childComponents'; import childComponents from './childComponents';
const spreadableOptionProperties = (option) => typeof option === 'object' ? {...option} : {};
/** /**
* @name VueSelect * @name VueSelect
*/ */
@@ -215,10 +219,11 @@
}, },
/** /**
* Decides wether an option is selectable or not. Not selectable options * Decides whether an option is selectable or not. Not selectable options
* are displayed but disabled and cannot be selected. * are displayed but disabled and cannot be selected.
* *
* @type {Function} * @type {Function}
* @since 3.3.0
* @param {Object|String} option * @param {Object|String} option
* @return {Boolean} * @return {Boolean}
*/ */
@@ -292,10 +297,8 @@
getOptionScope: { getOptionScope: {
type: Function, type: Function,
default (option, index) { default (option, index) {
const optionProperties = typeof option === 'object' ? {...option} : {};
return { return {
...optionProperties, ...spreadableOptionProperties(option),
label: this.getOptionLabel(option), label: this.getOptionLabel(option),
attributes: { attributes: {
key: this.getOptionKey(option), key: this.getOptionKey(option),
@@ -322,6 +325,7 @@
type: Function, type: Function,
default (option, index) { default (option, index) {
return { return {
...spreadableOptionProperties(option),
label: this.getOptionLabel(option), label: this.getOptionLabel(option),
deselect: this.getOptionDeselectScope(option), deselect: this.getOptionDeselectScope(option),
bindings: { bindings: {
@@ -354,6 +358,7 @@
'aria-label': `Deselect ${this.getOptionLabel(option)}`, 'aria-label': `Deselect ${this.getOptionLabel(option)}`,
'disabled': this.disabled, 'disabled': this.disabled,
'multiple': this.multiple, 'multiple': this.multiple,
'ref': 'deselectButtons'
}, },
events: { events: {
'click': () => this.deselect(option), 'click': () => this.deselect(option),
@@ -467,12 +472,20 @@
}, },
/** /**
* When false, updating the options will not reset the select value * When false, updating the options will not reset the selected value. Accepts
* @type {Boolean} * a `boolean` or `function` that returns a `boolean`. If defined as a function,
* it will receive the params listed below.
*
* @since 3.4 - Type changed to {Boolean|Function}
*
* @type {Boolean|Function}
* @param {Array} newOptions
* @param {Array} oldOptions
* @param {Array} selectedValue
*/ */
resetOnOptionsChange: { resetOnOptionsChange: {
type: Boolean, default: false,
default: false validator: (value) => ['function', 'boolean'].includes(typeof value)
}, },
/** /**
@@ -571,13 +584,17 @@
* is correct. * is correct.
* @return {[type]} [description] * @return {[type]} [description]
*/ */
options(val) { options (newOptions, oldOptions) {
if (!this.taggable && this.resetOnOptionsChange) { let shouldReset = () => typeof this.resetOnOptionsChange === 'function'
this.clearSelection() ? this.resetOnOptionsChange(newOptions, oldOptions, this.selectedValue)
: this.resetOnOptionsChange;
if (!this.taggable && shouldReset()) {
this.clearSelection();
} }
if (this.value && this.isTrackingValues) { if (this.value && this.isTrackingValues) {
this.setInternalValueFromOptions(this.value) this.setInternalValueFromOptions(this.value);
} }
}, },
@@ -712,33 +729,23 @@
* @param {Event} e * @param {Event} e
* @return {void} * @return {void}
*/ */
toggleDropdown (e) { toggleDropdown ({target}) {
const target = e.target; // don't react to click on deselect/clear buttons,
const toggleTargets = [ // they dropdown state will be set in their click handlers
this.$el, const ignoredButtons = [
this.searchEl, ...(this.$refs['deselectButtons'] || []),
this.$refs.toggle, ...([this.$refs['clearButton']] || [])
this.$refs.actions,
this.$refs.selectedOptions,
]; ];
if (typeof this.$refs.openIndicator !== 'undefined') { if (ignoredButtons.some(ref => ref.contains(target) || ref === target)) {
toggleTargets.push( return;
this.$refs.openIndicator.$el,
// the line below is a bit gross, but required to support IE11 without adding polyfills
...Array.prototype.slice.call(this.$refs.openIndicator.$el.childNodes),
);
} }
if (toggleTargets.indexOf(target) > -1 || target.classList.contains('vs__selected')) { if (this.open) {
if (this.open) { this.searchEl.blur();
this.searchEl.blur(); // dropdown will close on blur } else if (!this.disabled) {
} else { this.open = true;
if (!this.disabled) { this.searchEl.focus();
this.open = true;
this.searchEl.focus();
}
}
} }
}, },
@@ -1061,6 +1068,7 @@
clear: { clear: {
component: this.childComponents.Deselect, component: this.childComponents.Deselect,
bindings: { bindings: {
'ref': 'clearButton',
'disabled': this.disabled, 'disabled': this.disabled,
'type': 'button', 'type': 'button',
'class': 'vs__clear', 'class': 'vs__clear',
+9 -8
View File
@@ -1,5 +1,5 @@
import { shallowMount } from "@vue/test-utils"; import { mount, shallowMount } from '@vue/test-utils';
import VueSelect from "../src/components/Select.vue"; import VueSelect from '../src/components/Select.vue';
import Vue from 'vue'; import Vue from 'vue';
/** /**
@@ -13,7 +13,7 @@ export const searchSubmit = (Wrapper, searchText = false) => {
if (searchText) { if (searchText) {
Wrapper.vm.search = searchText; Wrapper.vm.search = searchText;
} }
Wrapper.find({ ref: "search" }).trigger("keydown.enter") Wrapper.find({ref: 'search'}).trigger('keydown.enter');
}; };
/** /**
@@ -22,9 +22,11 @@ export const searchSubmit = (Wrapper, searchText = false) => {
* @param propsData * @param propsData
* @returns {Wrapper<Vue>} * @returns {Wrapper<Vue>}
*/ */
export const selectWithProps = (propsData = {}) => { export const selectWithProps = (propsData = {}) =>
return shallowMount(VueSelect, { propsData }); shallowMount(VueSelect, {propsData});
};
export const mountWithProps = (propsData = {}) =>
mount(VueSelect, {propsData});
/** /**
* Returns a Wrapper with a v-select component. * Returns a Wrapper with a v-select component.
@@ -42,7 +44,6 @@ export const mountDefault = (props = {}, options = {}) => {
}); });
}; };
/** /**
* Returns a v-select component directly. * Returns a v-select component directly.
* @param props * @param props
@@ -54,7 +55,7 @@ export const mountWithoutTestUtils = (props = {}, options = {}) => {
render: createEl => createEl('vue-select', { render: createEl => createEl('vue-select', {
ref: 'select', ref: 'select',
props: {options: ['one', 'two', 'three'], ...props}, props: {options: ['one', 'two', 'three'], ...props},
...options ...options,
}), }),
components: {VueSelect}, components: {VueSelect},
}).$mount().$refs.select; }).$mount().$refs.select;
+36 -24
View File
@@ -1,25 +1,37 @@
import { selectWithProps } from "../helpers"; import { mountWithProps } from "../helpers";
import OpenIndicator from "../../src/components/OpenIndicator"; import OpenIndicator from "../../src/components/OpenIndicator";
describe("Toggling Dropdown", () => { describe("Toggling Dropdown", () => {
it("should not open the dropdown when the el is clicked but the component is disabled", () => { it("should open the dropdown when the el is clicked", async () => {
const Select = selectWithProps({ disabled: true }); const Select = mountWithProps({
Select.vm.toggleDropdown({ target: Select.vm.$refs.search });
expect(Select.vm.open).toEqual(false);
});
it("should open the dropdown when the el is clicked", () => {
const Select = selectWithProps({
value: [{ label: "one" }], value: [{ label: "one" }],
options: [{ label: "one" }] options: [{ label: "one" }]
}); });
const spy = jest.spyOn(Select.vm, 'toggleDropdown');
Select.vm.toggleDropdown({ target: Select.vm.$refs.search }); Select.find({ref: 'toggle'}).trigger('mousedown');
await Select.vm.$nextTick();
expect(spy).toHaveBeenCalled();
expect(Select.vm.open).toEqual(true); expect(Select.vm.open).toEqual(true);
}); });
it("should not open the dropdown when the el is clicked but the component is disabled", async () => {
const Select = mountWithProps({ disabled: true });
const spy = jest.spyOn(Select.vm, 'toggleDropdown');
Select.find({ref: 'toggle'}).trigger('mousedown');
await Select.vm.$nextTick();
expect(spy).toHaveBeenCalled();
expect(Select.vm.open).toEqual(false);
});
it("should open the dropdown when the selected tag is clicked", () => { it("should open the dropdown when the selected tag is clicked", () => {
const Select = selectWithProps({ const Select = mountWithProps({
value: [{ label: "one" }], value: [{ label: "one" }],
options: [{ label: "one" }] options: [{ label: "one" }]
}); });
@@ -31,7 +43,7 @@ describe("Toggling Dropdown", () => {
}); });
it("can close the dropdown when the el is clicked", () => { it("can close the dropdown when the el is clicked", () => {
const Select = selectWithProps(); const Select = mountWithProps();
const spy = jest.spyOn(Select.vm.$refs.search, "blur"); const spy = jest.spyOn(Select.vm.$refs.search, "blur");
Select.vm.open = true; Select.vm.open = true;
@@ -41,7 +53,7 @@ describe("Toggling Dropdown", () => {
}); });
it("closes the dropdown when an option is selected, multiple is true, and closeOnSelect option is true", () => { it("closes the dropdown when an option is selected, multiple is true, and closeOnSelect option is true", () => {
const Select = selectWithProps({ const Select = mountWithProps({
value: [], value: [],
options: ["one", "two", "three"], options: ["one", "two", "three"],
multiple: true multiple: true
@@ -54,7 +66,7 @@ describe("Toggling Dropdown", () => {
}); });
it("does not close the dropdown when the el is clicked, multiple is true, and closeOnSelect option is false", () => { it("does not close the dropdown when the el is clicked, multiple is true, and closeOnSelect option is false", () => {
const Select = selectWithProps({ const Select = mountWithProps({
value: [], value: [],
options: ["one", "two", "three"], options: ["one", "two", "three"],
multiple: true, multiple: true,
@@ -68,7 +80,7 @@ describe("Toggling Dropdown", () => {
}); });
it("should close the dropdown on search blur", () => { it("should close the dropdown on search blur", () => {
const Select = selectWithProps({ const Select = mountWithProps({
options: [{ label: "one" }] options: [{ label: "one" }]
}); });
@@ -79,7 +91,7 @@ describe("Toggling Dropdown", () => {
}); });
it("will close the dropdown and emit the search:blur event from onSearchBlur", () => { it("will close the dropdown and emit the search:blur event from onSearchBlur", () => {
const Select = selectWithProps(); const Select = mountWithProps();
const spy = jest.spyOn(Select.vm, "$emit"); const spy = jest.spyOn(Select.vm, "$emit");
Select.vm.open = true; Select.vm.open = true;
@@ -90,7 +102,7 @@ describe("Toggling Dropdown", () => {
}); });
it("will open the dropdown and emit the search:focus event from onSearchFocus", () => { it("will open the dropdown and emit the search:focus event from onSearchFocus", () => {
const Select = selectWithProps(); const Select = mountWithProps();
const spy = jest.spyOn(Select.vm, "$emit"); const spy = jest.spyOn(Select.vm, "$emit");
Select.vm.onSearchFocus(); Select.vm.onSearchFocus();
@@ -100,7 +112,7 @@ describe("Toggling Dropdown", () => {
}); });
it("will close the dropdown on escape, if search is empty", () => { it("will close the dropdown on escape, if search is empty", () => {
const Select = selectWithProps(); const Select = mountWithProps();
const spy = jest.spyOn(Select.vm.$refs.search, "blur"); const spy = jest.spyOn(Select.vm.$refs.search, "blur");
Select.vm.open = true; Select.vm.open = true;
@@ -110,7 +122,7 @@ describe("Toggling Dropdown", () => {
}); });
it("should remove existing search text on escape keydown", () => { it("should remove existing search text on escape keydown", () => {
const Select = selectWithProps({ const Select = mountWithProps({
value: [{ label: "one" }], value: [{ label: "one" }],
options: [{ label: "one" }] options: [{ label: "one" }]
}); });
@@ -121,7 +133,7 @@ describe("Toggling Dropdown", () => {
}); });
it("should have an open class when dropdown is active", () => { it("should have an open class when dropdown is active", () => {
const Select = selectWithProps(); const Select = mountWithProps();
expect(Select.vm.stateClasses['vs--open']).toEqual(false); expect(Select.vm.stateClasses['vs--open']).toEqual(false);
@@ -130,7 +142,7 @@ describe("Toggling Dropdown", () => {
}); });
it("should not display the dropdown if noDrop is true", () => { it("should not display the dropdown if noDrop is true", () => {
const Select = selectWithProps({ const Select = mountWithProps({
noDrop: true, noDrop: true,
}); });
@@ -141,21 +153,21 @@ describe("Toggling Dropdown", () => {
}); });
it("should hide the open indicator if noDrop is true", () => { it("should hide the open indicator if noDrop is true", () => {
const Select = selectWithProps({ const Select = mountWithProps({
noDrop: true, noDrop: true,
}); });
expect(Select.contains(OpenIndicator)).toBeFalsy(); expect(Select.contains(OpenIndicator)).toBeFalsy();
}); });
it("should not add the searchable state class when noDrop is true", () => { it("should not add the searchable state class when noDrop is true", () => {
const Select = selectWithProps({ const Select = mountWithProps({
noDrop: true, noDrop: true,
}); });
expect(Select.classes('vs--searchable')).toBeFalsy(); expect(Select.classes('vs--searchable')).toBeFalsy();
}); });
it("should not add the searching state class when noDrop is true", () => { it("should not add the searching state class when noDrop is true", () => {
const Select = selectWithProps({ const Select = mountWithProps({
noDrop: true, noDrop: true,
}); });
+69 -1
View File
@@ -1,5 +1,6 @@
import { shallowMount } from "@vue/test-utils"; import { mount, shallowMount } from '@vue/test-utils';
import VueSelect from "../../src/components/Select"; import VueSelect from "../../src/components/Select";
import { mountDefault } from '../helpers';
describe("Reset on options change", () => { describe("Reset on options change", () => {
it("should not reset the selected value by default when the options property changes", () => { it("should not reset the selected value by default when the options property changes", () => {
@@ -13,6 +14,73 @@ describe("Reset on options change", () => {
expect(Select.vm.selectedValue).toEqual(["one"]); expect(Select.vm.selectedValue).toEqual(["one"]);
}); });
describe('resetOnOptionsChange as a function', () => {
it('will yell at you if resetOnOptionsChange is not a function or boolean', () => {
const spy = jest.spyOn(console, 'error').mockImplementation(() => {});
mountDefault({resetOnOptionsChange: 1});
expect(spy.mock.calls[0][0]).toContain('Invalid prop: custom validator check failed for prop "resetOnOptionsChange"')
mountDefault({resetOnOptionsChange: 'one'});
expect(spy.mock.calls[1][0]).toContain('Invalid prop: custom validator check failed for prop "resetOnOptionsChange"')
mountDefault({resetOnOptionsChange: []});
expect(spy.mock.calls[2][0]).toContain('Invalid prop: custom validator check failed for prop "resetOnOptionsChange"')
mountDefault({resetOnOptionsChange: {}});
expect(spy.mock.calls[3][0]).toContain('Invalid prop: custom validator check failed for prop "resetOnOptionsChange"')
});
it('should receive the new options, old options, and current value', () => {
let resetOnOptionsChange = jest.fn(option => option);
const Select = mountDefault(
{resetOnOptionsChange, options: ['bear'], value: 'selected'},
);
Select.setProps({options: ['lake', 'kite']});
expect(resetOnOptionsChange).toHaveBeenCalledTimes(1);
expect(resetOnOptionsChange)
.toHaveBeenCalledWith(['lake', 'kite'], ['bear'], ['selected']);
});
it('should allow resetOnOptionsChange to be a function that returns true', () => {
let resetOnOptionsChange = () => true;
const Select = shallowMount(VueSelect, {
propsData: {resetOnOptionsChange, options: ['one'], value: 'one'},
});
const spy = jest.spyOn(Select.vm, 'clearSelection');
Select.setProps({options: ['one', 'two']});
expect(spy).toHaveBeenCalledTimes(1);
});
it('should allow resetOnOptionsChange to be a function that returns false', () => {
let resetOnOptionsChange = () => false;
const Select = shallowMount(VueSelect, {
propsData: {resetOnOptionsChange, options: ['one'], value: 'one'},
});
const spy = jest.spyOn(Select.vm, 'clearSelection');
Select.setProps({options: ['one', 'two']});
expect(spy).not.toHaveBeenCalled();
});
it('should reset the options if the selectedValue does not exist in the new options', async () => {
let resetOnOptionsChange = (options, old, val) => val.some(val => options.includes(val));
const Select = shallowMount(VueSelect, {
propsData: {resetOnOptionsChange, options: ['one'], value: 'one'},
});
const spy = jest.spyOn(Select.vm, 'clearSelection');
Select.setProps({options: ['one', 'two']});
expect(Select.vm.selectedValue).toEqual(['one']);
Select.setProps({options: ['two']});
expect(spy).toHaveBeenCalledTimes(1);
});
});
it("should reset the selected value when the options property changes", () => { it("should reset the selected value when the options property changes", () => {
const Select = shallowMount(VueSelect, { const Select = shallowMount(VueSelect, {
propsData: { resetOnOptionsChange: true, options: ["one"] } propsData: { resetOnOptionsChange: true, options: ["one"] }
+45 -21
View File
@@ -1,29 +1,53 @@
import { mountDefault } from '../helpers'; import { mountDefault } from '../helpers';
/**
* Breaking change to the slot signature: {option} is no longer a valid key
* Breaking change: removed selected-option-container
*/
describe('Scoped Slots', () => { describe('Scoped Slots', () => {
it('receives an option object to the selected-option slot', () => { let receiveProps = props => receivedSlotProps = props;
const Select = mountDefault( let receivedSlotProps;
{value: 'one'},
{
scopedSlots: {
'selected-option': `<span class="vs__selected" slot="selected-option" slot-scope="option">{{ option.label }}</span>`,
},
});
expect(Select.find('.vs__selected').text()).toEqual('one') beforeEach(() => receivedSlotProps = null);
describe('Slot: selected-option', () => {
it('receives an option object in the selected-option slot', () => {
mountDefault(
{value: 'one'},
{scopedSlots: {'selected-option': receiveProps}},
);
expect(receivedSlotProps.label).toEqual('one');
expect(receivedSlotProps.hasOwnProperty('bindings')).toBeTruthy();
expect(receivedSlotProps.hasOwnProperty('events')).toBeTruthy();
expect(receivedSlotProps.hasOwnProperty('deselect')).toBeTruthy();
});
xit('opens the dropdown when clicked', () => {
const Select = mountDefault(
{value: 'one'},
{
scopedSlots: {
'selected-option': `<span class="my-option" slot-scope="option">{{ option.label }}</span>`,
},
});
Select.find('.my-option').trigger('mousedown');
expect(Select.vm.open).toEqual(true);
});
}); });
it('receives an option object to the option slot in the dropdown menu', () => { describe('Slot: option', () => {
const Select = mountDefault( it('receives an option object in the option slot', () => {
{value: 'one'}, const {vm} = mountDefault(
{ {value: 'one', options: ['one']},
scopedSlots: { {scopedSlots: {option: receiveProps}},
'option': `<span slot="option" slot-scope="option">{{ option.label }}</span>`, );
}, vm.open = true;
}); expect(receivedSlotProps.label).toEqual('one');
expect(receivedSlotProps.hasOwnProperty('attributes')).toBeTruthy();
Select.vm.open = true; expect(receivedSlotProps.hasOwnProperty('events')).toBeTruthy();
});
expect(Select.find({ref: 'dropdownMenu'}).text()).toEqual('onetwothree')
}); });
}); });