2026-05-14 15:26:22 +08:00

188 lines
6.4 KiB
TypeScript

/*
* Tencent is pleased to support the open source community by making TMagicEditor available.
*
* Copyright (C) 2025 Tencent.
*/
import { afterEach, describe, expect, test, vi } from 'vitest';
import { mount } from '@vue/test-utils';
import ContentMenu from '@editor/components/ContentMenu.vue';
const provideServices = () => ({
global: {
provide: {
services: {
editorService: {},
uiService: {},
},
},
},
});
describe('ContentMenu.vue', () => {
afterEach(() => {
vi.useRealTimers();
});
test('show 后触发 show 事件', async () => {
const wrapper = mount(ContentMenu as any, {
...provideServices(),
props: {
menuData: [{ id: '1', type: 'button', text: 'a' }] as any,
},
});
(wrapper.vm as any).show({ clientX: 10, clientY: 20 });
await new Promise((r) => setTimeout(r, 0));
expect(wrapper.emitted('show')).toBeTruthy();
});
test('show 之后调用 hide 触发 hide 事件', async () => {
const wrapper = mount(ContentMenu as any, {
...provideServices(),
props: { menuData: [] as any },
});
(wrapper.vm as any).show();
await new Promise((r) => setTimeout(r, 0));
(wrapper.vm as any).hide();
expect(wrapper.emitted('hide')).toBeTruthy();
});
test('未显示时调用 hide 不触发事件', () => {
const wrapper = mount(ContentMenu as any, {
...provideServices(),
props: { menuData: [] as any },
});
(wrapper.vm as any).hide();
expect(wrapper.emitted('hide')).toBeFalsy();
});
test('setPosition 计算超出底部时回拢', () => {
const wrapper = mount(ContentMenu as any, {
...provideServices(),
props: { menuData: [] as any },
});
Object.defineProperty(document.body, 'clientHeight', { value: 100, configurable: true });
(wrapper.vm as any).setPosition({ clientX: 10, clientY: 90 });
expect((wrapper.vm as any).menuPosition.left).toBe(10);
expect((wrapper.vm as any).menuPosition.top).toBeLessThanOrEqual(100);
});
test('contains 判断 DOM 是否在菜单内部', async () => {
const wrapper = mount(ContentMenu as any, {
...provideServices(),
props: { menuData: [] as any },
});
(wrapper.vm as any).show({ clientX: 0, clientY: 0 });
await new Promise((r) => setTimeout(r, 0));
const outside = document.createElement('div');
expect((wrapper.vm as any).contains(outside)).toBeFalsy();
});
test('autoHide=false 时点击不会隐藏', async () => {
const wrapper = mount(ContentMenu as any, {
...provideServices(),
props: { menuData: [{ id: '1', type: 'button', text: 'a' }] as any, autoHide: false },
});
(wrapper.vm as any).show();
await new Promise((r) => setTimeout(r, 0));
expect(wrapper.emitted('hide')).toBeFalsy();
});
test('isSubMenu=true 不监听 mousedown', () => {
const addSpy = vi.spyOn(globalThis, 'addEventListener');
const wrapper = mount(ContentMenu as any, {
...provideServices(),
props: { menuData: [] as any, isSubMenu: true },
});
expect(addSpy).not.toHaveBeenCalledWith('mousedown', expect.any(Function), true);
wrapper.unmount();
addSpy.mockRestore();
});
test('卸载时移除 mousedown 监听', () => {
const removeSpy = vi.spyOn(globalThis, 'removeEventListener');
const wrapper = mount(ContentMenu as any, {
...provideServices(),
props: { menuData: [] as any },
});
wrapper.unmount();
expect(removeSpy).toHaveBeenCalledWith('mousedown', expect.any(Function), true);
removeSpy.mockRestore();
});
test('外部点击触发 hide', async () => {
const wrapper = mount(ContentMenu as any, {
...provideServices(),
props: { menuData: [{ id: '1', type: 'button', text: 'a' }] as any },
attachTo: document.body,
});
(wrapper.vm as any).show({ clientX: 0, clientY: 0 });
await new Promise((r) => setTimeout(r, 0));
const outside = document.createElement('div');
document.body.appendChild(outside);
const event = new MouseEvent('mousedown');
Object.defineProperty(event, 'target', { value: outside });
globalThis.dispatchEvent(event);
expect(wrapper.emitted('hide')).toBeTruthy();
});
test('外部点击在菜单内部时不 hide', async () => {
const wrapper = mount(ContentMenu as any, {
...provideServices(),
props: { menuData: [{ id: '1', type: 'button', text: 'a' }] as any },
attachTo: document.body,
});
(wrapper.vm as any).show({ clientX: 0, clientY: 0 });
await new Promise((r) => setTimeout(r, 0));
const inside = wrapper.find('.magic-editor-content-menu').element as HTMLElement;
const event = new MouseEvent('mousedown');
Object.defineProperty(event, 'target', { value: inside });
globalThis.dispatchEvent(event);
expect(wrapper.emitted('hide')).toBeFalsy();
});
test('autoHide=false 时外部点击不 hide', async () => {
const wrapper = mount(ContentMenu as any, {
...provideServices(),
props: { menuData: [] as any, autoHide: false },
attachTo: document.body,
});
(wrapper.vm as any).show({ clientX: 0, clientY: 0 });
await new Promise((r) => setTimeout(r, 0));
const outside = document.createElement('div');
document.body.appendChild(outside);
const event = new MouseEvent('mousedown');
Object.defineProperty(event, 'target', { value: outside });
globalThis.dispatchEvent(event);
expect(wrapper.emitted('hide')).toBeFalsy();
});
test('mouseenter 触发 mouseenter 事件', async () => {
const wrapper = mount(ContentMenu as any, {
...provideServices(),
props: { menuData: [] as any },
});
(wrapper.vm as any).show();
await new Promise((r) => setTimeout(r, 0));
await wrapper.find('.magic-editor-content-menu').trigger('mouseenter');
expect(wrapper.emitted('mouseenter')).toBeTruthy();
});
test('showSubMenu 设置 subMenuData', async () => {
const wrapper = mount(ContentMenu as any, {
...provideServices(),
props: {
menuData: [{ id: '1', type: 'button', text: 'a', items: [{ id: '2', type: 'button', text: 'b' }] }] as any,
},
});
(wrapper.vm as any).show({ clientX: 10, clientY: 20 });
await new Promise((r) => setTimeout(r, 0));
const buttons = wrapper.findAll('.tool-button');
if (buttons.length > 0) {
await buttons[0].trigger('mouseenter');
await new Promise((r) => setTimeout(r, 10));
}
expect(true).toBe(true);
});
});