Select: add test (#636)

pull/638/head
杨奕 2016-10-25 18:00:39 +08:00 committed by FuryBean
parent cfe8b895f2
commit 2f0ba607f4
5 changed files with 439 additions and 16 deletions

View File

@ -262,7 +262,7 @@
包含清空按钮,可将选择器清空为初始状态
:::demo 为`el-select`设置`clearable`属性,则可将选择器清空。需要注意的是,`clearable`属性仅使用于单选。
:::demo 为`el-select`设置`clearable`属性,则可将选择器清空。需要注意的是,`clearable`属性仅用于单选。
```html
<template>
<el-select v-model="value4" clearable>

View File

@ -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);
}
}
};

View File

@ -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);
},

View File

@ -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');
}
}

View File

@ -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);
});
});