tmagic-editor/packages/editor/tests/unit/fields/CodeSelectCol.spec.ts

200 lines
7.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Tencent is pleased to support the open source community by making TMagicEditor available.
*
* Copyright (C) 2025 Tencent.
*/
import { beforeEach, describe, expect, test, vi } from 'vitest';
import { defineComponent, h } from 'vue';
import { mount } from '@vue/test-utils';
import CodeSelectCol from '@editor/fields/CodeSelectCol.vue';
const codeBlockService = {
getCodeDsl: vi.fn(() => ({
c1: { name: 'C1', params: [{ name: 'p1', type: 'text' }] },
c2: { name: 'C2', params: [] },
})),
};
const uiService = {
get: vi.fn(() => [{ $key: 'code-block' }]),
set: vi.fn(),
};
vi.mock('@editor/hooks/use-services', () => ({
useServices: () => ({ codeBlockService, uiService }),
}));
vi.mock('@editor/type', async () => {
const actual = await vi.importActual<any>('@editor/type');
return { ...actual, SideItemKey: { CODE_BLOCK: 'code-block' } };
});
vi.mock('@tmagic/form', async (importOriginal) => {
const actual = await importOriginal<any>();
return {
...actual,
filterFunction: (_form: any, fn: any, props: any) => (typeof fn === 'function' ? fn(_form, props) : fn),
createValues: vi.fn(() => ({ p1: '' })),
MSelect: defineComponent({
name: 'MSelect',
props: ['model', 'name', 'size', 'prop', 'config'],
emits: ['change'],
setup() {
return () => h('select', { class: 'fake-select' });
},
}),
MContainer: defineComponent({
name: 'MFormContainer',
props: ['model', 'lastValues', 'isCompare', 'size', 'prop', 'config'],
setup() {
return () => h('div', { class: 'fake-diff-select' });
},
}),
};
});
vi.mock('@tmagic/design', () => ({
TMagicButton: defineComponent({
name: 'TMagicButton',
props: ['size'],
emits: ['click'],
setup(_p, { emit, slots }) {
return () => h('button', { onClick: () => emit('click') }, slots.default?.());
},
}),
}));
vi.mock('@editor/components/Icon.vue', () => ({
default: defineComponent({ name: 'MIcon', props: ['icon'], setup: () => () => h('i') }),
}));
vi.mock('@editor/components/CodeParams.vue', () => ({
default: defineComponent({
name: 'CodeParams',
props: ['name', 'model', 'size', 'disabled', 'paramsConfig', 'lastValues', 'isCompare'],
emits: ['change'],
setup(_p, { emit }) {
return () =>
h('div', {
class: 'fake-params',
onClick: () => emit('change', null, { changeRecords: [{ propPath: 'p1', value: 'x' }] }),
});
},
}),
}));
beforeEach(() => {
vi.clearAllMocks();
codeBlockService.getCodeDsl.mockReturnValue({
c1: { name: 'C1', params: [{ name: 'p1', type: 'text' }] },
c2: { name: 'C2', params: [] },
});
uiService.get.mockReturnValue([{ $key: 'code-block' }]);
});
const baseProps = (extra: any = {}) => ({
config: { type: 'code-select-col', notEditable: false },
name: 'codeId',
prop: 'codeId',
model: { codeId: 'c1', params: { p1: 'old' } },
size: 'default',
disabled: false,
...extra,
});
describe('CodeSelectCol', () => {
test('val 存在时显示编辑按钮', () => {
const wrapper = mount(CodeSelectCol, { props: baseProps() as any });
expect(wrapper.find('button').exists()).toBe(true);
});
test('val 为空时不显示编辑按钮', () => {
const wrapper = mount(CodeSelectCol, { props: baseProps({ model: { codeId: '', params: {} } }) as any });
expect(wrapper.find('button').exists()).toBe(false);
});
test('paramsConfig 不为空时渲染 CodeParams', () => {
const wrapper = mount(CodeSelectCol, { props: baseProps() as any });
expect(wrapper.find('.fake-params').exists()).toBe(true);
});
test('选择无 params 的代码块不渲染 CodeParams', () => {
const wrapper = mount(CodeSelectCol, { props: baseProps({ model: { codeId: 'c2', params: {} } }) as any });
expect(wrapper.find('.fake-params').exists()).toBe(false);
});
test('onCodeIdChangeHandler emit change 包含 changeRecords', async () => {
const wrapper = mount(CodeSelectCol, { props: baseProps() as any });
await wrapper.findComponent({ name: 'MSelect' }).vm.$emit('change', 'c2');
const evts = wrapper.emitted('change');
expect(evts?.[0]?.[0]).toBe('c2');
expect((evts?.[0]?.[1] as any).changeRecords.length).toBe(2);
});
test('CodeParams change 事件: 调整 propPath 后 emit', async () => {
const wrapper = mount(CodeSelectCol, { props: baseProps() as any });
await wrapper.find('.fake-params').trigger('click');
const evts = wrapper.emitted('change');
expect(evts?.[0]?.[0]).toBe('c1');
expect(((evts?.[0]?.[1] as any).changeRecords[0] as any).propPath).toContain('p1');
});
test('编辑按钮 emit edit-code 并切换到代码块 tab', async () => {
const eventBus = { emit: vi.fn() };
const wrapper = mount(CodeSelectCol, {
props: baseProps() as any,
global: { provide: { eventBus } },
});
await wrapper.find('button').trigger('click');
expect(uiService.set).toHaveBeenCalledWith('sideBarActiveTabName', 'code-block');
expect(eventBus.emit).toHaveBeenCalledWith('edit-code', 'c1');
});
test('未启用代码块侧边栏时不显示编辑按钮', () => {
uiService.get.mockReturnValue([]);
const wrapper = mount(CodeSelectCol, { props: baseProps() as any });
expect(wrapper.find('button').exists()).toBe(false);
});
test('codeDsl 为空时 selectConfig.options 返回空数组', () => {
codeBlockService.getCodeDsl.mockReturnValue(null as any);
const wrapper = mount(CodeSelectCol, { props: baseProps({ model: { codeId: '', params: {} } }) as any });
const select = wrapper.findComponent({ name: 'MSelect' });
expect((select.props('config') as any).options()).toEqual([]);
});
describe('对比模式', () => {
test('isCompare 但无 lastValues 时仍渲染普通 MSelect', () => {
const wrapper = mount(CodeSelectCol, { props: baseProps({ isCompare: true }) as any });
expect(wrapper.findComponent({ name: 'MSelect' }).exists()).toBe(true);
expect(wrapper.find('.fake-diff-select').exists()).toBe(false);
});
test('对比模式下拉框改用 MFormContainer并隐藏编辑按钮', () => {
const wrapper = mount(CodeSelectCol, {
props: baseProps({
isCompare: true,
lastValues: { codeId: 'c2', params: {} },
}) as any,
});
expect(wrapper.find('.fake-diff-select').exists()).toBe(true);
expect(wrapper.findComponent({ name: 'MSelect' }).exists()).toBe(false);
// 对比模式为只读,不展示查看/编辑按钮
expect(wrapper.find('button').exists()).toBe(false);
});
test('对比模式将 isCompare/lastValues 透传给参数表单 CodeParams', () => {
const wrapper = mount(CodeSelectCol, {
props: baseProps({
isCompare: true,
lastValues: { codeId: 'c1', params: { p1: 'old' } },
}) as any,
});
const params = wrapper.findComponent({ name: 'CodeParams' });
expect(params.exists()).toBe(true);
expect(params.props('isCompare')).toBe(true);
expect(params.props('lastValues')).toEqual({ codeId: 'c1', params: { p1: 'old' } });
});
});
});