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

127 lines
4.0 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 { type MApp, NodeType } from '@tmagic/schema';
import App from '../src/App';
import Node from '../src/Node';
const baseDsl = (): MApp => ({
type: NodeType.ROOT,
id: 'app',
items: [
{
type: NodeType.PAGE,
id: 'p1',
items: [{ id: 'btn', type: 'button' }],
},
],
});
describe('Node 基础', () => {
test('实例化时初始化 events / style 默认值', () => {
const app = new App({ config: baseDsl() });
const node = app.page!.getNode('btn')!;
expect(node).toBeInstanceOf(Node);
expect(node.events).toEqual([]);
expect(node.style).toEqual({});
});
test('setData 更新 events / style 并触发 update-data 事件', () => {
const app = new App({ config: baseDsl() });
const node = app.page!.getNode('btn')!;
const handler = vi.fn();
node.on('update-data', handler);
node.setData({
id: 'btn',
type: 'button',
events: [{ name: 'click', actions: [] }],
style: { color: 'red' },
} as any);
expect(handler).toHaveBeenCalled();
expect(node.events).toHaveLength(1);
expect(node.style.color).toBe('red');
});
test('setInstance 与 setData 同步实例的 config', () => {
const app = new App({ config: baseDsl() });
const node = app.page!.getNode('btn')!;
const instance: any = {};
node.setInstance(instance);
node.setData({ id: 'btn', type: 'button', text: 'changed' } as any);
expect(instance.config?.text).toBe('changed');
});
test('frozen instance 时 setData 不抛错', () => {
const app = new App({ config: baseDsl() });
const node = app.page!.getNode('btn')!;
const frozen = Object.freeze({ __isVue: false });
node.setInstance(frozen);
expect(() => node.setData({ id: 'btn', type: 'button' } as any)).not.toThrow();
});
test('addEventToQueue 入队', () => {
const app = new App({ config: baseDsl() });
const node = app.page!.getNode('btn')!;
node.addEventToQueue({ method: 'm', fromCpt: null, args: [1, 2] });
expect((node as any).eventQueue).toHaveLength(1);
});
test('registerMethod (deprecated) 注入实例方法', () => {
const app = new App({ config: baseDsl() });
const node = app.page!.getNode('btn')!;
node.registerMethod({ doIt: () => 'ok', notFn: 'x' as any });
expect(node.instance.doIt()).toBe('ok');
expect(node.instance.notFn).toBeUndefined();
node.registerMethod(undefined as any);
});
test('runHookCode 函数式回退', async () => {
const app = new App({ config: baseDsl() });
const node = app.page!.getNode('btn')!;
const fn = vi.fn();
(node.data as any).created = fn;
await node.runHookCode('created');
expect(fn).toHaveBeenCalledWith(node);
});
test('runHookCode 数据格式不匹配时不报错', async () => {
const app = new App({ config: baseDsl() });
const node = app.page!.getNode('btn')!;
(node.data as any).onSomething = { hookType: 'other' };
await expect(node.runHookCode('onSomething')).resolves.toBeUndefined();
});
test('destroy 清理状态与监听', () => {
const app = new App({ config: baseDsl() });
const node = app.page!.getNode('btn')!;
const handler = vi.fn();
node.on('test', handler);
node.destroy();
node.emit('test');
expect(handler).not.toHaveBeenCalled();
expect(node.instance).toBeNull();
expect(node.events).toEqual([]);
});
test('created/destroy 生命周期触发 hook', async () => {
const app = new App({ config: baseDsl() });
const codeFn = vi.fn();
app.codeDsl = {
hello: { name: 'hello', content: codeFn, params: [] },
} as any;
const node = app.page!.getNode('btn')!;
(node.data as any).created = {
hookType: 'code',
hookData: [{ codeId: 'hello', params: {} }],
};
node.emit('created', null);
await new Promise((r) => setTimeout(r, 0));
expect(codeFn).toHaveBeenCalled();
});
});