mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-05-14 20:43:57 +00:00
225 lines
7.2 KiB
TypeScript
225 lines
7.2 KiB
TypeScript
/*
|
||
* 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, nextTick } from 'vue';
|
||
import { mount } from '@vue/test-utils';
|
||
|
||
import DataSourceMethods from '@editor/fields/DataSourceMethods.vue';
|
||
|
||
const { messageBoxConfirm, codeBlockEditorShow, codeBlockEditorHide } = vi.hoisted(() => ({
|
||
messageBoxConfirm: vi.fn().mockResolvedValue(true),
|
||
codeBlockEditorShow: vi.fn(),
|
||
codeBlockEditorHide: vi.fn(),
|
||
}));
|
||
|
||
vi.mock('@tmagic/design', () => ({
|
||
TMagicButton: defineComponent({
|
||
name: 'FakeTMagicButton',
|
||
inheritAttrs: false,
|
||
setup(_p, { slots, attrs }) {
|
||
return () =>
|
||
h(
|
||
'button',
|
||
{
|
||
...attrs,
|
||
class: ['fake-btn', (attrs as any).class].filter(Boolean).join(' '),
|
||
},
|
||
slots.default?.(),
|
||
);
|
||
},
|
||
}),
|
||
tMagicMessageBox: { confirm: messageBoxConfirm },
|
||
}));
|
||
|
||
vi.mock('@tmagic/table', () => ({
|
||
MagicTable: defineComponent({
|
||
name: 'FakeMagicTable',
|
||
props: ['data', 'columns', 'border'],
|
||
setup(props) {
|
||
return () =>
|
||
h('div', { class: 'fake-magic-table' }, [
|
||
h('span', { class: 'data-len' }, String((props.data || []).length)),
|
||
...(props.columns as any[]).map((c, i) => h('span', { class: `col-${i}` }, c.label)),
|
||
]);
|
||
},
|
||
}),
|
||
}));
|
||
|
||
vi.mock('@editor/components/CodeBlockEditor.vue', () => ({
|
||
default: defineComponent({
|
||
name: 'FakeCodeBlockEditor',
|
||
props: ['disabled', 'content', 'isDataSource', 'dataSourceType'],
|
||
emits: ['submit'],
|
||
setup(props, { emit, expose }) {
|
||
expose({
|
||
show: codeBlockEditorShow,
|
||
hide: codeBlockEditorHide,
|
||
});
|
||
return () =>
|
||
h(
|
||
'div',
|
||
{
|
||
class: 'fake-code-block-editor',
|
||
onClick: (e: any) => {
|
||
if (e?.detail?.payload) {
|
||
emit('submit', e.detail.payload[0], e.detail.payload[1]);
|
||
}
|
||
},
|
||
},
|
||
JSON.stringify((props as any).content),
|
||
);
|
||
},
|
||
}),
|
||
}));
|
||
|
||
beforeEach(() => {
|
||
vi.clearAllMocks();
|
||
});
|
||
|
||
describe('DataSourceMethods.vue', () => {
|
||
test('渲染表格与添加按钮', () => {
|
||
const wrapper = mount(DataSourceMethods, {
|
||
props: {
|
||
name: 'methods',
|
||
prop: 'methods',
|
||
config: { type: 'data-source-methods' } as any,
|
||
model: { methods: [] } as any,
|
||
} as any,
|
||
});
|
||
expect(wrapper.find('.fake-magic-table').exists()).toBe(true);
|
||
expect(wrapper.find('.fake-btn').text()).toBe('添加');
|
||
});
|
||
|
||
test('点击添加显示编辑器', async () => {
|
||
const wrapper = mount(DataSourceMethods, {
|
||
props: {
|
||
name: 'methods',
|
||
prop: 'methods',
|
||
config: {} as any,
|
||
model: { methods: [] } as any,
|
||
} as any,
|
||
});
|
||
await wrapper.find('.fake-btn').trigger('click');
|
||
await nextTick();
|
||
expect(wrapper.find('.fake-code-block-editor').exists()).toBe(true);
|
||
await nextTick();
|
||
expect(codeBlockEditorShow).toHaveBeenCalled();
|
||
});
|
||
|
||
test('编辑 action - method.content 是 string', async () => {
|
||
const wrapper = mount(DataSourceMethods, {
|
||
props: {
|
||
name: 'methods',
|
||
prop: 'methods',
|
||
config: {} as any,
|
||
model: { methods: [{ name: 'm1', content: 'function () {}' }] } as any,
|
||
} as any,
|
||
});
|
||
const columns = wrapper.findComponent({ name: 'FakeMagicTable' }).props('columns') as any;
|
||
const editAction = columns[columns.length - 1].actions[0];
|
||
editAction.handler({ name: 'm1', content: 'function () {}' }, 0);
|
||
await nextTick();
|
||
await nextTick();
|
||
expect(codeBlockEditorShow).toHaveBeenCalled();
|
||
});
|
||
|
||
test('编辑 action - method.content 是函数(toString)', async () => {
|
||
const wrapper = mount(DataSourceMethods, {
|
||
props: {
|
||
name: 'methods',
|
||
prop: 'methods',
|
||
config: {} as any,
|
||
model: { methods: [] } as any,
|
||
} as any,
|
||
});
|
||
const columns = wrapper.findComponent({ name: 'FakeMagicTable' }).props('columns') as any;
|
||
const editAction = columns[columns.length - 1].actions[0];
|
||
const fn = function fakeFn() {
|
||
return 1;
|
||
};
|
||
editAction.handler({ name: 'm1', content: fn }, 0);
|
||
await nextTick();
|
||
await nextTick();
|
||
expect(codeBlockEditorShow).toHaveBeenCalled();
|
||
});
|
||
|
||
test('删除 action 调用 confirm 并移除项', async () => {
|
||
const model: any = { methods: [{ name: 'm1' }] };
|
||
const wrapper = mount(DataSourceMethods, {
|
||
props: {
|
||
name: 'methods',
|
||
prop: 'methods',
|
||
config: {} as any,
|
||
model,
|
||
} as any,
|
||
});
|
||
const columns = wrapper.findComponent({ name: 'FakeMagicTable' }).props('columns') as any;
|
||
const delAction = columns[columns.length - 1].actions[1];
|
||
await delAction.handler({ name: 'm1' }, 0);
|
||
await nextTick();
|
||
expect(messageBoxConfirm).toHaveBeenCalled();
|
||
expect(model.methods.length).toBe(0);
|
||
expect(wrapper.emitted('change')?.[0]?.[0]).toEqual([]);
|
||
});
|
||
|
||
test('params formatter 返回字符串', () => {
|
||
const wrapper = mount(DataSourceMethods, {
|
||
props: {
|
||
name: 'methods',
|
||
prop: 'methods',
|
||
config: {} as any,
|
||
model: { methods: [] } as any,
|
||
} as any,
|
||
});
|
||
const columns = wrapper.findComponent({ name: 'FakeMagicTable' }).props('columns') as any;
|
||
const paramsCol = columns.find((c: any) => c.prop === 'params');
|
||
expect(paramsCol.formatter([{ name: 'a' }, { name: 'b' }])).toBe('a, b');
|
||
expect(paramsCol.formatter()).toBe('');
|
||
});
|
||
|
||
test('submit - editIndex > -1 编辑模式提交', async () => {
|
||
const wrapper = mount(DataSourceMethods, {
|
||
props: {
|
||
name: 'methods',
|
||
prop: 'methods',
|
||
config: {} as any,
|
||
model: { methods: [{ name: 'm1', content: 'fn1' }] } as any,
|
||
} as any,
|
||
});
|
||
const columns = wrapper.findComponent({ name: 'FakeMagicTable' }).props('columns') as any;
|
||
columns[columns.length - 1].actions[0].handler({ name: 'm1', content: 'fn1' }, 0);
|
||
await nextTick();
|
||
await nextTick();
|
||
const editor = wrapper.findComponent({ name: 'FakeCodeBlockEditor' });
|
||
(editor.vm.$emit as any)('submit', { name: 'm1' }, { changeRecords: [{ propPath: 'name', value: 'm1' }] });
|
||
await nextTick();
|
||
const evt = wrapper.emitted('change')?.[0];
|
||
expect(evt?.[1]).toMatchObject({ modifyKey: 0 });
|
||
expect((evt?.[1] as any).changeRecords[0].propPath).toBe('methods.0.name');
|
||
expect(codeBlockEditorHide).toHaveBeenCalled();
|
||
});
|
||
|
||
test('submit - 新增模式提交', async () => {
|
||
const wrapper = mount(DataSourceMethods, {
|
||
props: {
|
||
name: 'methods',
|
||
prop: 'methods',
|
||
config: {} as any,
|
||
model: { methods: [{ name: 'a' }] } as any,
|
||
} as any,
|
||
});
|
||
await wrapper.find('.fake-btn').trigger('click');
|
||
await nextTick();
|
||
await nextTick();
|
||
const editor = wrapper.findComponent({ name: 'FakeCodeBlockEditor' });
|
||
(editor.vm.$emit as any)('submit', { name: 'b' }, {});
|
||
await nextTick();
|
||
const evt = wrapper.emitted('change')?.[0];
|
||
expect((evt?.[1] as any).modifyKey).toBe(1);
|
||
expect((evt?.[1] as any).changeRecords[0].propPath).toBe('methods.1');
|
||
});
|
||
});
|