init project
This commit is contained in:
commit
eb81760f47
679 changed files with 125497 additions and 0 deletions
137
test/unit/specs/affix.spec.js
Normal file
137
test/unit/specs/affix.spec.js
Normal file
|
@ -0,0 +1,137 @@
|
|||
import { createVue, destroyVM } from '../util';
|
||||
|
||||
describe('Affix.vue', () => {
|
||||
let vm;
|
||||
afterEach(() => {
|
||||
destroyVM(vm);
|
||||
});
|
||||
|
||||
it('should create a Affix component without slot', done => {
|
||||
vm = createVue('<Affix></Affix>');
|
||||
const affix = vm.$el.children[0];
|
||||
|
||||
expect(affix.tagName).to.equal('DIV');
|
||||
expect(affix.className).to.equal('');
|
||||
done();
|
||||
});
|
||||
|
||||
it('should create a Affix component contain slot', done => {
|
||||
vm = createVue(`
|
||||
<Affix>
|
||||
<span class="demo-affix">Fixed at the top</span>
|
||||
</Affix>
|
||||
`);
|
||||
const slot = vm.$el.children[0].children[0];
|
||||
|
||||
expect(slot.tagName).to.equal('SPAN');
|
||||
expect(slot.className).to.equal('demo-affix');
|
||||
done();
|
||||
});
|
||||
|
||||
it('only set offset-top props', done => {
|
||||
vm = createVue(`
|
||||
<div>
|
||||
<Affix :offset-top="20">
|
||||
<span class="demo-affix">Fixed at the top</span>
|
||||
</Affix>
|
||||
<div style="width: 100%; height: 2000px"></div>
|
||||
</div>
|
||||
`, true);
|
||||
const affix = vm.$el.children[0].children[0];
|
||||
const fakeBlock = vm.$el.children[0].children[1];
|
||||
|
||||
expect(affix.classList.contains('ivu-affix')).to.false;
|
||||
expect(affix.style.top).to.equal('');
|
||||
expect(fakeBlock.style.display).to.equal('none');
|
||||
window.scrollTo(0, 10000);
|
||||
setTimeout(()=>{
|
||||
expect(affix.classList.contains('ivu-affix')).to.true;
|
||||
expect(affix.style.top).to.equal('20px');
|
||||
expect(fakeBlock.style.display).to.equal('');
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('only set offset-bottom props', done => {
|
||||
vm = createVue(`
|
||||
<div>
|
||||
<div style="width: 100%; height: 2000px"></div>
|
||||
<Affix :offset-bottom="20">
|
||||
<span class="demo-affix">Fixed at the top</span>
|
||||
</Affix>
|
||||
<div style="width: 100%; height: 2000px"></div>
|
||||
</div>
|
||||
`, true);
|
||||
const affix = vm.$el.children[1].children[0];
|
||||
|
||||
expect(affix.classList.contains('ivu-affix')).to.false;
|
||||
expect(affix.style.bottom).to.equal('');
|
||||
// Affix component haven't run handleScroll function when component mounted in real dom.
|
||||
// use scrollTo() to trigger scroll event.
|
||||
window.scrollTo(0, 100);
|
||||
setTimeout(()=>{
|
||||
expect(affix.classList.contains('ivu-affix')).to.true;
|
||||
expect(affix.style.bottom).to.equal('20px');
|
||||
window.scrollTo(0, 10000);
|
||||
setTimeout(()=>{
|
||||
expect(affix.classList.contains('ivu-affix')).to.false;
|
||||
expect(affix.style.bottom).to.equal('');
|
||||
done();
|
||||
}, 100);
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('both props are set, only offset-bottom is valid', done => {
|
||||
vm = createVue(`
|
||||
<div>
|
||||
<div style="width: 100%; height: 2000px"></div>
|
||||
<Affix :offset-bottom="20" :offset-top="20">
|
||||
<span class="demo-affix">Fixed at the top</span>
|
||||
</Affix>
|
||||
<div style="width: 100%; height: 2000px"></div>
|
||||
</div>
|
||||
`, true);
|
||||
const affix = vm.$el.children[1].children[0];
|
||||
|
||||
expect(affix.classList.contains('ivu-affix')).to.false;
|
||||
expect(affix.style.bottom).to.equal('');
|
||||
// Affix component haven't run handleScroll function when component mounted in real dom.
|
||||
// use scrollTo() to trigger scroll event.
|
||||
window.scrollTo(0, 100);
|
||||
setTimeout(()=>{
|
||||
expect(affix.classList.contains('ivu-affix')).to.true;
|
||||
expect(affix.style.bottom).to.equal('20px');
|
||||
window.scrollTo(0, 10000);
|
||||
setTimeout(()=>{
|
||||
expect(affix.classList.contains('ivu-affix')).to.false;
|
||||
expect(affix.style.bottom).to.equal('');
|
||||
done();
|
||||
}, 100);
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('both props are not set, should fixed top and top equal 0px', done => {
|
||||
vm = createVue(`
|
||||
<div>
|
||||
<Affix>
|
||||
<span class="demo-affix">Fixed at the top</span>
|
||||
</Affix>
|
||||
<div style="width: 100%; height: 2000px"></div>
|
||||
</div>
|
||||
`, true);
|
||||
const affix = vm.$el.children[0].children[0];
|
||||
const fakeBlock = vm.$el.children[0].children[1];
|
||||
|
||||
expect(affix.classList.contains('ivu-affix')).to.false;
|
||||
expect(affix.style.top).to.equal('');
|
||||
expect(fakeBlock.style.display).to.equal('none');
|
||||
window.scrollTo(0, 10000);
|
||||
setTimeout(()=>{
|
||||
expect(affix.classList.contains('ivu-affix')).to.true;
|
||||
expect(affix.style.top).to.equal('0px');
|
||||
expect(fakeBlock.style.display).to.equal('');
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
});
|
18
test/unit/specs/assets/locale-expects.js
Normal file
18
test/unit/specs/assets/locale-expects.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
export default {
|
||||
'de-DE': 'Oktober 2030',
|
||||
'en-US': 'October 2030',
|
||||
'es-ES': 'octubre 2030',
|
||||
'fi-FI': 'lokakuu 2030',
|
||||
'fr-FR': 'octobre 2030',
|
||||
'id-ID': 'Oktober 2030',
|
||||
'ja-JP': '2030年 10月',
|
||||
'ko-KR': '2030년 10월',
|
||||
'pt-BR': 'outubro de 2030',
|
||||
'pt-PT': 'outubro de 2030',
|
||||
'ru-RU': 'Октябрь 2030',
|
||||
'sv-SE': 'oktober 2030',
|
||||
'tr-TR': 'Ekim 2030',
|
||||
'vi-VN': 'Tháng 10/2030',
|
||||
'zh-CN': '2030年 10月',
|
||||
'zh-TW': '2030年 10月'
|
||||
};
|
287
test/unit/specs/assets/table/csvData.js
Normal file
287
test/unit/specs/assets/table/csvData.js
Normal file
|
@ -0,0 +1,287 @@
|
|||
export const csvA = {
|
||||
columns: [
|
||||
{
|
||||
title: '名称',
|
||||
key: 'name',
|
||||
fixed: 'left',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: '展示',
|
||||
key: 'show',
|
||||
width: 150,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
title: '唤醒',
|
||||
key: 'weak',
|
||||
width: 150,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
title: '登录',
|
||||
key: 'signin',
|
||||
width: 150,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
title: '点击',
|
||||
key: 'click',
|
||||
width: 150,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
title: '激活',
|
||||
key: 'active',
|
||||
width: 150,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
title: '7日留存',
|
||||
key: 'day7',
|
||||
width: 150,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
title: '30日留存',
|
||||
key: 'day30',
|
||||
width: 150,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
title: '次日留存',
|
||||
key: 'tomorrow',
|
||||
width: 150,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
title: '日活跃',
|
||||
key: 'day',
|
||||
width: 150,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
title: '周活跃',
|
||||
key: 'week',
|
||||
width: 150,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
title: '月活跃',
|
||||
key: 'month',
|
||||
width: 150,
|
||||
sortable: true
|
||||
}
|
||||
],
|
||||
data: [
|
||||
{
|
||||
name: '推广名称1',
|
||||
fav: 0,
|
||||
show: 7302,
|
||||
weak: 5627,
|
||||
signin: 1563,
|
||||
click: 4254,
|
||||
active: 1438,
|
||||
day7: 274,
|
||||
day30: 285,
|
||||
tomorrow: 1727,
|
||||
day: 558,
|
||||
week: 4440,
|
||||
month: 5610
|
||||
},
|
||||
{
|
||||
name: '推广名称2',
|
||||
fav: 0,
|
||||
show: 4720,
|
||||
weak: 4086,
|
||||
signin: 3792,
|
||||
click: 8690,
|
||||
active: 8470,
|
||||
day7: 8172,
|
||||
day30: 5197,
|
||||
tomorrow: 1684,
|
||||
day: 2593,
|
||||
week: 2507,
|
||||
month: 1537
|
||||
},
|
||||
{
|
||||
name: '推广名称3',
|
||||
fav: 0,
|
||||
show: 7181,
|
||||
weak: 8007,
|
||||
signin: 8477,
|
||||
click: 1879,
|
||||
active: 16,
|
||||
day7: 2249,
|
||||
day30: 3450,
|
||||
tomorrow: 377,
|
||||
day: 1561,
|
||||
week: 3219,
|
||||
month: 1588
|
||||
},
|
||||
{
|
||||
name: '推广名称4',
|
||||
fav: 0,
|
||||
show: 9911,
|
||||
weak: 8976,
|
||||
signin: 8807,
|
||||
click: 8050,
|
||||
active: 7668,
|
||||
day7: 1547,
|
||||
day30: 2357,
|
||||
tomorrow: 7278,
|
||||
day: 5309,
|
||||
week: 1655,
|
||||
month: 9043
|
||||
},
|
||||
{
|
||||
name: '推广名称5',
|
||||
fav: 0,
|
||||
show: 934,
|
||||
weak: 1394,
|
||||
signin: 6463,
|
||||
click: 5278,
|
||||
active: 9256,
|
||||
day7: 209,
|
||||
day30: 3563,
|
||||
tomorrow: 8285,
|
||||
day: 1230,
|
||||
week: 4840,
|
||||
month: 9908
|
||||
},
|
||||
{
|
||||
name: '推广名称6',
|
||||
fav: 0,
|
||||
show: 6856,
|
||||
weak: 1608,
|
||||
signin: 457,
|
||||
click: 4949,
|
||||
active: 2909,
|
||||
day7: 4525,
|
||||
day30: 6171,
|
||||
tomorrow: 1920,
|
||||
day: 1966,
|
||||
week: 904,
|
||||
month: 6851
|
||||
},
|
||||
{
|
||||
name: '推广名称7',
|
||||
fav: 0,
|
||||
show: 5107,
|
||||
weak: 6407,
|
||||
signin: 4166,
|
||||
click: 7970,
|
||||
active: 1002,
|
||||
day7: 8701,
|
||||
day30: 9040,
|
||||
tomorrow: 7632,
|
||||
day: 4061,
|
||||
week: 4359,
|
||||
month: 3676
|
||||
},
|
||||
{
|
||||
name: '推广名称8',
|
||||
fav: 0,
|
||||
show: 862,
|
||||
weak: 6520,
|
||||
signin: 6696,
|
||||
click: 3209,
|
||||
active: 6801,
|
||||
day7: 6364,
|
||||
day30: 6850,
|
||||
tomorrow: 9408,
|
||||
day: 2481,
|
||||
week: 1479,
|
||||
month: 2346
|
||||
},
|
||||
{
|
||||
name: '推广名称9',
|
||||
fav: 0,
|
||||
show: 567,
|
||||
weak: 5859,
|
||||
signin: 128,
|
||||
click: 6593,
|
||||
active: 1971,
|
||||
day7: 7596,
|
||||
day30: 3546,
|
||||
tomorrow: 6641,
|
||||
day: 1611,
|
||||
week: 5534,
|
||||
month: 3190
|
||||
},
|
||||
{
|
||||
name: '推广名称10',
|
||||
fav: 0,
|
||||
show: 3651,
|
||||
weak: 1819,
|
||||
signin: 4595,
|
||||
click: 7499,
|
||||
active: 7405,
|
||||
day7: 8710,
|
||||
day30: 5518,
|
||||
tomorrow: 428,
|
||||
day: 9768,
|
||||
week: 2864,
|
||||
month: 5811
|
||||
}
|
||||
],
|
||||
expected: `
|
||||
名称,展示,唤醒,登录,点击,激活,7日留存,30日留存,次日留存,日活跃,周活跃,月活跃
|
||||
推广名称1,7302,5627,1563,4254,1438,274,285,1727,558,4440,5610
|
||||
推广名称2,4720,4086,3792,8690,8470,8172,5197,1684,2593,2507,1537
|
||||
推广名称3,7181,8007,8477,1879,16,2249,3450,377,1561,3219,1588
|
||||
推广名称4,9911,8976,8807,8050,7668,1547,2357,7278,5309,1655,9043
|
||||
推广名称5,934,1394,6463,5278,9256,209,3563,8285,1230,4840,9908
|
||||
推广名称6,6856,1608,457,4949,2909,4525,6171,1920,1966,904,6851
|
||||
推广名称7,5107,6407,4166,7970,1002,8701,9040,7632,4061,4359,3676
|
||||
推广名称8,862,6520,6696,3209,6801,6364,6850,9408,2481,1479,2346
|
||||
推广名称9,567,5859,128,6593,1971,7596,3546,6641,1611,5534,3190
|
||||
推广名称10,3651,1819,4595,7499,7405,8710,5518,428,9768,2864,5811
|
||||
`
|
||||
};
|
||||
|
||||
export const csvB = {
|
||||
columns: [
|
||||
{
|
||||
title: '姓名',
|
||||
key: 'name'
|
||||
},
|
||||
{
|
||||
title: '年龄',
|
||||
key: 'age'
|
||||
},
|
||||
{
|
||||
title: '地址',
|
||||
key: 'address'
|
||||
}
|
||||
],
|
||||
data: [
|
||||
{
|
||||
name: '王小明',
|
||||
age: 18,
|
||||
address: '北京市朝\n阳区芍药居'
|
||||
},
|
||||
{
|
||||
name: '张小刚',
|
||||
age: 25,
|
||||
address: '北京市海,淀区西二旗'
|
||||
},
|
||||
{
|
||||
name: '李小红',
|
||||
age: 30,
|
||||
address: '上海市浦东\r新区世纪大道'
|
||||
},
|
||||
{
|
||||
name: '周小伟',
|
||||
age: 26,
|
||||
address: '深圳市南山区深南大道'
|
||||
}
|
||||
],
|
||||
expected: `
|
||||
"姓名";"年龄";"地址"
|
||||
"王小明";"18";"北京市朝\n阳区芍药居"
|
||||
"张小刚";"25";"北京市海,淀区西二旗"
|
||||
"李小红";"30";"上海市浦东\r新区世纪大道"
|
||||
"周小伟";"26";"深圳市南山区深南大道"
|
||||
`
|
||||
};
|
24
test/unit/specs/breadcrumb.spec.js
Normal file
24
test/unit/specs/breadcrumb.spec.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { createVue, destroyVM } from '../util';
|
||||
|
||||
describe('Breadcrumb.vue', () => {
|
||||
let vm;
|
||||
afterEach(() => {
|
||||
destroyVM(vm);
|
||||
});
|
||||
it('create', done => {
|
||||
vm = createVue(`
|
||||
<Breadcrumb separator="<b class='demo-breadcrumb-separator'>=></b>">
|
||||
<Breadcrumb-item href="/">Home4</Breadcrumb-item>
|
||||
<Breadcrumb-item href="/components/breadcrumb">Components</Breadcrumb-item>
|
||||
<Breadcrumb-item>Breadcrumb</Breadcrumb-item>
|
||||
</Breadcrumb>
|
||||
`);
|
||||
expect(vm.$el.querySelectorAll('.ivu-breadcrumb-item-link').length).to.equal(3);
|
||||
|
||||
vm.$nextTick(_ => {
|
||||
// console.log(vm.$el.querySelector('.ivu-breadcrumb-item-separator').innerHTML);
|
||||
expect(vm.$el.querySelector('.ivu-breadcrumb-item-separator').innerHTML).to.equal('<b class="demo-breadcrumb-separator">=></b>');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
66
test/unit/specs/button.spec.js
Normal file
66
test/unit/specs/button.spec.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
import { createVue, destroyVM } from '../util';
|
||||
|
||||
describe('Button.vue', () => {
|
||||
let vm;
|
||||
afterEach(() => {
|
||||
destroyVM(vm);
|
||||
});
|
||||
|
||||
it('should render as <a>', done => {
|
||||
vm = createVue(`
|
||||
<Button to="http://www.thinkinfe.tech/">Think in FE</Button>
|
||||
`);
|
||||
expect(vm.$el.tagName).to.equal('A');
|
||||
done();
|
||||
});
|
||||
|
||||
it('should render as <button>', done => {
|
||||
vm = createVue(`
|
||||
<Button>Think in FE</Button>
|
||||
`);
|
||||
expect(vm.$el.tagName).to.equal('BUTTON');
|
||||
done();
|
||||
});
|
||||
|
||||
it('handle with `type` attribute', done => {
|
||||
// should render with `type` attribute
|
||||
// if it is a <button>
|
||||
vm = createVue(`
|
||||
<Button htmlType="reset">Think in FE</Button>
|
||||
`);
|
||||
expect(vm.$el.getAttribute('type')).to.equal('reset');
|
||||
|
||||
// should't render with `type` attribute
|
||||
// if it is a <button>
|
||||
vm = createVue(`
|
||||
<Button to="http://www.thinkinfe.tech/" htmlType="reset">Think in FE</Button>
|
||||
`);
|
||||
expect(vm.$el.getAttribute('type')).to.equal(null);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should change loading state', done => {
|
||||
vm = createVue({
|
||||
template: `
|
||||
<Button :loading="loading" @click="fetch">Think in FE</Button>
|
||||
`,
|
||||
data() {
|
||||
return {loading: false};
|
||||
},
|
||||
methods: {
|
||||
fetch() {
|
||||
this.loading = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
vm.$el.click();
|
||||
vm.$nextTick(() => {
|
||||
expect(vm.$el.classList.contains('ivu-btn-loading')).to.equal(true);
|
||||
const $icons = vm.$el.querySelectorAll('.ivu-icon');
|
||||
expect($icons.length).to.equal(1);
|
||||
expect($icons[0].classList.contains('ivu-load-loop')).to.equal(true);
|
||||
expect($icons[0].classList.contains('ivu-icon-ios-loading')).to.equal(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
67
test/unit/specs/date-picker-utils.spec.js
Normal file
67
test/unit/specs/date-picker-utils.spec.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
const {prevMonth, nextMonth, getDayCountOfMonth} = require('../../../src/components/date-picker/util.js');
|
||||
|
||||
// yyyy-mm-dd -> Date
|
||||
function dateFromString(str) {
|
||||
str = str.split('-').map(Number);
|
||||
str[1] = str[1] - 1;
|
||||
return new Date(...str);
|
||||
}
|
||||
|
||||
// Date -> yyyy-mm-dd
|
||||
function dateToString(date) {
|
||||
return [date.getFullYear(), date.getMonth() + 1, date.getDate()].join('-');
|
||||
}
|
||||
|
||||
describe('DatePicker utility functions', () => {
|
||||
const assets = [
|
||||
{date: '2030-3-31', prevMonth: '2030-2-28', nextMonth: '2030-4-30', count: 31},
|
||||
{date: '2030-3-28', prevMonth: '2030-2-28', nextMonth: '2030-4-28', count: 31},
|
||||
{date: '2030-3-1', prevMonth: '2030-2-1', nextMonth: '2030-4-1', count: 31},
|
||||
{date: '2030-2-1', prevMonth: '2030-1-1', nextMonth: '2030-3-1', count: 28},
|
||||
{date: '2030-1-1', prevMonth: '2029-12-1', nextMonth: '2030-2-1', count: 31},
|
||||
{date: '2030-12-31', prevMonth: '2030-11-30', nextMonth: '2031-1-31', count: 31},
|
||||
{date: '2030-6-30', prevMonth: '2030-5-30', nextMonth: '2030-7-30', count: 30},
|
||||
{date: '2030-5-31', prevMonth: '2030-4-30', nextMonth: '2030-6-30', count: 31},
|
||||
{date: '2032-3-31', prevMonth: '2032-2-29', nextMonth: '2032-4-30', count: 31},
|
||||
{date: '2032-2-1', prevMonth: '2032-1-1', nextMonth: '2032-3-1', count: 29}
|
||||
];
|
||||
|
||||
it('Should behave as pure functions and not change source date', () => {
|
||||
const date = new Date(2030, 4, 10);
|
||||
const original = date.getMonth();
|
||||
const foo = prevMonth(date);
|
||||
|
||||
expect(original).to.equal(date.getMonth());
|
||||
|
||||
const bar = nextMonth(date);
|
||||
expect(original).to.equal(date.getMonth());
|
||||
expect(bar.getMonth() - foo.getMonth()).to.equal(2);
|
||||
});
|
||||
|
||||
it('Should calculate the previous month', () => {
|
||||
for (const asset of assets) {
|
||||
const date = dateFromString(asset.date);
|
||||
const previous = prevMonth(date);
|
||||
|
||||
expect(dateToString(previous)).to.equal(asset.prevMonth);
|
||||
}
|
||||
});
|
||||
|
||||
it('Should calculate the next month', () => {
|
||||
for (const asset of assets) {
|
||||
const date = dateFromString(asset.date);
|
||||
const next = nextMonth(date);
|
||||
|
||||
expect(dateToString(next)).to.equal(asset.nextMonth);
|
||||
}
|
||||
});
|
||||
|
||||
it('Should calculate the month length', () => {
|
||||
for (const asset of assets) {
|
||||
const date = dateFromString(asset.date);
|
||||
const monthLength = getDayCountOfMonth(date.getFullYear(), date.getMonth());
|
||||
|
||||
expect(monthLength).to.equal(asset.count);
|
||||
}
|
||||
});
|
||||
});
|
391
test/unit/specs/date-picker.spec.js
Normal file
391
test/unit/specs/date-picker.spec.js
Normal file
|
@ -0,0 +1,391 @@
|
|||
import { createVue, destroyVM, stringToDate, dateToString, dateToTimeString, promissedTick } from '../util';
|
||||
|
||||
describe('DatePicker.vue', () => {
|
||||
let vm;
|
||||
afterEach(() => {
|
||||
destroyVM(vm);
|
||||
});
|
||||
|
||||
it('should create a DatePicker component and open the calendar with the current month', done => {
|
||||
vm = createVue(`
|
||||
<Date-Picker></Date-Picker>
|
||||
`);
|
||||
const picker = vm.$children[0];
|
||||
picker.$el.querySelector('input.ivu-input').focus();
|
||||
vm.$nextTick(() => {
|
||||
const calendarBody = vm.$el.querySelector('.ivu-picker-panel-body .ivu-date-picker-cells:first-of-type');
|
||||
const calendarCells = [...calendarBody.querySelectorAll('.ivu-date-picker-cells-cell')].filter(el => {
|
||||
const prevMonth = el.classList.contains('ivu-date-picker-cells-cell-prev-month');
|
||||
const nextMonth = el.classList.contains('ivu-date-picker-cells-cell-next-month');
|
||||
return !prevMonth && !nextMonth;
|
||||
});
|
||||
const today = new Date();
|
||||
const daysInCurrentMonth = new Date(today.getFullYear(), today.getMonth() + 1, 0).getDate();
|
||||
expect(daysInCurrentMonth).to.equal(calendarCells.length);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass correct arguments to on-change event', done => {
|
||||
const now = new Date();
|
||||
const nowDate = dateToString(now);
|
||||
const nowTime = dateToTimeString(now);
|
||||
const nextHour = dateToTimeString(now.getTime() + 36e5);
|
||||
const nextWeek = new Date(now.getTime() + 6048e5);
|
||||
|
||||
let dateValue, dateRangeValue, timeValue, timeRangeValue;
|
||||
vm = createVue({
|
||||
template: `
|
||||
<div>
|
||||
<date-picker type="date" @on-change="onChangeDate"></date-picker>
|
||||
<date-picker type="daterange" @on-change="onChangeDateRange"></date-picker>
|
||||
<time-picker type="time" @on-change="onChangeTime"></time-picker>
|
||||
<time-picker type="timerange" @on-change="onChangeTimeRange"></time-picker>
|
||||
</div>
|
||||
`,
|
||||
methods: {
|
||||
onChangeDate(val) {
|
||||
dateValue = val;
|
||||
},
|
||||
onChangeDateRange(val) {
|
||||
dateRangeValue = val;
|
||||
},
|
||||
onChangeTime(val) {
|
||||
timeValue = val;
|
||||
},
|
||||
onChangeTimeRange(val) {
|
||||
timeRangeValue = val;
|
||||
},
|
||||
}
|
||||
}, true);
|
||||
|
||||
vm.$nextTick(() => {
|
||||
const [datePicker, dateRangePicker, timePicker, timeRangePicker] = vm.$children;
|
||||
|
||||
datePicker.handleInputChange({target: {value: nowDate}});
|
||||
dateRangePicker.handleInputChange({target: {value: [
|
||||
nowDate,
|
||||
dateToString(nextWeek)
|
||||
].join(' - ')
|
||||
}});
|
||||
|
||||
timePicker.handleInputChange({target: {value: nowTime}});
|
||||
const timeRangeString = [
|
||||
nowTime,
|
||||
nextHour
|
||||
].join(' - ');
|
||||
timeRangePicker.handleInputChange({target: {
|
||||
value: timeRangeString
|
||||
}});
|
||||
|
||||
vm.$nextTick(() => {
|
||||
// DATE
|
||||
expect(typeof dateValue).to.equal('string');
|
||||
expect(dateValue).to.equal(nowDate);
|
||||
// DATERANGE
|
||||
expect(Array.isArray(dateRangeValue)).to.equal(true);
|
||||
expect(dateRangeValue[0]).to.equal(nowDate);
|
||||
expect(dateRangeValue[1]).to.equal(dateToString(nextWeek));
|
||||
|
||||
// TIME
|
||||
expect(typeof timeValue).to.equal('string');
|
||||
expect(timeValue).to.equal(nowTime);
|
||||
// TIMERANGE
|
||||
expect(Array.isArray(timeRangeValue)).to.equal(true);
|
||||
expect(timeRangeValue[0]).to.equal(nowTime);
|
||||
expect(timeRangeValue[1]).to.equal(nextHour);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a DatePicker component of type="datetimerange"', done => {
|
||||
vm = createVue(`
|
||||
<Date-Picker type="datetimerange"></Date-Picker>
|
||||
`);
|
||||
const picker = vm.$children[0];
|
||||
expect(picker.$children.length).to.equal(2);
|
||||
expect(Array.isArray(picker.internalValue)).to.equal(true);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should create a datetimerange component and pick 2 dates in the current month', done => {
|
||||
vm = createVue(`
|
||||
<Date-picker type="datetimerange"></Date-picker>
|
||||
`);
|
||||
|
||||
const picker = vm.$children[0];
|
||||
picker.handleFocus({type: 'focus'});
|
||||
vm.$nextTick(() => {
|
||||
const displayField = vm.$el.querySelector('.ivu-input');
|
||||
const clickableCells = vm.$el.querySelectorAll('.ivu-date-picker-cells-cell');
|
||||
const lastMonthClass = 'ivu-date-picker-cells-cell-prev-month';
|
||||
const firstDayInMonthIndex = [...clickableCells].findIndex(cell => !cell.classList.contains(lastMonthClass));
|
||||
|
||||
clickableCells[firstDayInMonthIndex].firstElementChild.click();
|
||||
vm.$nextTick(() => {
|
||||
clickableCells[firstDayInMonthIndex + 4].firstElementChild.click();
|
||||
vm.$nextTick(() => {
|
||||
const dayOne = new Date();
|
||||
dayOne.setDate(1);
|
||||
dayOne.setHours(0, 0, 0, 0);
|
||||
const dayFive = new Date(dayOne.getTime());
|
||||
dayFive.setDate(5);
|
||||
dayFive.setHours(0, 0, 0, 0);
|
||||
|
||||
// check pickers internal value
|
||||
const [startInternalValue, endInternalValue] = picker.internalValue; // Date Objects
|
||||
expect(Math.abs(dayOne - startInternalValue)).to.equal(0);
|
||||
expect(Math.abs(dayFive - endInternalValue)).to.equal(0);
|
||||
|
||||
/*
|
||||
const [startInternalValue, endInternalValue] = picker.internalValue; // Date Objects
|
||||
expect(dateToString(dayOne)).to.equal(dateToString(startInternalValue));
|
||||
expect(dateToString(dayFive)).to.equal(dateToString(endInternalValue));
|
||||
|
||||
*/
|
||||
|
||||
// check pickers display value
|
||||
const [startDisplayValue, endDisplayValue] = displayField.value.split(' - ').map(stringToDate); // Date Objects
|
||||
expect(Math.abs(dayOne - startDisplayValue)).to.equal(0);
|
||||
expect(Math.abs(dayFive - endDisplayValue)).to.equal(0);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should change type progamatically', done => {
|
||||
// https://jsfiddle.net/hq7cLz83/
|
||||
vm = createVue({
|
||||
template: '<Date-picker :type="dateType"></Date-picker>',
|
||||
data() {
|
||||
return {
|
||||
dateType: 'month'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const picker = vm.$children[0];
|
||||
picker.handleFocus({type: 'focus'});
|
||||
vm.$nextTick(() => {
|
||||
const panel = vm.$el.querySelector('.ivu-picker-panel-content');
|
||||
const dayPanel = panel.querySelector('[class="ivu-date-picker-cells"]');
|
||||
const monthPanel = panel.querySelector('.ivu-date-picker-cells-month');
|
||||
const yearPanel = panel.querySelector('.ivu-date-picker-cells-year');
|
||||
|
||||
expect(dayPanel).to.equal(null);
|
||||
expect(monthPanel.style.display).to.equal('');
|
||||
expect(yearPanel).to.equal(null);
|
||||
|
||||
expect(picker.type).to.equal('month');
|
||||
expect(picker.selectionMode).to.equal('month');
|
||||
|
||||
vm.dateType = 'year';
|
||||
promissedTick(picker)
|
||||
.then(() => {
|
||||
const yearPanel = panel.querySelector('.ivu-date-picker-cells-year');
|
||||
const monthPanel = panel.querySelector('.ivu-date-picker-cells-month');
|
||||
expect(yearPanel.style.display).to.equal('');
|
||||
expect(monthPanel).to.equal(null);
|
||||
|
||||
expect(picker.type).to.equal('year');
|
||||
expect(picker.selectionMode).to.equal('year');
|
||||
|
||||
vm.dateType = 'date';
|
||||
return promissedTick(picker);
|
||||
})
|
||||
.then(() => {
|
||||
expect(picker.type).to.equal('date');
|
||||
expect(picker.selectionMode).to.equal('date');
|
||||
|
||||
done();
|
||||
}).catch(err => console.log(err));
|
||||
});
|
||||
});
|
||||
|
||||
it('should fire `on-change` when reseting value', done => {
|
||||
const now = new Date();
|
||||
const nowDate = dateToString(now);
|
||||
let onChangeCalled = false;
|
||||
vm = createVue({
|
||||
template: '<date-picker :value="date" type="date" @on-change="onChange"></date-picker>',
|
||||
data(){
|
||||
return { date: now };
|
||||
},
|
||||
methods: {
|
||||
onChange() {
|
||||
onChangeCalled = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
vm.$nextTick(() => {
|
||||
const picker = vm.$children[0];
|
||||
const displayField = vm.$el.querySelector('.ivu-input');
|
||||
expect(displayField.value).to.equal(nowDate);
|
||||
|
||||
picker.showClose = true; // to simulate mouseenter in the Input
|
||||
picker.handleIconClick(); // reset the input value
|
||||
vm.$nextTick(() => {
|
||||
expect(onChangeCalled).to.equal(true);
|
||||
expect(displayField.value).to.equal('');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should have same behavior after a reset as before the reset', done => {
|
||||
vm = createVue(`
|
||||
<Date-picker type="datetimerange"></Date-picker>
|
||||
`);
|
||||
|
||||
const picker = vm.$children[0];
|
||||
picker.handleFocus({type: 'focus'});
|
||||
vm.$nextTick(() => {
|
||||
const displayField = vm.$el.querySelector('.ivu-input');
|
||||
const clickableCells = vm.$el.querySelectorAll('.ivu-date-picker-cells-cell');
|
||||
const lastMonthClass = 'ivu-date-picker-cells-cell-prev-month';
|
||||
const firstDayInMonthIndex = [...clickableCells].findIndex(cell => !cell.classList.contains(lastMonthClass));
|
||||
|
||||
// choose first date
|
||||
clickableCells[firstDayInMonthIndex].firstElementChild.click();
|
||||
vm.$nextTick(() => {
|
||||
// choose second date
|
||||
clickableCells[firstDayInMonthIndex + 4].firstElementChild.click();
|
||||
vm.$nextTick(() => {
|
||||
// cache first values
|
||||
const [startInternalValue, endInternalValue] = picker.internalValue; // Date Objects
|
||||
const [startDisplayValue, endDisplayValue] = displayField.value.split(' - ').map(stringToDate); // Date Objects
|
||||
|
||||
// clear picker
|
||||
picker.handleClear();
|
||||
vm.$nextTick(() => {
|
||||
// it should be closed by now
|
||||
expect(picker.visible).to.equal(false);
|
||||
// open picker again
|
||||
picker.handleFocus({type: 'focus'});
|
||||
picker.visible = true;
|
||||
|
||||
|
||||
vm.$nextTick(() => {
|
||||
expect(picker.visible).to.equal(true);
|
||||
expect(JSON.stringify(picker.internalValue)).to.equal('[null,null]');
|
||||
expect(displayField.value).to.equal('');
|
||||
|
||||
clickableCells[firstDayInMonthIndex].firstElementChild.click();
|
||||
vm.$nextTick(() => {
|
||||
clickableCells[firstDayInMonthIndex + 4].firstElementChild.click();
|
||||
vm.$nextTick(() => {
|
||||
// recheck internal values
|
||||
expect(Math.abs(picker.internalValue[0] - startInternalValue)).to.equal(0);
|
||||
expect(Math.abs(picker.internalValue[1] - endInternalValue)).to.equal(0);
|
||||
// recheck display value
|
||||
const [_startDisplayValue, _endDisplayValue] = displayField.value.split(' - ').map(stringToDate); // Date Objects
|
||||
expect(Math.abs(_startDisplayValue - startDisplayValue)).to.equal(0);
|
||||
expect(Math.abs(_endDisplayValue - endDisplayValue)).to.equal(0);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should accept a empty string as input v-model value', done => {
|
||||
vm = createVue({
|
||||
template: '<date-picker v-model="value" type="date"></date-picker>',
|
||||
data(){
|
||||
return {value: ''};
|
||||
}
|
||||
});
|
||||
|
||||
vm.$nextTick(() => {
|
||||
expect(vm.value).to.equal('');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert strings to Date objects', done => {
|
||||
vm = createVue({
|
||||
template: `
|
||||
<div>
|
||||
<date-picker v-model="value1" type="daterange" style="width: 200px"></date-picker>
|
||||
<date-picker v-model="value2" type="daterange" placement="bottom-end" style="width: 200px"></date-picker>
|
||||
<date-picker v-model="value3" type="datetime" placement="bottom-end" style="width: 200px"></date-picker>
|
||||
<date-picker v-model="value4" type="datetimerange" placement="bottom-end" style="width: 200px"></date-picker>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
value1: ['2017-10-10', '2017-10-20'],
|
||||
value2: [new Date(), new Date()],
|
||||
value3: '2017-10-10 10:00:00',
|
||||
value4: ['2027-10-10 10:00:00', '2027-10-20 10:00:00']
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
vm.$nextTick(() => {
|
||||
const {value1, value2, value3, value4} = vm;
|
||||
|
||||
expect(value1[0] instanceof Date).to.equal(true);
|
||||
expect(value1[1] instanceof Date).to.equal(true);
|
||||
expect(value1.map(dateToString).join('|')).to.equal('2017-10-10|2017-10-20');
|
||||
|
||||
expect(value2[0] instanceof Date).to.equal(true);
|
||||
expect(value2[1] instanceof Date).to.equal(true);
|
||||
expect(value2.map(dateToString).join('|')).to.equal([new Date(), new Date()].map(dateToString).join('|'));
|
||||
|
||||
expect(dateToString(value3)).to.equal('2017-10-10');
|
||||
|
||||
expect(value4[0] instanceof Date).to.equal(true);
|
||||
expect(value4[1] instanceof Date).to.equal(true);
|
||||
expect(value4.map(dateToString).join('|')).to.equal('2027-10-10|2027-10-20');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should render date-picker label correctly in zh-CN', done => {
|
||||
vm = createVue(`
|
||||
<Date-picker type="date"></Date-picker>
|
||||
`);
|
||||
|
||||
const picker = vm.$children[0];
|
||||
picker.handleFocus({type: 'focus'});
|
||||
vm.$nextTick(() => {
|
||||
const now = new Date();
|
||||
const labels = vm.$el.querySelectorAll('.ivu-picker-panel-body .ivu-date-picker-header-label');
|
||||
const labelText = [...labels].map(el => el.textContent).join(' ');
|
||||
expect(labelText).to.equal([now.getFullYear() + '年', now.getMonth() + 1 + '月'].join(' '));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should format labels correctly', done => {
|
||||
const formater = require('../../../src/components/date-picker/util').formatDateLabels;
|
||||
const expectedResults = require('./assets/locale-expects.js').default;
|
||||
const locales = [
|
||||
'de-DE', 'en-US', 'es-ES', 'fi-FI', 'fr-FR', 'id-ID', 'ja-JP', 'ko-KR', 'pt-BR',
|
||||
'pt-PT', 'ru-RU', 'sv-SE', 'tr-TR', 'vi-VN', 'zh-CN', 'zh-TW'
|
||||
].reduce((obj, locale) => {
|
||||
obj[locale] = require('../../../src/locale/lang/' + locale).default;
|
||||
return obj;
|
||||
}, {});
|
||||
const testDate = new Date(2030, 9); // October 2030
|
||||
|
||||
Object.keys(locales).forEach(locale => {
|
||||
const format = locales[locale].i.datepicker.datePanelLabel;
|
||||
const f = formater(locale, format, testDate);
|
||||
const labelText = f.labels.map(obj => obj.label).join(f.separator);
|
||||
expect(labelText).to.equal(expectedResults[locale]);
|
||||
});
|
||||
expect(Object.keys(locales).length > 0).to.equal(true);
|
||||
done();
|
||||
});
|
||||
});
|
64
test/unit/specs/message.spec.js
Normal file
64
test/unit/specs/message.spec.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
import {createVue, destroyVM, waitForIt} from '../util';
|
||||
|
||||
describe('Message.vue', () => {
|
||||
let vm;
|
||||
afterEach(() => {
|
||||
destroyVM(vm);
|
||||
});
|
||||
|
||||
it('should open a info message by default', done => {
|
||||
vm = createVue({render: () => {}});
|
||||
const testMessage = 'Hello world!';
|
||||
let messageContainer = null;
|
||||
vm.$Message.info({
|
||||
content: testMessage,
|
||||
duration: 200 // too long so we can test
|
||||
});
|
||||
|
||||
const selector = '.ivu-message-notice-content-text .ivu-message-info';
|
||||
const checkMessageOpens = () => (messageContainer = document.querySelector(selector));
|
||||
|
||||
waitForIt(checkMessageOpens, function() {
|
||||
expect(messageContainer.textContent.trim()).to.equal(testMessage);
|
||||
messageContainer.parentElement.removeChild(messageContainer);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should open specific messages of different types', function(done) {
|
||||
vm = createVue({render: () => {}});
|
||||
const testMessage = type => `Hello world! this is a ${type} message`;
|
||||
const tests = ['info', 'success', 'warning', 'error', 'loading'].reduce((tests, type) => {
|
||||
return tests.concat({
|
||||
type: type,
|
||||
message: testMessage(type),
|
||||
class: 'ivu-message-' + type
|
||||
});
|
||||
}, []);
|
||||
let domElements = [];
|
||||
|
||||
for (const {type, message} of tests) {
|
||||
vm.$Message[type]({
|
||||
content: message,
|
||||
duration: 10 // long so we can test
|
||||
});
|
||||
}
|
||||
|
||||
const checkAllMessageOpens = () => {
|
||||
domElements = document.querySelectorAll('.ivu-message-custom-content');
|
||||
return domElements.length == tests.length && domElements;
|
||||
};
|
||||
|
||||
waitForIt(checkAllMessageOpens, function() {
|
||||
const verify = {};
|
||||
domElements.forEach(el => {
|
||||
const message = el.textContent.trim();
|
||||
const test = tests.find(test => test.message == message);
|
||||
verify[test.type] = true;
|
||||
expect(el.classList.contains(test.class)).to.equal(true);
|
||||
});
|
||||
expect(Object.keys(verify).length).to.equal(tests.length);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
460
test/unit/specs/select.spec.js
Normal file
460
test/unit/specs/select.spec.js
Normal file
|
@ -0,0 +1,460 @@
|
|||
import {createVue, destroyVM, waitForIt, promissedTick} from '../util';
|
||||
|
||||
describe('Select.vue', () => {
|
||||
let vm;
|
||||
afterEach(() => {
|
||||
destroyVM(vm);
|
||||
});
|
||||
|
||||
describe('Props tests', () => {
|
||||
it('should create a Select component with passed placeholder', done => {
|
||||
const placeholder = 'Hi! Select something!';
|
||||
vm = createVue({
|
||||
template: `
|
||||
<Select placeholder="${placeholder}">
|
||||
<Option v-for="item in options" :value="item.value" :key="item.value">{{ item.label }}</Option>
|
||||
</Select>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
value: '',
|
||||
options: [{value: 1, label: 'Foo'}, {value: 2, label: 'Bar'}]
|
||||
};
|
||||
}
|
||||
});
|
||||
vm.$nextTick(() => {
|
||||
const placeholderSpan = vm.$el.querySelector('.ivu-select-placeholder');
|
||||
expect(placeholderSpan.textContent).to.equal(placeholder);
|
||||
expect(placeholderSpan.style.display).to.not.equal('none');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a Select component and take a pre-selected value', done => {
|
||||
vm = createVue({
|
||||
template: `
|
||||
<Select :value="value">
|
||||
<Option v-for="item in options" :value="item.value" :key="item.value">{{ item.label }}</Option>
|
||||
</Select>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
value: 2,
|
||||
options: [{value: 1, label: 'Foo'}, {value: 2, label: 'Bar'}]
|
||||
};
|
||||
}
|
||||
});
|
||||
waitForIt(
|
||||
() => {
|
||||
const selectedValueSpan = vm.$el.querySelector('.ivu-select-selected-value');
|
||||
return selectedValueSpan && selectedValueSpan.textContent === 'Bar';
|
||||
},
|
||||
() => {
|
||||
const selectedValueSpan = vm.$el.querySelector('.ivu-select-selected-value');
|
||||
const {label, value} = vm.$children[0].values[0];
|
||||
|
||||
expect(selectedValueSpan.textContent).to.equal('Bar');
|
||||
expect(selectedValueSpan.style.display).to.not.equal('none');
|
||||
expect(label).to.equal('Bar');
|
||||
expect(value).to.equal(2);
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should accept normal characters', done => {
|
||||
vm = createVue({
|
||||
template: `
|
||||
<Select :value="2">
|
||||
<Option v-for="item in options" :value="item.value" :key="item.value">{{ item.label }}</Option>
|
||||
</Select>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
value: '',
|
||||
options: [{value: 1, label: '> 100$'}, {value: 2, label: '< 100$'}]
|
||||
};
|
||||
}
|
||||
});
|
||||
vm.$nextTick(() => {
|
||||
const selectedValueSpan = vm.$el.querySelector('.ivu-select-selected-value');
|
||||
expect(selectedValueSpan.textContent).to.equal('< 100$');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display normal characters in input when in filterable mode', done => {
|
||||
vm = createVue({
|
||||
template: `
|
||||
<Select v-model="value" filterable>
|
||||
<Option v-for="item in options" :value="item.value" :key="item.value">{{ item.label }}</Option>
|
||||
</Select>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
value: 2,
|
||||
options: [{value: 1, label: '> 100$'}, {value: 2, label: '< 100$'}]
|
||||
};
|
||||
}
|
||||
});
|
||||
vm.$nextTick(() => {
|
||||
const input = vm.$el.querySelector('.ivu-select-input');
|
||||
expect(input.value).to.equal('< 100$');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should use the value\'s label instead of placeholder when both are set', done => {
|
||||
vm = createVue({
|
||||
template: `
|
||||
<Select placeholder="Choose anything!" :value="2">
|
||||
<Option v-for="item in options" :value="item.value" :key="item.value">{{ item.label }}</Option>
|
||||
</Select>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
value: '',
|
||||
options: [{value: 1, label: 'Foo'}, {value: 2, label: 'Bar'}]
|
||||
};
|
||||
}
|
||||
});
|
||||
waitForIt(
|
||||
() => {
|
||||
const selectedValueSpan = vm.$el.querySelector('.ivu-select-selected-value');
|
||||
return selectedValueSpan && selectedValueSpan.textContent === 'Bar';
|
||||
},
|
||||
() => {
|
||||
const placeholderSpan = vm.$el.querySelector('.ivu-select-placeholder');
|
||||
const selectedValueSpan = vm.$el.querySelector('.ivu-select-selected-value');
|
||||
expect(placeholderSpan).to.equal(null);
|
||||
expect(!!selectedValueSpan.style.display).to.not.equal('none');
|
||||
expect(selectedValueSpan.textContent).to.equal('Bar');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should set different classes for different sizes', done => {
|
||||
vm = createVue(`
|
||||
<div>
|
||||
<Select placeholder="Choose anything!"><Option v-for="item in []" :value="item" :key="item">{{item}}</Option></Select>
|
||||
<Select placeholder="Choose anything!" size="large"><Option v-for="item in []" :value="item" :key="item">{{item}}</Option></Select>
|
||||
<Select placeholder="Choose anything!" size="small"><Option v-for="item in []" :value="item" :key="item">{{item}}</Option></Select>
|
||||
</div>
|
||||
`);
|
||||
vm.$nextTick(() => {
|
||||
const [defaultSelect, largeSelect, smallSelect] = [...vm.$el.querySelectorAll('.ivu-select')];
|
||||
expect(defaultSelect.className).to.equal('ivu-select ivu-select-single ivu-select-default');
|
||||
expect(largeSelect.classList.contains('ivu-select-large')).to.equal(true);
|
||||
expect(smallSelect.classList.contains('ivu-select-small')).to.equal(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should set new options', done => {
|
||||
const laterOptions = [{value: 1, label: 'Foo'}, {value: 2, label: 'Bar'}];
|
||||
|
||||
vm = createVue({
|
||||
template: `
|
||||
<Select>
|
||||
<Option v-for="item in options" :value="item.value" :key="item.value">{{ item.label }}</Option>
|
||||
</Select>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
value: '',
|
||||
options: []
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => (this.options = laterOptions));
|
||||
}
|
||||
});
|
||||
const condition = function() {
|
||||
const componentOptions = vm.$children[0].flatOptions;
|
||||
return componentOptions && componentOptions.length > 0;
|
||||
};
|
||||
const callback = function() {
|
||||
const renderedOptions = vm.$el.querySelectorAll('.ivu-select-dropdown-list li');
|
||||
expect(renderedOptions.length).to.equal(laterOptions.length);
|
||||
|
||||
const labels = [...renderedOptions].map(el => el.textContent).join('<>');
|
||||
const expected = laterOptions.map(o => o.label).join('<>');
|
||||
expect(labels).to.equal(expected);
|
||||
done();
|
||||
};
|
||||
waitForIt(condition, callback);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Behavior tests', () => {
|
||||
it('should create different and independent instances', done => {
|
||||
const options = [
|
||||
{value: 'beijing', label: 'Beijing'},
|
||||
{value: 'stockholm', label: 'Stockholm'},
|
||||
{value: 'lisboa', label: 'Lisboa'}
|
||||
];
|
||||
|
||||
vm = createVue({
|
||||
template: `
|
||||
<div>
|
||||
<i-select v-model="modelA" multiple style="width:260px">
|
||||
<i-option v-for="item in cityList" :value="item.value" :key="item.value">{{ item.label }}</i-option>
|
||||
</i-select>
|
||||
<i-select v-model="modelB" multiple style="width:260px">
|
||||
<i-option v-for="item in cityList" :value="item.value" :key="item.value">{{ item.label }}</i-option>
|
||||
</i-select>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
cityList: [],
|
||||
modelA: [],
|
||||
modelB: []
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
setTimeout(() => (this.cityList = options), 200);
|
||||
}
|
||||
});
|
||||
const [SelectA, SelectB] = vm.$children;
|
||||
SelectA.toggleMenu(null, true);
|
||||
SelectB.toggleMenu(null, true);
|
||||
|
||||
new Promise(resolve => {
|
||||
const condition = function() {
|
||||
const optionsA = SelectA.$el.querySelectorAll('.ivu-select-item');
|
||||
const optionsB = SelectB.$el.querySelectorAll('.ivu-select-item');
|
||||
return optionsA.length > 0 && optionsB.length > 0;
|
||||
};
|
||||
waitForIt(condition, resolve);
|
||||
})
|
||||
.then(() => {
|
||||
// click in A options
|
||||
const optionsA = SelectA.$el.querySelectorAll('.ivu-select-item');
|
||||
optionsA[0].click();
|
||||
return promissedTick(SelectA);
|
||||
})
|
||||
.then(() => {
|
||||
expect(SelectA.value[0]).to.equal(options[0].value);
|
||||
expect(SelectA.value.length).to.equal(1);
|
||||
expect(SelectB.value.length).to.equal(0);
|
||||
|
||||
// click in B options
|
||||
const optionsB = SelectB.$el.querySelectorAll('.ivu-select-item');
|
||||
optionsB[1].click();
|
||||
optionsB[2].click();
|
||||
return promissedTick(SelectB);
|
||||
})
|
||||
.then(() => {
|
||||
// lets check the values!
|
||||
const getSelections = component => {
|
||||
const tags = component.$el.querySelectorAll('.ivu-select-selection .ivu-tag');
|
||||
return [...tags].map(el => el.textContent.trim()).join(',');
|
||||
};
|
||||
const selectAValue = getSelections(SelectA);
|
||||
const selectBValue = getSelections(SelectB);
|
||||
|
||||
expect(selectAValue).to.equal(options[0].label);
|
||||
expect(selectBValue).to.equal(options.slice(1, 3).map(obj => obj.label.trim()).join(','));
|
||||
|
||||
done();
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
done(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('should create update model with value, and label when asked', done => {
|
||||
const options = [
|
||||
{value: 'beijing', label: 'Beijing'},
|
||||
{value: 'stockholm', label: 'Stockholm'},
|
||||
{value: 'lisboa', label: 'Lisboa'}
|
||||
];
|
||||
let onChangeValueA, onChangeValueB;
|
||||
|
||||
|
||||
vm = createVue({
|
||||
template: `
|
||||
<div>
|
||||
<i-select v-model="modelA" style="width:260px" @on-change="onChangeA">
|
||||
<i-option v-for="item in cityList" :value="item.value" :key="item.value">{{ item.label }}</i-option>
|
||||
</i-select>
|
||||
<i-select v-model="modelB" label-in-value style="width:260px" @on-change="onChangeB">
|
||||
<i-option v-for="item in cityList" :value="item.value" :key="item.value">{{ item.label }}</i-option>
|
||||
</i-select>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
cityList: options,
|
||||
modelA: [],
|
||||
modelB: []
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onChangeA(val){
|
||||
onChangeValueA = val;
|
||||
},
|
||||
onChangeB(val){
|
||||
onChangeValueB = val;
|
||||
}
|
||||
}
|
||||
});
|
||||
const [SelectA, SelectB] = vm.$children;
|
||||
SelectA.toggleMenu(null, true);
|
||||
SelectB.toggleMenu(null, true);
|
||||
|
||||
|
||||
new Promise(resolve => {
|
||||
const condition = function() {
|
||||
const optionsA = SelectA.$el.querySelectorAll('.ivu-select-item');
|
||||
const optionsB = SelectB.$el.querySelectorAll('.ivu-select-item');
|
||||
return optionsA.length > 0 && optionsB.length > 0;
|
||||
};
|
||||
waitForIt(condition, resolve);
|
||||
})
|
||||
.then(() => {
|
||||
// click in A options
|
||||
const optionsA = SelectA.$el.querySelectorAll('.ivu-select-item');
|
||||
optionsA[0].click();
|
||||
return promissedTick(SelectA);
|
||||
})
|
||||
.then(() => {
|
||||
expect(vm.modelA).to.equal(options[0].value);
|
||||
expect(onChangeValueA).to.equal(options[0].value);
|
||||
|
||||
// click in B options
|
||||
const optionsB = SelectB.$el.querySelectorAll('.ivu-select-item');
|
||||
optionsB[2].click();
|
||||
return promissedTick(SelectB);
|
||||
})
|
||||
.then(() => {
|
||||
expect(vm.modelB).to.equal(options[2].value);
|
||||
expect(JSON.stringify(onChangeValueB)).to.equal(JSON.stringify(options[2]));
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Public API', () => {
|
||||
it('The "setQuery" method should behave as expected', (done) => {
|
||||
|
||||
const options = [
|
||||
{value: 'beijing', label: 'Beijing'},
|
||||
{value: 'stockholm', label: 'Stockholm'},
|
||||
{value: 'lisboa', label: 'Lisboa'}
|
||||
];
|
||||
|
||||
vm = createVue({
|
||||
template: `
|
||||
<Select v-model="value" filterable>
|
||||
<Option v-for="item in options" :value="item.value" :key="item.value">{{ item.label }}</Option>
|
||||
</Select>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
value: '',
|
||||
options: options
|
||||
};
|
||||
}
|
||||
});
|
||||
const [Select] = vm.$children;
|
||||
Select.setQuery('i');
|
||||
vm.$nextTick(() => {
|
||||
const query = 'i';
|
||||
const input = vm.$el.querySelector('.ivu-select-input');
|
||||
expect(input.value).to.equal(query);
|
||||
|
||||
const renderedOptions = [...vm.$el.querySelectorAll('.ivu-select-item')].map(el => el.textContent);
|
||||
const filteredOptions = options.filter(option => JSON.stringify(option).includes(query)).map(({label}) => label);
|
||||
expect(JSON.stringify(renderedOptions)).to.equal(JSON.stringify(filteredOptions));
|
||||
|
||||
// reset query
|
||||
// setQuery(null) should clear the select
|
||||
Select.setQuery(null);
|
||||
vm.$nextTick(() => {
|
||||
const input = vm.$el.querySelector('.ivu-select-input');
|
||||
expect(input.value).to.equal('');
|
||||
|
||||
const renderedOptions = [...vm.$el.querySelectorAll('.ivu-select-item')].map(el => el.textContent);
|
||||
expect(JSON.stringify(renderedOptions)).to.equal(JSON.stringify(options.map(({label}) => label)));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('The "clearSingleSelect" method should behave as expected', (done) => {
|
||||
|
||||
// clearSingleSelect
|
||||
const options = [
|
||||
{value: 'beijing', label: 'Beijing'},
|
||||
{value: 'stockholm', label: 'Stockholm'},
|
||||
{value: 'lisboa', label: 'Lisboa'}
|
||||
];
|
||||
const preSelected = 'lisboa';
|
||||
|
||||
vm = createVue({
|
||||
template: `
|
||||
<Select v-model="value" clearable>
|
||||
<Option v-for="item in options" :value="item.value" :key="item.value">{{ item.label }}</Option>
|
||||
</Select>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
value: preSelected,
|
||||
options: options
|
||||
};
|
||||
}
|
||||
});
|
||||
const [Select] = vm.$children;
|
||||
vm.$nextTick(() => {
|
||||
expect(Select.publicValue).to.equal(preSelected);
|
||||
Select.clearSingleSelect();
|
||||
expect(typeof Select.publicValue).to.equal('undefined');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Performance tests', () => {
|
||||
it('should handle big numbers of options', done => {
|
||||
const manyLaterOptions = Array.apply(null, Array(200)).map((_, i) => {
|
||||
return {
|
||||
value: i + 1,
|
||||
label: Math.random().toString(36).slice(2).toUpperCase()
|
||||
};
|
||||
});
|
||||
const start = +new Date();
|
||||
vm = createVue({
|
||||
template: `
|
||||
<Select>
|
||||
<Option v-for="item in options" :value="item.value" :key="item.value">{{ item.label }}</Option>
|
||||
</Select>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
value: '',
|
||||
options: []
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => (this.options = manyLaterOptions));
|
||||
}
|
||||
});
|
||||
const condition = function() {
|
||||
const componentOptions = vm.$children[0].flatOptions;
|
||||
return componentOptions && componentOptions.length === manyLaterOptions.length;
|
||||
};
|
||||
const callback = function() {
|
||||
const end = +new Date();
|
||||
const renderedOptions = vm.$el.querySelectorAll('.ivu-select-dropdown-list li');
|
||||
expect(renderedOptions.length).to.equal(manyLaterOptions.length);
|
||||
expect(end - start).to.be.not.above(1000);
|
||||
done();
|
||||
};
|
||||
waitForIt(condition, callback);
|
||||
});
|
||||
});
|
||||
});
|
47
test/unit/specs/table.spec.js
Normal file
47
test/unit/specs/table.spec.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { createVue, destroyVM } from '../util';
|
||||
import { csvA, csvB } from './assets/table/csvData.js';
|
||||
|
||||
const cleanCSV = (str) => str.split('\n').map(s => s.trim()).filter(Boolean).join('\n');
|
||||
|
||||
describe('Table.vue', () => {
|
||||
let vm;
|
||||
afterEach(() => {
|
||||
destroyVM(vm);
|
||||
});
|
||||
|
||||
describe('CSV export', () => {
|
||||
it('should export simple data to CSV - test A', done => {
|
||||
vm = createVue({
|
||||
template: '<div><Table :columns="columns" :data="data" ref="tableA" /></div>',
|
||||
data() {
|
||||
return csvA;
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.tableA.exportCsv({callback: data => {
|
||||
expect(cleanCSV(data)).to.equal(cleanCSV(this.expected));
|
||||
expect(cleanCSV(data).length > 0).to.equal(true);
|
||||
done();
|
||||
}});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should export data with commas and line breaks to CSV - test B', done => {
|
||||
vm = createVue({
|
||||
template: '<div><Table :columns="columns" :data="data" ref="tableB" /></div>',
|
||||
data() {
|
||||
return csvB;
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.tableB.exportCsv({separator: ';', quoted: true, callback: data => {
|
||||
expect(cleanCSV(data)).to.equal(cleanCSV(this.expected));
|
||||
expect(cleanCSV(data).length > 0).to.equal(true);
|
||||
done();
|
||||
}});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
60
test/unit/specs/time-spinner.spec.js
Normal file
60
test/unit/specs/time-spinner.spec.js
Normal file
|
@ -0,0 +1,60 @@
|
|||
import { createVue, destroyVM } from '../util';
|
||||
|
||||
describe('TimePicker.vue', () => {
|
||||
let vm;
|
||||
afterEach(() => {
|
||||
destroyVM(vm);
|
||||
});
|
||||
|
||||
it('should create a TimePicker component with hours, minutes and seconds', done => {
|
||||
vm = createVue(`
|
||||
<Time-Picker></Time-Picker>
|
||||
`);
|
||||
const picker = vm.$children[0];
|
||||
picker.handleFocus({type: 'focus'}); // open the picker panels
|
||||
|
||||
vm.$nextTick(() => {
|
||||
const spiners = picker.$el.querySelectorAll('.ivu-time-picker-cells-list');
|
||||
expect(spiners.length).to.equal(3); // hh:mm:ss
|
||||
expect(spiners[0].querySelectorAll('.ivu-time-picker-cells-cell').length).to.equal(24);
|
||||
expect(spiners[1].querySelectorAll('.ivu-time-picker-cells-cell').length).to.equal(60);
|
||||
expect(spiners[2].querySelectorAll('.ivu-time-picker-cells-cell').length).to.equal(60);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a TimePicker component with only hours and minutes', done => {
|
||||
vm = createVue(`
|
||||
<Time-Picker format="HH:mm"></Time-Picker>
|
||||
`);
|
||||
const picker = vm.$children[0];
|
||||
picker.handleFocus({type: 'focus'}); // open the picker panels
|
||||
|
||||
vm.$nextTick(() => {
|
||||
const spiners = picker.$el.querySelectorAll('.ivu-time-picker-cells-list');
|
||||
expect([...spiners].filter(el => el.style.display != 'none').length).to.equal(2); // hh:mm
|
||||
expect(spiners[0].querySelectorAll('.ivu-time-picker-cells-cell').length).to.equal(24);
|
||||
expect(spiners[1].querySelectorAll('.ivu-time-picker-cells-cell').length).to.equal(60);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a TimePicker component with steps of 15 minutes', done => {
|
||||
vm = createVue(`
|
||||
<Time-Picker :steps="[1, 15]"></Time-Picker>
|
||||
`);
|
||||
const picker = vm.$children[0];
|
||||
picker.handleFocus({type: 'focus'}); // open the picker panels
|
||||
|
||||
vm.$nextTick(() => {
|
||||
const spiners = picker.$el.querySelectorAll('.ivu-time-picker-cells-list');
|
||||
const minutesList = [...spiners[1].querySelectorAll('.ivu-time-picker-cells-cell')];
|
||||
|
||||
expect(spiners[0].querySelectorAll('.ivu-time-picker-cells-cell').length).to.equal(24);
|
||||
expect(minutesList.map(el => el.textContent).join(',')).to.equal('00,15,30,45');
|
||||
expect(spiners[1].querySelectorAll('.ivu-time-picker-cells-cell').length).to.equal(4);
|
||||
expect(spiners[2].querySelectorAll('.ivu-time-picker-cells-cell').length).to.equal(60);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue