diff --git a/devui/splitter/__tests__/event-helper.ts b/devui/splitter/__tests__/event-helper.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4bc643c3c293db95effdb848f80154fd9ce52e25
--- /dev/null
+++ b/devui/splitter/__tests__/event-helper.ts
@@ -0,0 +1,38 @@
+export function mouseMoveTrigger(
+ el: HTMLElement,
+ from: { x: number; y: number; },
+ to: { x: number; y: number; }
+): void {
+ if (typeof window === 'undefined') {
+ return
+ }
+ dispatchMouseEvent(el, 'mousedown', from.x, from.y)
+ dispatchMouseEvent(window.document, 'mousemove', to.x, to.y)
+ dispatchMouseEvent(window.document, 'mouseup')
+}
+
+export function dispatchMouseEvent(
+ node: Node,
+ type: string,
+ x = 0,
+ y = 0,
+ event: MouseEvent = createMouseEvent(type, x, y)
+): void {
+ node.dispatchEvent(event)
+}
+
+export function createMouseEvent(
+ type: string,
+ x = 0,
+ y = 0
+): MouseEvent {
+ const event = new MouseEvent(type, {
+ bubbles: true,
+ cancelable: false,
+ clientX: x,
+ clientY: y,
+ // TODO pageX
+ // TODO pageY
+ })
+ return event
+}
diff --git a/devui/splitter/__tests__/splitter.spec.ts b/devui/splitter/__tests__/splitter.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..270082acab962701d0b83e113711682e92298f14
--- /dev/null
+++ b/devui/splitter/__tests__/splitter.spec.ts
@@ -0,0 +1,343 @@
+import { mount } from '@vue/test-utils'
+import { wrap } from 'lodash'
+import { ref } from 'vue'
+import DSplitter from '../src/splitter'
+import DSplitterPane from '../src/splitter-pane'
+import { mouseMoveTrigger } from './event.helper'
+
+describe('splitter', () => {
+ describe('basic', () => {
+ const testComponent = {
+ components: {
+ DSplitter,
+ DSplitterPane,
+ },
+ template: `
+
+
+
+
+
左侧面板
+
左侧内容区域,宽度 30%,最小宽度 20%
+
+
+
+
+
+
+
+
+
+
+ `,
+ setup() {
+ const orientation = ref('horizontal')
+ const collapsible = ref(true)
+ const collapsed = ref(false)
+ const splitBarSize = ref('2px')
+ const size = ref('30%')
+ const minSize = ref('20%')
+ const maxSize = ref('60%')
+ const sizeChange = (size) => {
+ console.log(size)
+ }
+ return {
+ orientation,
+ collapsible,
+ collapsed,
+ splitBarSize,
+ size,
+ minSize,
+ maxSize,
+ sizeChange,
+ }
+ },
+ }
+
+ let wrapper = null
+ let splitterElement: HTMLElement
+ beforeEach(() => {
+ wrapper = mount(testComponent)
+ splitterElement = wrapper.vm.$el
+ })
+ it('should create testComponent', () => {
+ expect(wrapper.vm).toBeTruthy()
+ })
+
+ it('should create splitter container', () => {
+ expect(splitterElement).toBeTruthy()
+ expect(wrapper.classes()).toContain('devui-splitter-horizontal')
+ })
+
+ it('should render splitter-bar', () => {
+ const handles = wrapper.findAll('.devui-splitter-bar')
+ expect(handles.length).toBe(2)
+ })
+
+ it('should collapse left pane when collapseButton clicked', async () => {
+ // const handleButton = wrapper.find('.prev.devui-collapse')
+ // handleButton.trigger('click')
+ // await wrapper.vm.$nextTick()
+ // TODO: Jest 基于 jsdom,jsdom not support `clientWidth`,clientWidth 为0
+ // const pane = wrapper.find('.devui-splitter-pane').element
+ // expect(pane.clientWidth).toBe(0)
+ })
+
+ it('should add collapsed class when collapseButton clicked', async () => {
+ const handleButton = wrapper.find('.prev.devui-collapse')
+ handleButton.trigger('click')
+ await wrapper.vm.$nextTick()
+ expect(handleButton.classes()).toContain('collapsed')
+ })
+
+ it('should change collapse state', () => {
+ wrapper = mount(
+ Object.assign(testComponent, {
+ setup() {
+ const orientation = ref('horizontal')
+ const collapsible = ref(false)
+ const collapsed = ref(false)
+ const splitBarSize = ref('2px')
+ const size = ref('30%')
+ const minSize = ref('20%')
+ const maxSize = ref('60%')
+ const sizeChange = (size) => {
+ console.log(size)
+ }
+ return {
+ orientation,
+ collapsible,
+ collapsed,
+ splitBarSize,
+ size,
+ minSize,
+ maxSize,
+ sizeChange,
+ }
+ },
+ })
+ )
+ expect(wrapper.find('.prev').classes()).not.toContain('devui-collapse')
+ })
+
+ it('should be collapsed', () => {
+ wrapper = mount(
+ Object.assign(testComponent, {
+ setup() {
+ const orientation = ref('horizontal')
+ const collapsible = ref(true)
+ const collapsed = ref(true)
+ const splitBarSize = ref('2px')
+ const size = ref('30%')
+ const minSize = ref('20%')
+ const maxSize = ref('60%')
+ const sizeChange = (size) => {
+ console.log(size)
+ }
+ return {
+ orientation,
+ collapsible,
+ collapsed,
+ splitBarSize,
+ size,
+ minSize,
+ maxSize,
+ sizeChange,
+ }
+ },
+ })
+ )
+ expect(wrapper.find('.prev.devui-collapse').classes()).toContain(
+ 'collapsed'
+ )
+ })
+
+ it('should change splitterBar size', async () => {
+ // TODO: Jest 基于 jsdom,jsdom not support `clientWidth`,clientWidth 为0
+ // 详细可以看 ReadME https://github.com/jsdom/jsdom
+ // README 建议: `using Object.defineProperty() to change what various layout-related getters and methods return.` 待处理
+ // expect(wrapper.find('.devui-splitter-bar').element.clientWidth).toBe(2)
+ })
+
+ it('should change splitter direction', () => {
+ wrapper = mount(
+ Object.assign(testComponent, {
+ setup() {
+ const orientation = ref('vertical')
+ const collapsible = ref(true)
+ const collapsed = ref(true)
+ const splitBarSize = ref('2px')
+ const size = ref('30%')
+ const minSize = ref('20%')
+ const maxSize = ref('60%')
+ const sizeChange = (size) => {
+ console.log(size)
+ }
+ return {
+ orientation,
+ collapsible,
+ collapsed,
+ splitBarSize,
+ size,
+ minSize,
+ maxSize,
+ sizeChange,
+ }
+ },
+ })
+ )
+ expect(wrapper.classes()).toContain('devui-splitter-vertical')
+ })
+
+ it('should change pane size', async () => {
+ wrapper = mount(
+ Object.assign(testComponent, {
+ setup() {
+ const orientation = ref('vertical')
+ const collapsible = ref(true)
+ const collapsed = ref(true)
+ const splitBarSize = ref('2px')
+ const size = ref('40%')
+ const minSize = ref('20%')
+ const maxSize = ref('60%')
+ const sizeChange = (size) => {
+ console.log(size)
+ }
+ return {
+ orientation,
+ collapsible,
+ collapsed,
+ splitBarSize,
+ size,
+ minSize,
+ maxSize,
+ sizeChange,
+ }
+ },
+ })
+ )
+ await wrapper.vm.$nextTick()
+ const computedStyle = getComputedStyle(
+ wrapper.find('.devui-splitter-pane').element
+ )
+ expect(computedStyle.flexBasis).toContain('40%')
+ })
+
+ it('should change pane size', () => {
+ wrapper = mount(
+ Object.assign(testComponent, {
+ setup() {
+ const orientation = ref('vertical')
+ const collapsible = ref(true)
+ const collapsed = ref(true)
+ const splitBarSize = ref('2px')
+ const size = ref(undefined)
+ const minSize = ref('20%')
+ const maxSize = ref('60%')
+ const sizeChange = (size) => {
+ console.log(size)
+ }
+ return {
+ orientation,
+ collapsible,
+ collapsed,
+ splitBarSize,
+ size,
+ minSize,
+ maxSize,
+ sizeChange,
+ }
+ },
+ })
+ )
+ expect(wrapper.find('.devui-splitter-pane').classes()).not.toContain(
+ 'devui-splitter-pane-fixed'
+ )
+ })
+
+ // 测试拖动时size最小边界
+ it('should minimum size work', async () => {
+ const leftPaneElement: HTMLElement = wrapper.find(
+ '.devui-splitter-pane'
+ ).element
+
+ // TODO Jest 基于 jsdom,jsdom not support getBoundingClientRect
+ const rect = leftPaneElement.getBoundingClientRect()
+ const splitterBarElement: HTMLElement = wrapper.find(
+ '.devui-splitter-bar'
+ ).element
+ // 模拟鼠标事件
+ mouseMoveTrigger(
+ splitterBarElement,
+ { x: rect.right, y: rect.height },
+ { x: rect.right - 2000, y: rect.height }
+ )
+
+ // TODO: Jest 基于 jsdom,jsdom not support `clientWidth`,clientWidth 为 0
+ })
+ })
+
+ describe('vertical', () => {
+ const testComponent = {
+ components: {
+ DSplitter,
+ DSplitterPane,
+ },
+ template: `
+
+
+
+
+
+
+
+
+
+
+
+ `,
+ setup() {
+ const orientation = ref('vertical')
+ const size = ref('100px')
+ const minSize = ref('50px')
+ const maxSize = ref('200px')
+ return {
+ orientation,
+ size,
+ minSize,
+ maxSize,
+ }
+ },
+ }
+
+ let wrapper = null
+ beforeEach(() => {
+ wrapper = mount(testComponent)
+ })
+
+ it('should create vertical container', () => {
+ expect(wrapper.vm.$el).toBeTruthy()
+ expect(wrapper.classes()).toContain('devui-splitter-vertical')
+ })
+
+ // 测试拖动时 size 最大边界
+ it('should right panel maximum size work', async () => {
+ // TODO Jest 基于 jsdom,jsdom not support getBoundingClientRect
+ })
+ })
+})