From dbaf83e2a4d8a1b71c994dfe43ac2cbeaa5e9c26 Mon Sep 17 00:00:00 2001 From: hangzou Date: Thu, 13 Aug 2020 15:16:38 +0800 Subject: [PATCH] Feat/checkbox (#131) * feat(checkbox): init checkbox * feat(checkbox): update checkbox-button checkbox-group * feat(checkbox): init unit test * feat(checkbox): update unit test * fix(checkbox): improve some code * test(checkbox): update test case --- .eslintrc.js | 1 + packages/checkbox/__tests__/checkbox.spec.ts | 387 +++++++++++++++++++ packages/checkbox/doc/basic.vue | 36 ++ packages/checkbox/doc/group.vue | 77 ++++ packages/checkbox/doc/index.stories.ts | 6 + packages/checkbox/index.ts | 10 + packages/checkbox/package.json | 12 + packages/checkbox/src/checkbox-button.vue | 200 ++++++++++ packages/checkbox/src/checkbox-group.vue | 82 ++++ packages/checkbox/src/checkbox.vue | 222 +++++++++++ packages/checkbox/src/useCheckbox.ts | 24 ++ packages/element-plus/index.ts | 3 + packages/element-plus/package.json | 1 - packages/rate/__tests__/rate.spec.ts | 20 +- 14 files changed, 1079 insertions(+), 2 deletions(-) create mode 100644 packages/checkbox/__tests__/checkbox.spec.ts create mode 100644 packages/checkbox/doc/basic.vue create mode 100644 packages/checkbox/doc/group.vue create mode 100644 packages/checkbox/doc/index.stories.ts create mode 100644 packages/checkbox/index.ts create mode 100644 packages/checkbox/package.json create mode 100644 packages/checkbox/src/checkbox-button.vue create mode 100644 packages/checkbox/src/checkbox-group.vue create mode 100644 packages/checkbox/src/checkbox.vue create mode 100644 packages/checkbox/src/useCheckbox.ts diff --git a/.eslintrc.js b/.eslintrc.js index 2a75a2a49d..0d7edba6c1 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -54,5 +54,6 @@ module.exports = { ], '@typescript-eslint/explicit-module-boundary-types': 'off', 'vue/html-closing-bracket-spacing': 'error', + '@typescript-eslint/no-explicit-any': 0, }, } diff --git a/packages/checkbox/__tests__/checkbox.spec.ts b/packages/checkbox/__tests__/checkbox.spec.ts new file mode 100644 index 0000000000..6129629b82 --- /dev/null +++ b/packages/checkbox/__tests__/checkbox.spec.ts @@ -0,0 +1,387 @@ +import { mount } from '@vue/test-utils' +import Checkbox from '../src/checkbox.vue' +import CheckboxButton from '../src/checkbox-button.vue' +import CheckboxGroup from '../src/checkbox-group.vue' + +const _mount = (template: string, data, otherObj?) => mount({ + components: { + 'el-checkbox': Checkbox, + 'el-checkbox-group': CheckboxGroup, + 'el-checkbox-button': CheckboxButton, + }, + template, + data, + ...otherObj, +}, { + global: { + provide: { + elForm: {}, + elFormItem: {}, + CheckboxGroup: {}, + }, + }, +}) + +describe('Checkbox', () => { + test('create', async (done) => { + const wrapper = _mount('', () => ({ checkbox: false })) + const vm = wrapper.vm + expect(wrapper.classes()).toContain('el-checkbox') + await wrapper.trigger('click') + vm.$nextTick(async () => { + expect(wrapper.classes()).toContain('is-checked') + await wrapper.trigger('click') + expect(wrapper.classes('is-checked')).toBe(false) + done() + }) + }) + + test('disabled', async (done) => { + const wrapper = _mount('', () => ({ checkbox: false })) + const vm = wrapper.vm + expect(wrapper.classes()).toContain('is-disabled') + await wrapper.trigger('click') + vm.$nextTick(() => { + expect(wrapper.classes()).toContain('is-disabled') + done() + }) + }) + + test('change event', async (done) => { + const wrapper = _mount( + ` + + `, + () => ({ + data: '', + checked: false, + }), + { + methods: { + onChange(val) { + this.data = val + }, + }, + }, + ) + + const vm = wrapper.vm + + await wrapper.trigger('click') + vm.$nextTick(() => { + expect(vm.data).toBe(true) + done() + }) + }) + + test('checkbox group', async (done) => { + const wrapper = _mount( + ` + + + + + + + `, + () => ({ checkList: [] }), + ) + const vm = wrapper.vm + expect(vm.checkList.length).toBe(0) + await wrapper.findComponent({ ref: 'a' }).trigger('click') + vm.$nextTick(async () => { + expect(vm.checkList.length).toBe(1) + expect(vm.checkList).toContain('a') + await wrapper.findComponent({ ref: 'b' }).trigger('click') + vm.$nextTick(() => { + expect(vm.checkList.length).toBe(2) + expect(vm.checkList).toContain('a') + expect(vm.checkList).toContain('b') + done() + }) + }) + }) + + test('checkbox group change', async done => { + const wrapper = _mount( + ` + + + + + `, + () => ({ checkList: [] }), + { + methods: { + onChange(val) { + this.data = val + }, + }, + }, + ) + const vm = wrapper.vm + await wrapper.findComponent({ ref: 'a' }).trigger('click') + vm.$nextTick(() => { + expect(vm.data.length).toBe(1) + expect(vm.data).toEqual(['a']) + done() + }) + }) + + test('nested group', async done => { + const wrapper = _mount( + ` + +
+ + + + +
+
+ `, + () => ({ checkList: [] }), + ) + const vm = wrapper.vm + expect(vm.checkList.length).toBe(0) + await wrapper.findComponent({ ref: 'a' }).trigger('click') + vm.$nextTick(() => { + expect(vm.checkList).toEqual(['a']) + done() + }) + }) + + test('true false lable', async done => { + const wrapper = _mount( + ``, + () => ({ + checked: 'a', + }), + ) + const vm = wrapper.vm + await wrapper.trigger('click') + vm.$nextTick(() => { + expect((vm as any).checked).toBe(3) + done() + }) + }) + + test('check', () => { + const wrapper = _mount( + ` +
+ + + + +
+ `, + () => ({ + checked: false, + checklist: [], + }), + ) as any + expect(wrapper.vm.checked).toBe(true) + expect(wrapper.vm.checklist).toEqual(['a']) + }) +}) + +describe('check-button', () => { + test('create', async (done) => { + const wrapper = _mount('', () => ({ checkbox: false })) + const vm = wrapper.vm + expect(wrapper.classes()).toContain('el-checkbox-button') + await wrapper.trigger('click') + vm.$nextTick(async () => { + expect(wrapper.classes()).toContain('is-checked') + await wrapper.trigger('click') + expect(wrapper.classes('is-checked')).toBe(false) + done() + }) + }) + + test('disabled', async (done) => { + const wrapper = _mount('', () => ({ checkbox: false })) + const vm = wrapper.vm + expect(wrapper.classes()).toContain('is-disabled') + await wrapper.trigger('click') + vm.$nextTick(() => { + expect(wrapper.classes()).toContain('is-disabled') + done() + }) + }) + + test('change event', async (done) => { + const wrapper = _mount( + ` + + `, + () => ({ + data: '', + checked: false, + }), + { + methods: { + onChange(val) { + this.data = val + }, + }, + }, + ) + + const vm = wrapper.vm + await wrapper.trigger('click') + vm.$nextTick(() => { + expect(vm.data).toBe(true) + done() + }) + }) + + test('button group change', async done => { + const wrapper = _mount( + ` + + + + + + + `, + () => ({ + data: '', + checkList: [], + }), + { + methods: { + onChange(val) { + this.data = val + }, + }, + }, + ) + const vm = wrapper.vm + await wrapper.findComponent({ ref: 'a' }).trigger('click') + vm.$nextTick(async () => { + expect(vm.data).toEqual(['a']) + await wrapper.findComponent({ ref: 'b' }).trigger('click') + vm.$nextTick(() => { + expect(vm.data).toEqual(['a', 'b']) + done() + }) + }) + }) + + test('button group props', () => { + const wrapper = _mount( + ` + + + + + + + `, + () => ({ checkList: ['a', 'b'] }), + ) + const vm = wrapper.vm + expect(vm.checkList.length).toBe(2) + expect((vm.$refs.a as any).$el.classList.contains('is-checked')).toBe(true) + expect((vm.$refs.a as any).$el.querySelector('.el-checkbox-button__inner').style.borderColor).toEqual('#ff0000') + }) + + test('button group min and max', async done => { + const wrapper = _mount( + ` + + + + + + + `, + () => ({ + checkList: ['a'], + lastEvent: null, + }), + ) + const vm = wrapper.vm + expect(vm.checkList.length).toBe(1) + await wrapper.findComponent({ ref: 'a' }).trigger('click') + vm.$nextTick(async () => { + expect(vm.checkList.length).toBe(1) + await wrapper.findComponent({ ref: 'b' }).trigger('click') + vm.$nextTick(async () => { + expect(vm.checkList.length).toBe(2) + await wrapper.findComponent({ ref: 'c' }).trigger('click') + vm.$nextTick(() => { + expect(vm.checkList.length).toBe(2) + expect(vm.checkList).toEqual(['a', 'b']) + expect((wrapper.findComponent({ ref: 'c' }).vm as any).isDisabled).toBe(true) + expect((wrapper.findComponent({ ref: 'd' }).vm as any).isDisabled).toBe(true) + done() + }) + }) + }) + }) + + test('nested group', async done => { + const wrapper = _mount( + ` + +
+ + + + +
+
+ `, + () => ({ checkList: [] }), + ) + const vm = wrapper.vm + expect(vm.checkList.length).toBe(0) + await wrapper.findComponent({ ref: 'a' }).trigger('click') + vm.$nextTick(() => { + expect(vm.checkList).toEqual(['a']) + done() + }) + }) + + test('true false lable', async done => { + const wrapper = _mount( + ``, + () => ({ + checked: 'a', + }), + ) + const vm = wrapper.vm + await wrapper.trigger('click') + vm.$nextTick(() => { + expect((vm as any).checked).toBe(3) + done() + }) + }) + + test('check', () => { + const wrapper = _mount( + ` +
+ + + + +
+ `, + () => ({ + checked: false, + checklist: [], + }), + ) as any + expect(wrapper.vm.checked).toBe(true) + expect(wrapper.vm.checklist).toEqual(['a']) + }) +}) diff --git a/packages/checkbox/doc/basic.vue b/packages/checkbox/doc/basic.vue new file mode 100644 index 0000000000..3a97684548 --- /dev/null +++ b/packages/checkbox/doc/basic.vue @@ -0,0 +1,36 @@ + + diff --git a/packages/checkbox/doc/group.vue b/packages/checkbox/doc/group.vue new file mode 100644 index 0000000000..2d61581b71 --- /dev/null +++ b/packages/checkbox/doc/group.vue @@ -0,0 +1,77 @@ + + diff --git a/packages/checkbox/doc/index.stories.ts b/packages/checkbox/doc/index.stories.ts new file mode 100644 index 0000000000..8a2b23a536 --- /dev/null +++ b/packages/checkbox/doc/index.stories.ts @@ -0,0 +1,6 @@ +export { default as BasicUsage } from './basic.vue' +export { default as GroupUsage } from './group.vue' + +export default { + title: 'Checkbox', +} diff --git a/packages/checkbox/index.ts b/packages/checkbox/index.ts new file mode 100644 index 0000000000..afaf37c0f2 --- /dev/null +++ b/packages/checkbox/index.ts @@ -0,0 +1,10 @@ +import { App } from 'vue' +import Checkbox from './src/checkbox.vue' +import CheckboxButton from './src/checkbox-button.vue' +import CheckboxGroup from './src/checkbox-group.vue' + +export default (app: App): void => { + app.component(Checkbox.name, Checkbox) + app.component(CheckboxButton.name, CheckboxButton) + app.component(CheckboxGroup.name, CheckboxGroup) +} diff --git a/packages/checkbox/package.json b/packages/checkbox/package.json new file mode 100644 index 0000000000..2337118bdb --- /dev/null +++ b/packages/checkbox/package.json @@ -0,0 +1,12 @@ +{ + "name": "@element-plus/checkbox", + "version": "0.0.0", + "main": "dist/index.js", + "license": "MIT", + "peerDependencies": { + "vue": "^3.0.0-rc.1" + }, + "devDependencies": { + "@vue/test-utils": "^2.0.0-beta.0" + } +} diff --git a/packages/checkbox/src/checkbox-button.vue b/packages/checkbox/src/checkbox-button.vue new file mode 100644 index 0000000000..21899d8e0d --- /dev/null +++ b/packages/checkbox/src/checkbox-button.vue @@ -0,0 +1,200 @@ + + + diff --git a/packages/checkbox/src/checkbox-group.vue b/packages/checkbox/src/checkbox-group.vue new file mode 100644 index 0000000000..588e7e845f --- /dev/null +++ b/packages/checkbox/src/checkbox-group.vue @@ -0,0 +1,82 @@ + + + diff --git a/packages/checkbox/src/checkbox.vue b/packages/checkbox/src/checkbox.vue new file mode 100644 index 0000000000..18b304a8b5 --- /dev/null +++ b/packages/checkbox/src/checkbox.vue @@ -0,0 +1,222 @@ + + + diff --git a/packages/checkbox/src/useCheckbox.ts b/packages/checkbox/src/useCheckbox.ts new file mode 100644 index 0000000000..e5acff0a4e --- /dev/null +++ b/packages/checkbox/src/useCheckbox.ts @@ -0,0 +1,24 @@ +import { ref, computed, inject } from 'vue' + +export const useCheckbox = () => { + //todo: ELEMENT + const ELEMENT = null + const elForm = inject('elForm', {}) + const elFormItem = inject('elFormItem', {}) as any + const _checkboxGroup = inject('CheckboxGroup', {}) as any + const focus = ref(false) + const isGroup = computed(() => _checkboxGroup && _checkboxGroup.name === 'ElCheckboxGroup') + const _elFormItemSize = computed(() => { + + return (elFormItem || {} as any).elFormItemSize + }) + return { + isGroup, + focus, + _checkboxGroup, + elForm, + ELEMENT, + _elFormItemSize, + elFormItem, + } +} diff --git a/packages/element-plus/index.ts b/packages/element-plus/index.ts index 4c758415e8..67fd141caf 100644 --- a/packages/element-plus/index.ts +++ b/packages/element-plus/index.ts @@ -4,6 +4,7 @@ import ElBacktop from '@element-plus/backtop' import ElButton from '@element-plus/button' import ElBadge from '@element-plus/badge' import ElCard from '@element-plus/card' +import ElCheckbox from '@element-plus/checkbox' import ElTag from '@element-plus/tag' import ElLayout from '@element-plus/layout' import ElDivider from '@element-plus/divider' @@ -28,6 +29,7 @@ export { ElButton, ElBadge, ElCard, + ElCheckbox, ElDivider, ElTag, ElTimeline, @@ -51,6 +53,7 @@ export default function install(app: App): void { ElButton(app) ElBadge(app) ElCard(app) + ElCheckbox(app) ElTag(app) ElLayout(app) ElDivider(app) diff --git a/packages/element-plus/package.json b/packages/element-plus/package.json index b5d36fb5b7..9b96f1196c 100644 --- a/packages/element-plus/package.json +++ b/packages/element-plus/package.json @@ -20,7 +20,6 @@ "@element-plus/button": "^0.0.0", "@element-plus/breadcrumb": "^0.0.0", "@element-plus/card": "^0.0.0", - "@element-plus/tag": "^0.0.0", "@element-plus/timeline": "^0.0.0", "@element-plus/divider": "^0.0.0", "@element-plus/icon": "^0.0.0", diff --git a/packages/rate/__tests__/rate.spec.ts b/packages/rate/__tests__/rate.spec.ts index 16b5a4de1b..bdb41fa7f6 100644 --- a/packages/rate/__tests__/rate.spec.ts +++ b/packages/rate/__tests__/rate.spec.ts @@ -7,6 +7,11 @@ describe('Rate.vue', () => { props: { max: 10, }, + global: { + provide: { + elForm: {}, + }, + }, }) const stars = wrapper.findAll('.el-rate__item') expect(stars.length).toEqual(10) @@ -19,6 +24,11 @@ describe('Rate.vue', () => { modelValue: 4, texts: ['1', '2', '3', '4', '5'], }, + global: { + provide: { + elForm: {}, + }, + }, }) const text = wrapper.find('.el-rate__text').element expect(text.textContent).toEqual('4') @@ -29,6 +39,11 @@ describe('Rate.vue', () => { props: { modelValue: 0, }, + global: { + provide: { + elForm: {}, + }, + }, }) const vm = wrapper.vm await wrapper.setProps({ modelValue: 3 }) @@ -52,7 +67,10 @@ describe('Rate.vue', () => { 'el-rate': Rate, }, }, { - props: { + global: { + provide: { + elForm: {}, + }, }, }) const vm = wrapper.vm