mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-05-15 04:54:12 +00:00
448 lines
11 KiB
TypeScript
448 lines
11 KiB
TypeScript
import { describe, expect, test, vi } from 'vitest';
|
|
|
|
import { MApp, NodeType } from '@tmagic/schema';
|
|
|
|
import App from '../src/App';
|
|
import TMagicIteratorContainer from '../src/IteratorContainer';
|
|
import Node from '../src/Node';
|
|
|
|
const createAppDsl = (pageLength: number, nodeLength = 0) => {
|
|
const dsl: MApp = {
|
|
type: NodeType.ROOT,
|
|
id: 'app_1',
|
|
dataSources: [
|
|
{
|
|
id: 'ds_1',
|
|
fields: [
|
|
{
|
|
type: 'array',
|
|
name: 'array',
|
|
title: 'array',
|
|
enable: true,
|
|
fields: [
|
|
{
|
|
type: 'array',
|
|
name: 'arr',
|
|
title: 'arr',
|
|
defaultValue: [],
|
|
enable: true,
|
|
fields: [],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
events: [],
|
|
methods: [],
|
|
type: 'base',
|
|
},
|
|
],
|
|
dataSourceDeps: {},
|
|
dataSourceCondDeps: {},
|
|
items: [
|
|
...new Array(pageLength)
|
|
.fill({
|
|
type: NodeType.PAGE,
|
|
items: new Array(nodeLength)
|
|
.fill({
|
|
type: 'text',
|
|
})
|
|
.map((node, index) => ({
|
|
...node,
|
|
id: `text_${index}`,
|
|
})),
|
|
})
|
|
.map((page, index) => ({
|
|
...page,
|
|
id: `page_${index}`,
|
|
})),
|
|
{
|
|
type: NodeType.PAGE_FRAGMENT,
|
|
id: 'page_fragment_1',
|
|
items: [
|
|
{
|
|
type: 'text',
|
|
id: 'text_page_fragment',
|
|
text: 'text_page_fragment',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
|
|
return dsl;
|
|
};
|
|
|
|
describe('App', () => {
|
|
test('instance', () => {
|
|
const app = new App({});
|
|
expect(app).toBeInstanceOf(App);
|
|
});
|
|
|
|
test('page', () => {
|
|
const app = new App({
|
|
config: createAppDsl(2),
|
|
});
|
|
expect(app.getNode('page_0')?.data.id).toBe('page_0');
|
|
expect(app.page?.data.id).toBe('page_0');
|
|
|
|
app.setConfig(createAppDsl(3), 'page_1');
|
|
expect(app.page?.data.id).toBe('page_1');
|
|
|
|
app.setPage('page_2');
|
|
expect(app.page?.data.id).toBe('page_2');
|
|
});
|
|
|
|
test('node', () => {
|
|
const app = new App({
|
|
config: createAppDsl(1, 10),
|
|
});
|
|
|
|
expect(app.getNode('text_1')?.data.id).toBe('text_1');
|
|
});
|
|
|
|
test('iterator-container', () => {
|
|
const dsl = createAppDsl(1, 10);
|
|
|
|
dsl.items[0].items.push({
|
|
type: 'iterator-container',
|
|
id: 'iterator-container_1',
|
|
items: [
|
|
{
|
|
type: 'text',
|
|
id: 'text',
|
|
},
|
|
],
|
|
});
|
|
|
|
const app = new App({
|
|
config: dsl,
|
|
});
|
|
|
|
const ic = app.getNode('iterator-container_1') as unknown as TMagicIteratorContainer;
|
|
|
|
expect(ic?.data.id).toBe('iterator-container_1');
|
|
|
|
ic?.setNodes(
|
|
[
|
|
{
|
|
type: 'text',
|
|
id: 'text',
|
|
text: '1',
|
|
},
|
|
{
|
|
type: 'page-fragment-container',
|
|
id: 'page_fragment_container_1',
|
|
pageFragmentId: 'page_fragment_1',
|
|
},
|
|
{
|
|
type: 'iterator-container',
|
|
id: 'iterator-container_11',
|
|
items: [
|
|
{
|
|
type: 'text',
|
|
id: 'text',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
0,
|
|
);
|
|
|
|
ic?.setNodes(
|
|
[
|
|
{
|
|
type: 'text',
|
|
id: 'text',
|
|
text: '2',
|
|
},
|
|
{
|
|
type: 'iterator-container',
|
|
id: 'iterator-container_11',
|
|
items: [
|
|
{
|
|
type: 'text',
|
|
id: 'text',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
1,
|
|
);
|
|
|
|
expect(app.getNode('text', { iteratorContainerId: ['iterator-container_1'], iteratorIndex: [0] })?.data.text).toBe(
|
|
'1',
|
|
);
|
|
expect(app.getNode('text', { iteratorContainerId: ['iterator-container_1'], iteratorIndex: [1] })?.data.text).toBe(
|
|
'2',
|
|
);
|
|
expect(
|
|
app.getNode('text_page_fragment', { iteratorContainerId: ['iterator-container_1'], iteratorIndex: [0] })?.data
|
|
.text,
|
|
).toBe('text_page_fragment');
|
|
|
|
const ic1 = app.getNode('iterator-container_11', {
|
|
iteratorContainerId: ['iterator-container_1'],
|
|
iteratorIndex: [0],
|
|
}) as unknown as TMagicIteratorContainer;
|
|
|
|
ic1?.setNodes(
|
|
[
|
|
{
|
|
type: 'text',
|
|
id: 'text',
|
|
text: '111',
|
|
},
|
|
],
|
|
0,
|
|
);
|
|
|
|
ic1?.setNodes(
|
|
[
|
|
{
|
|
type: 'text',
|
|
id: 'text',
|
|
text: '222',
|
|
},
|
|
],
|
|
1,
|
|
);
|
|
|
|
const ic2 = app.getNode('iterator-container_11', {
|
|
iteratorContainerId: ['iterator-container_1'],
|
|
iteratorIndex: [1],
|
|
}) as unknown as TMagicIteratorContainer;
|
|
|
|
ic2?.setNodes(
|
|
[
|
|
{
|
|
type: 'text',
|
|
id: 'text',
|
|
text: '11',
|
|
},
|
|
],
|
|
0,
|
|
);
|
|
|
|
ic2?.setNodes(
|
|
[
|
|
{
|
|
type: 'text',
|
|
id: 'text',
|
|
text: '22',
|
|
},
|
|
],
|
|
1,
|
|
);
|
|
|
|
expect(
|
|
app.getNode('text', {
|
|
iteratorContainerId: ['iterator-container_1', 'iterator-container_11'],
|
|
iteratorIndex: [0, 0],
|
|
})?.data.text,
|
|
).toBe('111');
|
|
expect(
|
|
app.getNode('text', {
|
|
iteratorContainerId: ['iterator-container_1', 'iterator-container_11'],
|
|
iteratorIndex: [0, 1],
|
|
})?.data.text,
|
|
).toBe('222');
|
|
expect(
|
|
app.getNode('text', {
|
|
iteratorContainerId: ['iterator-container_1', 'iterator-container_11'],
|
|
iteratorIndex: [1, 0],
|
|
})?.data.text,
|
|
).toBe('11');
|
|
expect(
|
|
app.getNode('text', {
|
|
iteratorContainerId: ['iterator-container_1', 'iterator-container_11'],
|
|
iteratorIndex: [1, 1],
|
|
})?.data.text,
|
|
).toBe('22');
|
|
|
|
ic.resetNodes();
|
|
|
|
expect(ic2?.nodes.length).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe('App 配置/方法/组件注册', () => {
|
|
test('platform=editor 时不创建 eventHelper', () => {
|
|
const app = new App({ platform: 'editor' });
|
|
expect(app.eventHelper).toBeUndefined();
|
|
expect(app.platform).toBe('editor');
|
|
});
|
|
|
|
test('disabledFlexible 时不创建 flexible', () => {
|
|
const app = new App({ disabledFlexible: true });
|
|
expect((app as any).flexible).toBeUndefined();
|
|
});
|
|
|
|
test('设置自定义 iteratorContainerType / pageFragmentContainerType', () => {
|
|
const app = new App({
|
|
iteratorContainerType: ['my-iter', 'custom-iter'],
|
|
pageFragmentContainerType: 'my-frag',
|
|
});
|
|
expect(app.iteratorContainerType.has('my-iter')).toBe(true);
|
|
expect(app.iteratorContainerType.has('custom-iter')).toBe(true);
|
|
expect(app.pageFragmentContainerType.has('my-frag')).toBe(true);
|
|
});
|
|
|
|
test('useMock=true 透传到 DataSourceManager', () => {
|
|
const app = new App({ useMock: true });
|
|
expect(app.useMock).toBe(true);
|
|
});
|
|
|
|
test('registerComponent / resolveComponent / unregisterComponent', () => {
|
|
const app = new App({});
|
|
const comp = { tag: 'x' };
|
|
app.registerComponent('my', comp);
|
|
expect(app.resolveComponent('my')).toBe(comp);
|
|
app.unregisterComponent('my');
|
|
expect(app.resolveComponent('my')).toBeUndefined();
|
|
});
|
|
|
|
test('registerNode 静态方法存入 nodeClassMap', () => {
|
|
class Custom extends Node {}
|
|
App.registerNode('custom-type', Custom);
|
|
expect(App.nodeClassMap.get('custom-type')).toBe(Custom);
|
|
});
|
|
|
|
test('setEnv 接受字符串/Env 实例', () => {
|
|
const app = new App({});
|
|
app.setEnv();
|
|
expect(app.env).toBeDefined();
|
|
app.setEnv('Mozilla/5.0');
|
|
expect(app.env).toBeDefined();
|
|
});
|
|
|
|
test('getPage / getNode 默认返回当前 page', () => {
|
|
const app = new App({
|
|
config: {
|
|
type: NodeType.ROOT,
|
|
id: 'app',
|
|
items: [{ type: NodeType.PAGE, id: 'p1', items: [{ id: 'btn', type: 'button' }] }],
|
|
},
|
|
});
|
|
expect(app.getPage()).toBe(app.page);
|
|
expect(app.getPage('p1')).toBe(app.page);
|
|
expect(app.getPage('not-exist')).toBeUndefined();
|
|
expect(app.getNode('btn')?.data.id).toBe('btn');
|
|
});
|
|
|
|
test('setPage 不存在时清空当前 page', () => {
|
|
const app = new App({
|
|
config: {
|
|
type: NodeType.ROOT,
|
|
id: 'app',
|
|
items: [{ type: NodeType.PAGE, id: 'p1', items: [] }],
|
|
},
|
|
});
|
|
app.setPage('not-exist');
|
|
expect(app.page).toBeUndefined();
|
|
});
|
|
|
|
test('runCode 执行代码块', async () => {
|
|
const fn = vi.fn();
|
|
const app = new App({
|
|
config: {
|
|
type: NodeType.ROOT,
|
|
id: 'app',
|
|
items: [{ type: NodeType.PAGE, id: 'p1', items: [] }],
|
|
codeBlocks: { c1: { name: 'c1', content: fn, params: [] } },
|
|
},
|
|
});
|
|
await app.runCode('c1', { p: 1 }, []);
|
|
expect(fn).toHaveBeenCalled();
|
|
});
|
|
|
|
test('runCode 抛错时进入 errorHandler', async () => {
|
|
const errorHandler = vi.fn();
|
|
const app = new App({
|
|
errorHandler,
|
|
config: {
|
|
type: NodeType.ROOT,
|
|
id: 'app',
|
|
items: [{ type: NodeType.PAGE, id: 'p1', items: [] }],
|
|
codeBlocks: {
|
|
c1: {
|
|
name: 'c1',
|
|
content: () => {
|
|
throw new Error('boom');
|
|
},
|
|
params: [],
|
|
},
|
|
},
|
|
},
|
|
});
|
|
await app.runCode('c1', {}, []);
|
|
expect(errorHandler).toHaveBeenCalled();
|
|
});
|
|
|
|
test('runDataSourceMethod 调用 schema methods 中的 content', async () => {
|
|
const fn = vi.fn().mockResolvedValue('ok');
|
|
const app = new App({
|
|
config: {
|
|
type: NodeType.ROOT,
|
|
id: 'app',
|
|
items: [{ type: NodeType.PAGE, id: 'p1', items: [] }],
|
|
dataSources: [
|
|
{
|
|
type: 'base',
|
|
id: 'ds_1',
|
|
fields: [],
|
|
methods: [{ name: 'doIt', content: fn, params: [] }],
|
|
events: [],
|
|
},
|
|
],
|
|
} as any,
|
|
});
|
|
await app.runDataSourceMethod('ds_1', 'doIt', { p: 1 }, []);
|
|
expect(fn).toHaveBeenCalled();
|
|
});
|
|
|
|
test('runDataSourceMethod 不存在的数据源直接返回', async () => {
|
|
const app = new App({
|
|
config: {
|
|
type: NodeType.ROOT,
|
|
id: 'app',
|
|
items: [{ type: NodeType.PAGE, id: 'p1', items: [] }],
|
|
},
|
|
});
|
|
await expect(app.runDataSourceMethod('not', 'm', {}, [])).resolves.toBeUndefined();
|
|
await expect(app.runDataSourceMethod('', '', {}, [])).resolves.toBeUndefined();
|
|
});
|
|
|
|
test('emit 触发 node 事件时走 eventHelper', () => {
|
|
const app = new App({
|
|
config: {
|
|
type: NodeType.ROOT,
|
|
id: 'app',
|
|
items: [
|
|
{
|
|
type: NodeType.PAGE,
|
|
id: 'p1',
|
|
items: [{ id: 'btn', type: 'button', events: [{ name: 'click', actions: [] }] }],
|
|
},
|
|
],
|
|
} as any,
|
|
});
|
|
const node = app.getNode('btn')!;
|
|
const result = app.emit('click', node, 'arg1');
|
|
expect(typeof result).toBe('boolean');
|
|
});
|
|
|
|
test('destroy 清理所有资源', () => {
|
|
const app = new App({
|
|
config: {
|
|
type: NodeType.ROOT,
|
|
id: 'app',
|
|
items: [{ type: NodeType.PAGE, id: 'p1', items: [{ id: 'btn', type: 'button' }] }],
|
|
},
|
|
});
|
|
app.destroy();
|
|
expect(app.page).toBeUndefined();
|
|
expect(app.dsl).toBeUndefined();
|
|
expect(app.components.size).toBe(0);
|
|
});
|
|
});
|