mirror of https://github.com/ElemeFE/element
Select: add test (#636)
parent
cfe8b895f2
commit
2f0ba607f4
|
@ -262,7 +262,7 @@
|
|||
|
||||
包含清空按钮,可将选择器清空为初始状态
|
||||
|
||||
:::demo 为`el-select`设置`clearable`属性,则可将选择器清空。需要注意的是,`clearable`属性仅使用于单选。
|
||||
:::demo 为`el-select`设置`clearable`属性,则可将选择器清空。需要注意的是,`clearable`属性仅适用于单选。
|
||||
```html
|
||||
<template>
|
||||
<el-select v-model="value4" clearable>
|
||||
|
|
|
@ -25,9 +25,15 @@
|
|||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
disabled(val) {
|
||||
this.broadcast('option', 'handleGroupDisabled', val);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.disabled) {
|
||||
this.broadcast('option', 'disableOptions');
|
||||
this.broadcast('option', 'handleGroupDisabled', this.disabled);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
@click.stop="selectOptionClick"
|
||||
class="el-select-dropdown__item"
|
||||
v-show="queryPassed"
|
||||
:class="{ 'selected': itemSelected, 'is-disabled': disabled, 'hover': parent.hoverIndex === index }">
|
||||
:class="{ 'selected': itemSelected, 'is-disabled': disabled || groupDisabled, 'hover': parent.hoverIndex === index }">
|
||||
<slot>
|
||||
<span>{{ currentLabel }}</span>
|
||||
</slot>
|
||||
|
@ -39,13 +39,17 @@
|
|||
data() {
|
||||
return {
|
||||
index: -1,
|
||||
groupDisabled: false,
|
||||
queryPassed: true,
|
||||
hitState: false,
|
||||
currentLabel: this.label
|
||||
hitState: false
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
currentLabel() {
|
||||
return this.label || ((typeof this.value === 'string' || typeof this.value === 'number') ? this.value : '');
|
||||
},
|
||||
|
||||
parent() {
|
||||
let result = this.$parent;
|
||||
while (!result.isSelect) {
|
||||
|
@ -76,18 +80,18 @@
|
|||
},
|
||||
|
||||
methods: {
|
||||
disableOptions() {
|
||||
this.disabled = true;
|
||||
handleGroupDisabled(val) {
|
||||
this.groupDisabled = val;
|
||||
},
|
||||
|
||||
hoverItem() {
|
||||
if (!this.disabled) {
|
||||
if (!this.disabled && !this.groupDisabled) {
|
||||
this.parent.hoverIndex = this.parent.options.indexOf(this);
|
||||
}
|
||||
},
|
||||
|
||||
selectOptionClick() {
|
||||
if (this.disabled !== true) {
|
||||
if (this.disabled !== true && this.groupDisabled !== true) {
|
||||
this.dispatch('select', 'handleOptionClick', this);
|
||||
}
|
||||
},
|
||||
|
@ -107,7 +111,6 @@
|
|||
},
|
||||
|
||||
created() {
|
||||
this.currentLabel = this.currentLabel || ((typeof this.value === 'string' || typeof this.value === 'number') ? this.value : '');
|
||||
this.parent.options.push(this);
|
||||
this.parent.optionsCount++;
|
||||
this.parent.filteredOptionsCount++;
|
||||
|
@ -118,7 +121,7 @@
|
|||
}
|
||||
|
||||
this.$on('queryChange', this.queryChange);
|
||||
this.$on('disableOptions', this.disableOptions);
|
||||
this.$on('handleGroupDisabled', this.handleGroupDisabled);
|
||||
this.$on('resetIndex', this.resetIndex);
|
||||
},
|
||||
|
||||
|
|
|
@ -53,11 +53,11 @@
|
|||
<transition name="md-fade-bottom" @after-leave="doDestroy">
|
||||
<el-select-menu
|
||||
ref="popper"
|
||||
v-show="visible && nodataText !== false">
|
||||
v-show="visible && emptyText !== false">
|
||||
<ul class="el-select-dropdown__list" v-show="options.length > 0 && filteredOptionsCount > 0 && !loading">
|
||||
<slot></slot>
|
||||
</ul>
|
||||
<p class="el-select-dropdown__nodata" v-if="nodataText">{{ nodataText }}</p>
|
||||
<p class="el-select-dropdown__nodata" v-if="emptyText">{{ emptyText }}</p>
|
||||
</el-select-menu>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -106,7 +106,7 @@
|
|||
return criteria;
|
||||
},
|
||||
|
||||
nodataText() {
|
||||
emptyText() {
|
||||
if (this.loading) {
|
||||
return '加载中';
|
||||
} else {
|
||||
|
@ -439,7 +439,9 @@
|
|||
this.hoverIndex = 0;
|
||||
}
|
||||
this.resetScrollTop();
|
||||
if (this.options[this.hoverIndex].disabled === true || !this.options[this.hoverIndex].queryPassed) {
|
||||
if (this.options[this.hoverIndex].disabled === true ||
|
||||
this.options[this.hoverIndex].groupDisabled === true ||
|
||||
!this.options[this.hoverIndex].queryPassed) {
|
||||
this.navigateOptions('next');
|
||||
}
|
||||
}
|
||||
|
@ -449,7 +451,9 @@
|
|||
this.hoverIndex = this.options.length - 1;
|
||||
}
|
||||
this.resetScrollTop();
|
||||
if (this.options[this.hoverIndex].disabled === true || !this.options[this.hoverIndex].queryPassed) {
|
||||
if (this.options[this.hoverIndex].disabled === true ||
|
||||
this.options[this.hoverIndex].groupDisabled === true ||
|
||||
!this.options[this.hoverIndex].queryPassed) {
|
||||
this.navigateOptions('prev');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,410 @@
|
|||
import { createTest, createVue, triggerEvent } from '../util';
|
||||
import Select from 'packages/select';
|
||||
|
||||
describe('Select', () => {
|
||||
const getSelectVm = (configs = {}, options) => {
|
||||
['multiple', 'clearable', 'filterable', 'remote'].forEach(config => {
|
||||
configs[config] = configs[config] || false;
|
||||
});
|
||||
if (!options) {
|
||||
options = [{
|
||||
value: '选项1',
|
||||
label: '黄金糕',
|
||||
disabled: false
|
||||
}, {
|
||||
value: '选项2',
|
||||
label: '双皮奶',
|
||||
disabled: false
|
||||
}, {
|
||||
value: '选项3',
|
||||
label: '蚵仔煎',
|
||||
disabled: false
|
||||
}, {
|
||||
value: '选项4',
|
||||
label: '龙须面',
|
||||
disabled: false
|
||||
}, {
|
||||
value: '选项5',
|
||||
label: '北京烤鸭',
|
||||
disabled: false
|
||||
}];
|
||||
}
|
||||
const vm = createVue({
|
||||
template: `
|
||||
<div>
|
||||
<el-select
|
||||
v-model="value"
|
||||
:multiple="multiple"
|
||||
:clearable="clearable"
|
||||
:filterable="filterable"
|
||||
:filterMethod="filterMethod"
|
||||
:remote="remote"
|
||||
:loading="loading"
|
||||
:remoteMethod="remoteMethod">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:label="item.label"
|
||||
:disabled="item.disabled"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
`,
|
||||
|
||||
data() {
|
||||
return {
|
||||
options,
|
||||
multiple: configs.multiple,
|
||||
clearable: configs.clearable,
|
||||
filterable: configs.filterable,
|
||||
loading: false,
|
||||
filterMethod: configs.filterMethod && configs.filterMethod(this),
|
||||
remote: configs.remote,
|
||||
remoteMethod: configs.remoteMethod && configs.remoteMethod(this),
|
||||
value: configs.multiple ? [] : ''
|
||||
};
|
||||
}
|
||||
}, true);
|
||||
return vm;
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
const el = document.querySelector('.el-select');
|
||||
if (!el) return;
|
||||
if (el.parentNode) {
|
||||
el.parentNode.removeChild(el);
|
||||
}
|
||||
});
|
||||
|
||||
it('create', () => {
|
||||
const vm = createTest(Select, true);
|
||||
expect(vm.$el.className).to.equal('el-select');
|
||||
expect(vm.$el.querySelector('.el-input__inner').placeholder).to.equal('请选择');
|
||||
vm.toggleMenu();
|
||||
expect(vm.visible).to.true;
|
||||
});
|
||||
|
||||
it('options rendered correctly', () => {
|
||||
const vm = getSelectVm();
|
||||
const options = vm.$el.querySelectorAll('.el-select-dropdown__item');
|
||||
const result = [].every.call(options, (option, index) => {
|
||||
let text = option.querySelector('span').textContent;
|
||||
return text === vm.options[index].label;
|
||||
});
|
||||
expect(result).to.true;
|
||||
});
|
||||
|
||||
it('default value', done => {
|
||||
const vm = createVue({
|
||||
template: `
|
||||
<div>
|
||||
<el-select v-model="value">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
`,
|
||||
|
||||
data() {
|
||||
return {
|
||||
options: [{
|
||||
value: '选项1',
|
||||
label: '黄金糕'
|
||||
}, {
|
||||
value: '选项2',
|
||||
label: '双皮奶'
|
||||
}],
|
||||
value: '选项2'
|
||||
};
|
||||
}
|
||||
}, true);
|
||||
setTimeout(() => {
|
||||
expect(vm.$el.querySelector('.el-input__inner').value).to.equal('双皮奶');
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('single select', done => {
|
||||
sinon.stub(window.console, 'log');
|
||||
const vm = createVue({
|
||||
template: `
|
||||
<div>
|
||||
<el-select v-model="value" @change="handleChange">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
<p>{{item.label}} {{item.value}}</p>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
`,
|
||||
|
||||
data() {
|
||||
return {
|
||||
options: [{
|
||||
value: '选项1',
|
||||
label: '黄金糕'
|
||||
}, {
|
||||
value: '选项2',
|
||||
label: '双皮奶'
|
||||
}, {
|
||||
value: '选项3',
|
||||
label: '蚵仔煎'
|
||||
}, {
|
||||
value: '选项4',
|
||||
label: '龙须面'
|
||||
}, {
|
||||
value: '选项5',
|
||||
label: '北京烤鸭'
|
||||
}],
|
||||
value: ''
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleChange() {
|
||||
console.log('changed');
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
const options = vm.$el.querySelectorAll('.el-select-dropdown__item');
|
||||
expect(vm.value).to.equal('');
|
||||
triggerEvent(options[2], 'mouseenter');
|
||||
options[2].click();
|
||||
setTimeout(() => {
|
||||
expect(vm.value).to.equal('选项3');
|
||||
expect(window.console.log.callCount).to.equal(1);
|
||||
options[4].click();
|
||||
setTimeout(() => {
|
||||
expect(vm.value).to.equal('选项5');
|
||||
expect(window.console.log.callCount).to.equal(2);
|
||||
window.console.log.restore();
|
||||
done();
|
||||
}, 100);
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('disabled option', done => {
|
||||
const vm = getSelectVm();
|
||||
vm.options[1].disabled = true;
|
||||
setTimeout(() => {
|
||||
const options = vm.$el.querySelectorAll('.el-select-dropdown__item');
|
||||
expect(options[1].classList.contains('is-disabled')).to.true;
|
||||
options[1].click();
|
||||
setTimeout(() => {
|
||||
expect(vm.value).to.equal('');
|
||||
done();
|
||||
}, 100);
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('disabled select', () => {
|
||||
const vm = createTest(Select, { disabled: true }, true);
|
||||
expect(vm.$el.querySelector('.el-input').classList.contains('is-disabled')).to.true;
|
||||
});
|
||||
|
||||
it('keyboard operations', done => {
|
||||
const vm = getSelectVm();
|
||||
const select = vm.$children[0];
|
||||
let i = 8;
|
||||
while (i--) {
|
||||
select.navigateOptions('next');
|
||||
}
|
||||
select.navigateOptions('prev');
|
||||
setTimeout(() => {
|
||||
expect(select.hoverIndex).to.equal(0);
|
||||
select.selectOption();
|
||||
setTimeout(() => {
|
||||
expect(select.value).to.equal('选项1');
|
||||
done();
|
||||
}, 100);
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('clearable', done => {
|
||||
const vm = getSelectVm({ clearable: true });
|
||||
const select = vm.$children[0];
|
||||
vm.value = '选项1';
|
||||
select.inputHovering = true;
|
||||
setTimeout(() => {
|
||||
const icon = vm.$el.querySelector('.el-input__icon');
|
||||
expect(icon.classList.contains('el-icon-circle-close')).to.true;
|
||||
icon.click();
|
||||
expect(vm.value).to.equal('');
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('custom el-option template', () => {
|
||||
const vm = createVue({
|
||||
template: `
|
||||
<div>
|
||||
<el-select v-model="value">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
<p>{{item.label}} {{item.value}}</p>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
`,
|
||||
|
||||
data() {
|
||||
return {
|
||||
options: [{
|
||||
value: 'value',
|
||||
label: 'label'
|
||||
}],
|
||||
value: ''
|
||||
};
|
||||
}
|
||||
}, true);
|
||||
expect(vm.$el.querySelector('.el-select-dropdown__item p').textContent).to.equal('label value');
|
||||
});
|
||||
|
||||
it('option group', () => {
|
||||
const vm = createVue({
|
||||
template: `
|
||||
<div>
|
||||
<el-select v-model="value">
|
||||
<el-option-group
|
||||
v-for="group in options"
|
||||
:disabled="group.disabled"
|
||||
:label="group.label">
|
||||
<el-option
|
||||
v-for="item in group.options"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
</div>
|
||||
`,
|
||||
|
||||
data() {
|
||||
return {
|
||||
options: [{
|
||||
label: '热门城市',
|
||||
options: [{
|
||||
value: 'Shanghai',
|
||||
label: '上海'
|
||||
}, {
|
||||
value: 'Beijing',
|
||||
label: '北京'
|
||||
}]
|
||||
}, {
|
||||
label: '城市名',
|
||||
disabled: true,
|
||||
options: [{
|
||||
value: 'Chengdu',
|
||||
label: '成都'
|
||||
}, {
|
||||
value: 'Shenzhen',
|
||||
label: '深圳'
|
||||
}, {
|
||||
value: 'Guangzhou',
|
||||
label: '广州'
|
||||
}, {
|
||||
value: 'Dalian',
|
||||
label: '大连'
|
||||
}]
|
||||
}],
|
||||
value: ''
|
||||
};
|
||||
}
|
||||
}, true);
|
||||
const groups = vm.$el.querySelectorAll('.el-select-group__wrap');
|
||||
const options = groups[1].querySelectorAll('.el-select-dropdown__item');
|
||||
expect(groups.length).to.equal(2);
|
||||
expect(options.length).to.equal(4);
|
||||
expect(options[0].querySelector('span').textContent).to.equal('成都');
|
||||
});
|
||||
|
||||
it('filterable', done => {
|
||||
const vm = getSelectVm({ filterable: true });
|
||||
const select = vm.$children[0];
|
||||
select.selectedLabel = '面';
|
||||
select.onInputChange();
|
||||
select.visible = true;
|
||||
setTimeout(() => {
|
||||
expect(select.filteredOptionsCount).to.equal(1);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('filterable with custom filter-method', done => {
|
||||
const filterMethod = vm => {
|
||||
return query => {
|
||||
vm.options = vm.options.filter(option => option.label.indexOf(query) === -1);
|
||||
};
|
||||
};
|
||||
const vm = getSelectVm({ filterable: true, filterMethod });
|
||||
const select = vm.$children[0];
|
||||
select.query = '面';
|
||||
setTimeout(() => {
|
||||
expect(select.filteredOptionsCount).to.equal(4);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('multiple select', done => {
|
||||
const vm = getSelectVm({ multiple: true });
|
||||
const options = vm.$el.querySelectorAll('.el-select-dropdown__item');
|
||||
vm.value = ['选项1'];
|
||||
setTimeout(() => {
|
||||
options[1].click();
|
||||
options[3].click();
|
||||
setTimeout(() => {
|
||||
expect(vm.value.indexOf('选项2') > -1 && vm.value.indexOf('选项4') > -1).to.true;
|
||||
const tagCloseIcons = vm.$el.querySelectorAll('.el-tag__close');
|
||||
tagCloseIcons[0].click();
|
||||
setTimeout(() => {
|
||||
expect(vm.value.indexOf('选项1')).to.equal(-1);
|
||||
done();
|
||||
}, 100);
|
||||
}, 100);
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('multiple remote search', done => {
|
||||
const remoteMethod = vm => {
|
||||
return query => {
|
||||
vm.loading = true;
|
||||
setTimeout(() => {
|
||||
vm.options = vm.options.filter(option => {
|
||||
return option.label.indexOf(query) > -1;
|
||||
});
|
||||
vm.loading = false;
|
||||
}, 200);
|
||||
};
|
||||
};
|
||||
const vm = getSelectVm({
|
||||
multiple: true,
|
||||
remote: true,
|
||||
filterable: true,
|
||||
remoteMethod
|
||||
});
|
||||
const select = vm.$children[0];
|
||||
select.query = '面';
|
||||
setTimeout(() => {
|
||||
expect(select.filteredOptionsCount).to.equal(1);
|
||||
select.query = '';
|
||||
select.options[0].$el.click();
|
||||
vm.$nextTick(() => {
|
||||
expect(vm.value[0]).to.equal('选项4');
|
||||
select.deletePrevTag({ target: select.$refs.input });
|
||||
select.deletePrevTag({ target: select.$refs.input });
|
||||
select.resetInputState({ keyCode: 1 });
|
||||
vm.$nextTick(() => {
|
||||
expect(vm.value.length).to.equal(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}, 250);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue