mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-05-20 15:33:37 +00:00
- 抽离每列渲染逻辑为 NavMenuColumn 组件,监听容器宽度 - 容器空间不足时自动隐藏溢出项,并通过更多按钮 Popover 展开 - ToolButton 暴露根元素引用,便于父级测量宽度 - design ButtonProps 新增 bg 属性,用于更多按钮的激活态样式 - 补充 NavMenuColumn / NavMenu / ToolButton 的单元测试 Co-authored-by: Cursor <cursoragent@cursor.com>
225 lines
6.5 KiB
TypeScript
225 lines
6.5 KiB
TypeScript
/*
|
||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||
*
|
||
* Copyright (C) 2025 Tencent.
|
||
*/
|
||
import { describe, expect, test, vi } from 'vitest';
|
||
import { mount } from '@vue/test-utils';
|
||
|
||
import ToolButton from '@editor/components/ToolButton.vue';
|
||
|
||
const provideServices = () => ({
|
||
global: {
|
||
provide: {
|
||
services: {
|
||
editorService: {},
|
||
uiService: {},
|
||
},
|
||
},
|
||
},
|
||
});
|
||
|
||
describe('ToolButton.vue', () => {
|
||
test('display 为 false 时不渲染', () => {
|
||
const wrapper = mount(ToolButton as any, {
|
||
...provideServices(),
|
||
props: {
|
||
data: { type: 'button', display: false, text: 'btn' },
|
||
},
|
||
});
|
||
expect(wrapper.find('.menu-item').exists()).toBe(false);
|
||
});
|
||
|
||
test('data.type=text 时渲染文字', () => {
|
||
const wrapper = mount(ToolButton as any, {
|
||
...provideServices(),
|
||
props: {
|
||
data: { type: 'text', text: 'hello' } as any,
|
||
},
|
||
});
|
||
expect(wrapper.text()).toContain('hello');
|
||
});
|
||
|
||
test('data.type=divider 时渲染 divider', () => {
|
||
const wrapper = mount(ToolButton as any, {
|
||
...provideServices(),
|
||
props: {
|
||
data: { type: 'divider' } as any,
|
||
},
|
||
});
|
||
expect(wrapper.find('.menu-item').exists()).toBe(true);
|
||
});
|
||
|
||
test('data.type=button 点击触发 handler', async () => {
|
||
const handler = vi.fn();
|
||
const wrapper = mount(ToolButton as any, {
|
||
...provideServices(),
|
||
props: {
|
||
data: { type: 'button', text: 'click', handler } as any,
|
||
eventType: 'click',
|
||
},
|
||
});
|
||
await wrapper.find('.menu-item').trigger('click');
|
||
expect(handler).toHaveBeenCalled();
|
||
});
|
||
|
||
test('display 函数返回 false 时不渲染', () => {
|
||
const wrapper = mount(ToolButton as any, {
|
||
...provideServices(),
|
||
props: {
|
||
data: { type: 'button', display: () => false, text: 'x' } as any,
|
||
},
|
||
});
|
||
expect(wrapper.find('.menu-item').exists()).toBe(false);
|
||
});
|
||
|
||
test('disabled 函数返回 true 时不调用 handler', async () => {
|
||
const handler = vi.fn();
|
||
const wrapper = mount(ToolButton as any, {
|
||
...provideServices(),
|
||
props: {
|
||
data: { type: 'button', text: 'x', disabled: () => true, handler } as any,
|
||
eventType: 'click',
|
||
},
|
||
});
|
||
await wrapper.find('.menu-item').trigger('click');
|
||
expect(handler).not.toHaveBeenCalled();
|
||
});
|
||
|
||
test('eventType=mousedown 仅 mousedown 触发', async () => {
|
||
const handler = vi.fn();
|
||
const wrapper = mount(ToolButton as any, {
|
||
...provideServices(),
|
||
props: {
|
||
data: { type: 'button', text: 'x', handler } as any,
|
||
eventType: 'mousedown',
|
||
},
|
||
});
|
||
await wrapper.find('.menu-item').trigger('click');
|
||
expect(handler).not.toHaveBeenCalled();
|
||
await wrapper.find('.menu-item').trigger('mousedown');
|
||
expect(handler).toHaveBeenCalled();
|
||
});
|
||
|
||
test('eventType=mouseup 仅左键 mouseup 触发', async () => {
|
||
const handler = vi.fn();
|
||
const wrapper = mount(ToolButton as any, {
|
||
...provideServices(),
|
||
props: {
|
||
data: { type: 'button', text: 'x', handler } as any,
|
||
eventType: 'mouseup',
|
||
},
|
||
});
|
||
await wrapper.find('.menu-item').trigger('mouseup', { button: 1 });
|
||
expect(handler).not.toHaveBeenCalled();
|
||
await wrapper.find('.menu-item').trigger('mouseup', { button: 0 });
|
||
expect(handler).toHaveBeenCalled();
|
||
});
|
||
|
||
test('button 含 tooltip 时渲染 tooltip', () => {
|
||
const wrapper = mount(ToolButton as any, {
|
||
...provideServices(),
|
||
props: {
|
||
data: { type: 'button', text: 'x', tooltip: 'tip' } as any,
|
||
},
|
||
});
|
||
expect(wrapper.find('.menu-item').exists()).toBe(true);
|
||
expect(wrapper.text()).toContain('x');
|
||
});
|
||
|
||
test('data.type=dropdown 时渲染下拉菜单', () => {
|
||
const wrapper = mount(ToolButton as any, {
|
||
...provideServices(),
|
||
props: {
|
||
data: {
|
||
type: 'dropdown',
|
||
text: 'menu',
|
||
items: [{ text: 'item1', handler: vi.fn() }],
|
||
} as any,
|
||
},
|
||
});
|
||
expect(wrapper.find('.menu-item').exists()).toBe(true);
|
||
expect(wrapper.find('.menubar-menu-button').exists()).toBe(true);
|
||
expect(wrapper.text()).toContain('menu');
|
||
});
|
||
|
||
test('data.type=component 时渲染对应组件', () => {
|
||
const fakeComp = {
|
||
name: 'FakeC',
|
||
props: ['v'],
|
||
template: '<div class="custom-comp">{{v}}</div>',
|
||
};
|
||
const wrapper = mount(ToolButton as any, {
|
||
...provideServices(),
|
||
props: {
|
||
data: {
|
||
type: 'component',
|
||
component: fakeComp,
|
||
props: { v: 'hello' },
|
||
} as any,
|
||
},
|
||
});
|
||
expect(wrapper.find('.custom-comp').exists()).toBe(true);
|
||
expect(wrapper.find('.custom-comp').text()).toBe('hello');
|
||
});
|
||
|
||
test('dropdown 选中调用对应 handler', async () => {
|
||
const handler = vi.fn();
|
||
const wrapper = mount(ToolButton as any, {
|
||
...provideServices(),
|
||
props: {
|
||
data: {
|
||
type: 'dropdown',
|
||
text: 'menu',
|
||
items: [{ text: 'item1', handler }],
|
||
} as any,
|
||
},
|
||
});
|
||
const dropdown = wrapper.findComponent({ name: 'TMagicDropdown' });
|
||
if (dropdown.exists()) {
|
||
await dropdown.vm.$emit('command', { item: { handler } });
|
||
expect(handler).toHaveBeenCalled();
|
||
}
|
||
});
|
||
|
||
test('disabled 为 boolean 时直接使用', async () => {
|
||
const handler = vi.fn();
|
||
const wrapper = mount(ToolButton as any, {
|
||
...provideServices(),
|
||
props: {
|
||
data: { type: 'button', text: 'x', disabled: true, handler } as any,
|
||
eventType: 'click',
|
||
},
|
||
});
|
||
await wrapper.find('.menu-item').trigger('click');
|
||
expect(handler).not.toHaveBeenCalled();
|
||
});
|
||
|
||
test('暴露 getElRef,可获取根元素引用', () => {
|
||
const wrapper = mount(ToolButton as any, {
|
||
...provideServices(),
|
||
props: {
|
||
data: { type: 'button', text: 'x' } as any,
|
||
},
|
||
});
|
||
const exposed = wrapper.vm as any;
|
||
expect(typeof exposed.getElRef).toBe('function');
|
||
|
||
const elRef = exposed.getElRef();
|
||
expect(elRef).toBeDefined();
|
||
expect(elRef.value).toBe(wrapper.find('.menu-item').element);
|
||
});
|
||
|
||
test('display 为 false 时 getElRef 返回的 ref.value 为 null', () => {
|
||
const wrapper = mount(ToolButton as any, {
|
||
...provideServices(),
|
||
props: {
|
||
data: { type: 'button', display: false, text: 'x' } as any,
|
||
},
|
||
});
|
||
const exposed = wrapper.vm as any;
|
||
const elRef = exposed.getElRef();
|
||
expect(elRef.value).toBeNull();
|
||
});
|
||
});
|