Merge pull request #538 from QingWei-Li/test/unit/popover

Popover: add test
pull/540/head
baiyaaaaa 2016-10-20 15:57:09 +08:00 committed by GitHub
commit d4ec462340
8 changed files with 280 additions and 59 deletions

View File

@ -1,4 +1,4 @@
.PHONY: dist .PHONY: dist test
default: help default: help
# build all theme # build all theme

View File

@ -1,8 +1,14 @@
const Popover = require('./src/main'); const Popover = require('./src/main');
const directive = require('./src/directive').default;
const Vue = require('vue');
Vue.directive('popover', directive);
/* istanbul ignore next */ /* istanbul ignore next */
Popover.install = function(Vue) { Popover.install = function(Vue) {
Vue.directive('popover', directive);
Vue.component(Popover.name, Popover); Vue.component(Popover.name, Popover);
}; };
Popover.directive = directive;
module.exports = Popover; module.exports = Popover;

View File

@ -0,0 +1,5 @@
export default {
bind(el, binding, vnode) {
vnode.context.$refs[binding.arg].$refs.reference = el;
}
};

View File

@ -17,15 +17,8 @@
<script> <script>
import Popper from 'element-ui/src/utils/vue-popper'; import Popper from 'element-ui/src/utils/vue-popper';
import Vue from 'vue';
import { on, off } from 'wind-dom/src/event'; import { on, off } from 'wind-dom/src/event';
Vue.directive('popover', {
bind(el, binding, vnode) {
vnode.context.$refs[binding.arg].$refs.reference = el;
}
});
export default { export default {
name: 'el-popover', name: 'el-popover',
@ -52,55 +45,63 @@ export default {
}, },
mounted() { mounted() {
let _timer; let reference = this.reference || this.$refs.reference;
const reference = this.reference || this.$refs.reference || this.$slots.reference[0].elm;
const popper = this.popper || this.$refs.popper; const popper = this.popper || this.$refs.popper;
this.$nextTick(() => { if (!reference && this.$slots.reference && this.$slots.reference[0]) {
if (this.trigger === 'click') { reference = this.$slots.reference[0].elm;
on(reference, 'click', () => { this.showPopper = !this.showPopper; }); }
on(document, 'click', (e) => { if (this.trigger === 'click') {
if (!this.$el || on(reference, 'click', () => { this.showPopper = !this.showPopper; });
!reference || on(document, 'click', (e) => {
this.$el.contains(e.target) || if (!this.$el ||
reference.contains(e.target) || !reference ||
!popper || this.$el.contains(e.target) ||
popper.contains(e.target)) return; reference.contains(e.target) ||
this.showPopper = false; !popper ||
}); popper.contains(e.target)) return;
} else if (this.trigger === 'hover') { this.showPopper = false;
on(reference, 'mouseenter', () => { });
this.showPopper = true; } else if (this.trigger === 'hover') {
clearTimeout(_timer); on(reference, 'mouseenter', this.handleMouseEnter);
}); on(popper, 'mouseenter', this.handleMouseEnter);
on(reference, 'mouseleave', () => { on(reference, 'mouseleave', this.handleMouseLeave);
_timer = setTimeout(() => { on(popper, 'mouseleave', this.handleMouseLeave);
this.showPopper = false; } else {
}, 200); if ([].slice.call(reference.children).length) {
}); const children = reference.childNodes;
} else {
if ([].slice.call(reference.children).length) {
const children = reference.childNodes;
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
if (children[i].nodeName === 'INPUT') { if (children[i].nodeName === 'INPUT' ||
on(children[i], 'focus', () => { this.showPopper = true; }); children[i].nodeName === 'TEXTAREA') {
on(children[i], 'blur', () => { this.showPopper = false; }); on(children[i], 'focus', () => { this.showPopper = true; });
break; on(children[i], 'blur', () => { this.showPopper = false; });
} break;
} }
} else if (
reference.nodeName === 'INPUT' ||
reference.nodeName === 'TEXTAREA'
) {
on(reference, 'focus', () => { this.showPopper = true; });
on(reference, 'blur', () => { this.showPopper = false; });
} else {
on(reference, 'mousedown', () => { this.showPopper = true; });
on(reference, 'mouseup', () => { this.showPopper = false; });
} }
} else if (
reference.nodeName === 'INPUT' ||
reference.nodeName === 'TEXTAREA'
) {
on(reference, 'focus', () => { this.showPopper = true; });
on(reference, 'blur', () => { this.showPopper = false; });
} else {
on(reference, 'mousedown', () => { this.showPopper = true; });
on(reference, 'mouseup', () => { this.showPopper = false; });
} }
}); }
},
methods: {
handleMouseEnter() {
this.showPopper = true;
clearTimeout(this._timer);
},
handleMouseLeave() {
this._timer = setTimeout(() => {
this.showPopper = false;
}, 200);
}
}, },
destroyed() { destroyed() {

View File

@ -19,8 +19,8 @@ export default {
type: Number, type: Number,
default: 5 default: 5
}, },
reference: Object, reference: {},
popper: Object, popper: {},
offset: { offset: {
default: 0 default: 0
}, },
@ -73,7 +73,6 @@ export default {
const reference = this.referenceElm = this.referenceElm || this.reference || this.$refs.reference || this.$slots.reference[0].elm; const reference = this.referenceElm = this.referenceElm || this.reference || this.$refs.reference || this.$slots.reference[0].elm;
if (!popper || !reference) return; if (!popper || !reference) return;
if (this.visibleArrow) this.appendArrow(popper); if (this.visibleArrow) this.appendArrow(popper);
if (this.appendToBody) document.body.appendChild(this.popperElm); if (this.appendToBody) document.body.appendChild(this.popperElm);
if (this.popperJS && this.popperJS.hasOwnProperty('destroy')) { if (this.popperJS && this.popperJS.hasOwnProperty('destroy')) {

View File

@ -0,0 +1,196 @@
import { createVue, triggerEvent, createTest } from '../util';
import Popover, { directive } from 'packages/popover';
describe('Popover', () => {
describe('trigger', () => {
const createVM = (trigger) => {
return createVue(`
<div>
<el-popover
ref="popover"
trigger="${trigger}"
content="content">
<button slot="reference">trigger ${trigger}</button>
</el-popover>
</div>
`, true);
};
it('click', () => {
const vm = createVM('click');
const compo = vm.$refs.popover;
vm.$el.querySelector('button').click();
expect(compo.showPopper).to.true;
document.body.click();
expect(compo.showPopper).to.false;
});
it('hover', done => {
const vm = createVM('hover');
const compo = vm.$refs.popover;
const button = vm.$el.querySelector('button');
triggerEvent(button, 'mouseenter');
expect(compo.showPopper).to.true;
triggerEvent(button, 'mouseleave');
setTimeout(_ => {
expect(compo.showPopper).to.false;
done();
}, 250); // 代码里是 200ms
});
it('focus input in children node', () => {
const vm = createVue(`
<div>
<el-popover
ref="popover"
trigger="focus"
content="content">
<div slot="reference">
<input type="text" value="trigger focus" />
</div>
</el-popover>
</div>
`, true);
const compo = vm.$refs.popover;
const input = vm.$el.querySelector('input');
input.focus();
expect(compo.showPopper).to.true;
input.blur();
expect(compo.showPopper).to.false;
});
it('focus textarea in children node', () => {
const vm = createVue(`
<div>
<el-popover
ref="popover"
trigger="focus"
content="content">
<div slot="reference">
<textarea></textarea>
</div>
</el-popover>
</div>
`, true);
const compo = vm.$refs.popover;
const textarea = vm.$el.querySelector('textarea');
textarea.focus();
expect(compo.showPopper).to.true;
textarea.blur();
expect(compo.showPopper).to.false;
});
it('focus input', () => {
const vm = createVue(`
<div>
<el-popover
ref="popover"
trigger="focus"
content="content">
<input type="text" slot="reference" value="trigger focus" />
</el-popover>
</div>
`, true);
const compo = vm.$refs.popover;
const input = vm.$el.querySelector('input');
input.focus();
expect(compo.showPopper).to.true;
input.blur();
expect(compo.showPopper).to.false;
});
it('focus button', () => {
const vm = createVM('focus');
const compo = vm.$refs.popover;
const button = vm.$el.querySelector('button');
triggerEvent(button, 'mousedown');
expect(compo.showPopper).to.true;
triggerEvent(button, 'mouseup');
expect(compo.showPopper).to.false;
});
});
describe('create by directive', () => {
const vm = createVue({
template: `
<div>
<el-popover
ref="popover1"
trigger="click"
content="content">
</el-popover>
<button v-popover:popover1>create by directive</button>
</div>
`,
directives: {
Popover: directive
}
}, true);
const compo = vm.$refs.popover1;
it('render', () => {
expect(vm.$el.querySelector('.el-popover')).to.have.deep.property('textContent').include('content');
});
it('triggering click', done => {
vm.$el.querySelector('button').click();
expect(compo.popperElm).to.not.exist;
vm.$nextTick(_ => {
expect(compo).to.have.deep.property('popperElm.style.display').not.equal('none');
done();
});
});
it('click outside', () => {
document.body.click();
expect(compo.showPopper).to.false;
});
});
describe('create by slot', () => {
const vm = createVue(`
<div>
<el-popover
ref="popover"
trigger="click"
content="content">
<button slot="reference">create by slot</button>
</el-popover>
</div>
`, true);
const compo = vm.$refs.popover;
it('render', () => {
expect(vm.$el.querySelector('.el-popover')).to.have.deep.property('textContent').include('content');
});
it('triggering click', done => {
vm.$el.querySelector('button').click();
expect(compo.popperElm).to.not.exist;
vm.$nextTick(_ => {
expect(compo).to.have.deep.property('popperElm.style.display').not.equal('none');
done();
});
});
it('click outside', () => {
document.body.click();
expect(compo.showPopper).to.false;
});
});
it('destroy event', () => {
const vm = createTest(Popover, {
reference: document.createElement('div'),
popper: document.createElement('div')
});
expect(() => vm.$destroy(true)).not.throw();
});
});

View File

@ -7,8 +7,7 @@ describe('Tooltip', () => {
<button>click</button> <button>click</button>
</el-tooltip>`); </el-tooltip>`);
expect(vm.$el.querySelector('.el-tooltip__popper')).to.exist; expect(vm.$el.querySelector('.el-tooltip__popper')).to.have.property('textContent', '提示文字');
expect(vm.$el.querySelector('.el-tooltip__popper').textContent).to.equal('提示文字');
}); });
it('hover', done => { it('hover', done => {
@ -24,14 +23,13 @@ describe('Tooltip', () => {
expect(tooltip.popperElm).to.not.exist; expect(tooltip.popperElm).to.not.exist;
setTimeout(_ => { setTimeout(_ => {
expect(tooltip.popperElm).to.exist; expect(tooltip).to.have.deep.property('popperElm.style.display').not.equal('none');
expect(tooltip.popperElm.style.display).to.not.equal('none');
// trigger mouseleave // trigger mouseleave
tooltip.handleClosePopper(); tooltip.handleClosePopper();
setTimeout(_ => { setTimeout(_ => {
expect(tooltip.popperElm.style.display).to.equal('none'); expect(tooltip).to.have.deep.property('popperElm.style.display', 'none');
done(); done();
}, 500); }, 500);
}, 150); }, 150);

View File

@ -46,3 +46,19 @@ exports.createTest = function(Compo, propsData = {}, mounted = false) {
const Ctor = Vue.extend(Compo); const Ctor = Vue.extend(Compo);
return new Ctor({ propsData }).$mount(mounted === false ? null : elm); return new Ctor({ propsData }).$mount(mounted === false ? null : elm);
}; };
/**
* 触发一个事件
* mouseenter, mouseleave, mouseover
* @param {Element} elm
* @param {EventName} name
* @param {options} opts
*/
exports.triggerEvent = function(elm, name, opts) {
const evt = document.createEvent('MouseEvents');
evt.initEvent(name, ...opts);
elm.dispatchEvent
? elm.dispatchEvent(evt)
: elm.fireEvent('on' + name, evt);
};