mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-09-13 04:14:25 +08:00
fix(editor): 修复 eventsService resetState 响应式失效并在编辑器重置时清空
resetState 改为原地清空 reactive 对象以保留代理身份,避免 computed 不更新。 编辑器 reset 时同步调用 eventsService.resetState,并补充文档与单测。
This commit is contained in:
parent
b0d43dc277
commit
959c0322b6
@ -16,7 +16,11 @@
|
||||
|
||||
- **详情:**
|
||||
|
||||
批量设置多个组件类型的事件列表
|
||||
批量设置多个组件类型的事件列表。增量合并语义:只写入入参中出现的类型,已有的其他类型保持不变。
|
||||
|
||||
::: tip 切换 runtime 版本
|
||||
不同版本的 runtime 事件表不同,直接调用 `setEvents` 会让上一个版本独有的类型残留。是否需要清掉上一个版本的数据由业务自行决定,需要清掉时先调用 [`resetState`](#resetstate) 再写入新表。
|
||||
:::
|
||||
|
||||
- **示例:**
|
||||
|
||||
@ -47,7 +51,7 @@ eventsService.setEvents({
|
||||
|
||||
- **详情:**
|
||||
|
||||
设置指定组件类型的事件列表
|
||||
设置指定组件类型的事件列表,只影响该类型
|
||||
|
||||
- **示例:**
|
||||
|
||||
@ -106,7 +110,7 @@ eventsService.usePlugin({
|
||||
|
||||
- **详情:**
|
||||
|
||||
批量设置多个组件类型的方法列表
|
||||
批量设置多个组件类型的方法列表。语义与 `setEvents` 一致:增量合并,入参中不存在的类型保持不变。
|
||||
|
||||
- **示例:**
|
||||
|
||||
@ -138,7 +142,7 @@ eventsService.setMethods({
|
||||
|
||||
- **详情:**
|
||||
|
||||
设置指定组件类型的方法列表
|
||||
设置指定组件类型的方法列表,只影响该类型
|
||||
|
||||
- **示例:**
|
||||
|
||||
@ -209,14 +213,17 @@ eventsService.usePlugin({
|
||||
|
||||
- **详情:**
|
||||
|
||||
重置事件服务状态,清空所有事件和方法配置
|
||||
重置事件服务状态,清空所有事件和方法配置。`setEvents` / `setMethods` 是增量合并,切换 runtime 版本这类需要丢弃上一份事件表的场景,由业务在写入新表前自行调用本方法。
|
||||
|
||||
- **示例:**
|
||||
|
||||
```js
|
||||
import { eventsService } from '@tmagic/editor';
|
||||
|
||||
// 切到另一个版本的 runtime:先清空,再写入该版本的事件表
|
||||
eventsService.resetState();
|
||||
eventsService.setEvents(nextVersionEvents);
|
||||
eventsService.setMethods(nextVersionMethods);
|
||||
```
|
||||
|
||||
## destroy
|
||||
|
||||
@ -630,6 +630,10 @@ const propsValues = {
|
||||
该属性最终会设置到[eventsService](./eventsServiceMethods.md)中,所以也可直接调用[eventsService.setEvents()](./eventsServiceMethods.md#setEvents)与[eventsService.setMethods()](./eventsServiceMethods.md#setMethods)方法来配置
|
||||
:::
|
||||
|
||||
:::warning
|
||||
该属性每次变更都是增量合并,不会清掉上一次写入的类型。切换 runtime 版本时若需要丢弃旧版本的事件表,请自行调用 [eventsService.resetState()](./eventsServiceMethods.md#resetstate)
|
||||
:::
|
||||
|
||||
- **默认值:** `{}`
|
||||
|
||||
- **类型:** `Record<string, { events: EventOption[]; methods: EventOption[] }>`
|
||||
|
||||
@ -254,6 +254,7 @@ export const initServiceState = (
|
||||
uiService.resetState();
|
||||
componentListService.resetState();
|
||||
codeBlockService.resetState();
|
||||
eventsService.resetState();
|
||||
keybindingService.reset();
|
||||
depService.reset();
|
||||
});
|
||||
|
||||
@ -35,8 +35,8 @@ const canUsePluginMethods = {
|
||||
type AsyncMethodName = Writable<(typeof canUsePluginMethods)['async']>;
|
||||
type SyncMethodName = Writable<(typeof canUsePluginMethods)['sync']>;
|
||||
|
||||
let eventMap: Record<string, EventOption[]> = reactive({});
|
||||
let methodMap: Record<string, EventOption[]> = reactive({});
|
||||
const eventMap: Record<string, EventOption[]> = reactive({});
|
||||
const methodMap: Record<string, EventOption[]> = reactive({});
|
||||
|
||||
class Events extends BaseService {
|
||||
constructor() {
|
||||
@ -75,8 +75,9 @@ class Events extends BaseService {
|
||||
}
|
||||
|
||||
public resetState() {
|
||||
eventMap = reactive({});
|
||||
methodMap = reactive({});
|
||||
// 原地清空而不是重新赋值,保留 reactive 代理身份,已建立的 computed / 渲染副作用才能收到更新
|
||||
Object.keys(eventMap).forEach((type) => delete eventMap[type]);
|
||||
Object.keys(methodMap).forEach((type) => delete methodMap[type]);
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
|
||||
@ -8,6 +8,7 @@ import { defineComponent, h, nextTick } from 'vue';
|
||||
import { mount } from '@vue/test-utils';
|
||||
|
||||
import { DepTargetType } from '@tmagic/core';
|
||||
import { getNodes } from '@tmagic/utils';
|
||||
|
||||
import { initServiceEvents, initServiceState } from '@editor/initService';
|
||||
import * as logger from '@editor/utils/logger';
|
||||
@ -60,6 +61,7 @@ const mkServices = () => {
|
||||
...mkSvc('events'),
|
||||
setEvents: vi.fn(),
|
||||
setMethods: vi.fn(),
|
||||
resetState: vi.fn(),
|
||||
};
|
||||
const uiService: any = {
|
||||
...mkSvc('ui'),
|
||||
@ -210,8 +212,8 @@ describe('initServiceState', () => {
|
||||
eventMethodList: { typeA: { events: [{ name: 'click' }], methods: [{ name: 'm' }] } },
|
||||
} as any;
|
||||
mount(Wrap(props, services));
|
||||
expect(services.eventsService.setEvents).toHaveBeenCalled();
|
||||
expect(services.eventsService.setMethods).toHaveBeenCalled();
|
||||
expect(services.eventsService.setEvents).toHaveBeenCalledWith({ typeA: [{ name: 'click' }] });
|
||||
expect(services.eventsService.setMethods).toHaveBeenCalledWith({ typeA: [{ name: 'm' }] });
|
||||
});
|
||||
|
||||
test('datasourceConfigs 设置 form config', () => {
|
||||
@ -284,11 +286,44 @@ describe('initServiceState', () => {
|
||||
expect(services.uiService.resetState).toHaveBeenCalled();
|
||||
expect(services.componentListService.resetState).toHaveBeenCalled();
|
||||
expect(services.codeBlockService.resetState).toHaveBeenCalled();
|
||||
expect(services.eventsService.resetState).toHaveBeenCalled();
|
||||
expect(services.keybindingService.reset).toHaveBeenCalled();
|
||||
expect(services.depService.reset).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
const mkDataSourceManager = () => ({
|
||||
addDataSource: vi.fn(),
|
||||
removeDataSource: vi.fn(),
|
||||
get: vi.fn(() => ({
|
||||
setFields: vi.fn(),
|
||||
setData: vi.fn(),
|
||||
getDefaultData: vi.fn(() => ({})),
|
||||
})),
|
||||
init: vi.fn(),
|
||||
compiledNode: vi.fn((node: any) => node),
|
||||
});
|
||||
|
||||
/** renderer.runtime 直接就绪,getTMagicApp 走同步分支 */
|
||||
const mkReadyStage = (app: any) => {
|
||||
const runtime = {
|
||||
getApp: vi.fn(() => app),
|
||||
updateRootConfig: vi.fn(),
|
||||
updatePageId: vi.fn(),
|
||||
};
|
||||
return {
|
||||
renderer: {
|
||||
runtime,
|
||||
getRuntime: vi.fn(async () => runtime),
|
||||
once: vi.fn(),
|
||||
},
|
||||
select: vi.fn(),
|
||||
reloadIframe: vi.fn(),
|
||||
update: vi.fn(),
|
||||
runtime,
|
||||
};
|
||||
};
|
||||
|
||||
describe('initServiceEvents', () => {
|
||||
let services: ReturnType<typeof mkServices>;
|
||||
let emit: any;
|
||||
@ -499,4 +534,217 @@ describe('initServiceEvents', () => {
|
||||
});
|
||||
|
||||
// 因 services 中 editor.state 不是 reactive,stage watch 不会触发,跳过该测试场景
|
||||
|
||||
test('getTMagicApp 在 runtime 未就绪时等待 runtime-ready,并复用同一个 promise', async () => {
|
||||
const dataSourceManager = mkDataSourceManager();
|
||||
const app = { dsl: {}, dataSourceManager };
|
||||
let runtimeReady: any;
|
||||
const renderer: any = {
|
||||
runtime: null,
|
||||
getRuntime: vi.fn(),
|
||||
once: vi.fn((_event: string, cb: any) => {
|
||||
runtimeReady = cb;
|
||||
}),
|
||||
};
|
||||
services.editorService.state.stage = { renderer, select: vi.fn() };
|
||||
mount(WrapEvents({} as any, emit, services));
|
||||
|
||||
services.dataSourceService.emit('add', { id: 'd1', type: 'base' });
|
||||
services.dataSourceService.emit('add', { id: 'd2', type: 'base' });
|
||||
await nextTick();
|
||||
// 两次调用只应注册一次 runtime-ready 监听
|
||||
expect(renderer.once).toHaveBeenCalledTimes(1);
|
||||
|
||||
renderer.runtime = { getApp: () => app };
|
||||
runtimeReady();
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
expect(dataSourceManager.addDataSource).toHaveBeenCalledTimes(2);
|
||||
expect(dataSourceManager.init).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('getTMagicApp 在 stage 没有 renderer 时返回 undefined', async () => {
|
||||
services.editorService.state.stage = { select: vi.fn() };
|
||||
mount(WrapEvents({} as any, emit, services));
|
||||
|
||||
services.dataSourceService.emit('add', { id: 'd1', type: 'base' });
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
expect(services.depService.addTarget).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('ds-collected 事件把 dataSourceDeps 同步给 runtime app', async () => {
|
||||
const app: any = { dsl: { dataSourceDeps: null }, dataSourceManager: mkDataSourceManager() };
|
||||
services.editorService.state.stage = mkReadyStage(app);
|
||||
services.editorService.state.root = { id: 'r', dataSourceDeps: { d1: {} } };
|
||||
mount(WrapEvents({} as any, emit, services));
|
||||
|
||||
services.depService.emit('ds-collected');
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
expect(app.dsl.dataSourceDeps).toEqual({ d1: {} });
|
||||
});
|
||||
|
||||
test('rootChange items 是数组时更新画布 dsl', async () => {
|
||||
const app: any = { dsl: {}, dataSourceManager: mkDataSourceManager() };
|
||||
const stage = mkReadyStage(app);
|
||||
services.editorService.state.stage = stage;
|
||||
services.editorService.state.page = { id: 'p1' };
|
||||
services.editorService.state.node = { id: 'n1' };
|
||||
mount(WrapEvents({} as any, emit, services));
|
||||
|
||||
services.editorService.emit('root-change', {
|
||||
id: 'r',
|
||||
items: [{ id: 'n1', type: 'text' }],
|
||||
dataSources: [],
|
||||
dataSourceDeps: { d1: {} },
|
||||
codeBlocks: {},
|
||||
});
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
|
||||
expect(stage.runtime.updatePageId).toHaveBeenCalledWith('p1');
|
||||
expect(stage.runtime.updateRootConfig).toHaveBeenCalled();
|
||||
expect(stage.select).toHaveBeenCalledWith('n1');
|
||||
});
|
||||
|
||||
test('rootChange items 不是数组时清空依赖', async () => {
|
||||
services.editorService.state.root = { id: 'r' };
|
||||
mount(WrapEvents({} as any, emit, services));
|
||||
|
||||
const value: any = { id: 'r', dataSourceDeps: { a: {} }, dataSourceCondDeps: { b: {} } };
|
||||
services.editorService.emit('root-change', value);
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
expect(services.depService.clear).toHaveBeenCalled();
|
||||
expect(value.dataSourceDeps).toBeUndefined();
|
||||
expect(value.dataSourceCondDeps).toBeUndefined();
|
||||
});
|
||||
|
||||
test('rootChange 没有可选中节点时回落到 root 自身', async () => {
|
||||
services.editorService.getNodeById.mockReturnValue(null);
|
||||
mount(WrapEvents({} as any, emit, services));
|
||||
|
||||
const value: any = { id: 'r', items: [] };
|
||||
services.editorService.emit('root-change', value, { id: 'prev' });
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
expect(services.editorService.set).toHaveBeenCalledWith('nodes', [value]);
|
||||
expect(services.editorService.set).toHaveBeenCalledWith('parent', null);
|
||||
expect(services.editorService.set).toHaveBeenCalledWith('page', null);
|
||||
expect(emit).toHaveBeenCalledWith('update:modelValue', value);
|
||||
});
|
||||
|
||||
test('rootChange 有 items 时选中第一个节点', async () => {
|
||||
services.editorService.getNodeById.mockReturnValue(null);
|
||||
mount(WrapEvents({} as any, emit, services));
|
||||
|
||||
services.editorService.emit('root-change', { id: 'r', items: [{ id: 'first', type: 'page' }] });
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
expect(services.editorService.select).toHaveBeenCalledWith({ id: 'first', type: 'page' });
|
||||
});
|
||||
|
||||
test('update 事件:ROOT 节点、无 propPath、命中已收集依赖三种分支', async () => {
|
||||
services.editorService.state.root = { id: 'r', items: [] };
|
||||
services.depService.getTargets.mockReturnValue({
|
||||
t1: { deps: { n3: { keys: ['props.text'] } } },
|
||||
});
|
||||
mount(WrapEvents({} as any, emit, services));
|
||||
|
||||
services.editorService.emit('update', [
|
||||
{ newNode: { id: 'r', type: 'root' }, oldNode: { id: 'r', type: 'root' } },
|
||||
{
|
||||
newNode: { id: 'n2', type: 'text' },
|
||||
oldNode: { id: 'n2', type: 'text' },
|
||||
changeRecords: [{ value: 'x' }],
|
||||
},
|
||||
{
|
||||
newNode: { id: 'n3', type: 'text' },
|
||||
oldNode: { id: 'n3', type: 'text' },
|
||||
changeRecords: [{ propPath: 'props.text', value: 'x' }],
|
||||
},
|
||||
]);
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
expect(services.depService.collectIdle).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('dataSource update 修改 mocks / methods 分别只重建对应 target', async () => {
|
||||
const app: any = { dsl: {}, dataSourceManager: mkDataSourceManager() };
|
||||
services.editorService.state.stage = mkReadyStage(app);
|
||||
services.editorService.state.root = { id: 'r', items: [{ id: 'a', type: 'text' }] };
|
||||
mount(WrapEvents({} as any, emit, services));
|
||||
|
||||
services.dataSourceService.emit(
|
||||
'update',
|
||||
{ id: 'd1', type: 'base', fields: [], mocks: [{ useInEditor: true, data: { a: 1 } }] },
|
||||
{ changeRecords: [{ propPath: 'mocks' }] },
|
||||
);
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
expect(services.depService.removeTarget).toHaveBeenCalledWith('d1', DepTargetType.DATA_SOURCE);
|
||||
|
||||
services.depService.removeTarget.mockClear();
|
||||
services.dataSourceService.emit(
|
||||
'update',
|
||||
{ id: 'd1', type: 'base', fields: [], methods: [] },
|
||||
{ changeRecords: [{ propPath: 'methods.0.name' }] },
|
||||
);
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
expect(services.depService.removeTarget).toHaveBeenCalledWith('d1', DepTargetType.DATA_SOURCE_METHOD);
|
||||
});
|
||||
|
||||
test('dataSource update 无依赖变更时只刷新数据', async () => {
|
||||
const dataSourceManager = mkDataSourceManager();
|
||||
const app: any = { dsl: {}, dataSourceManager };
|
||||
services.editorService.state.stage = mkReadyStage(app);
|
||||
services.editorService.state.root = { id: 'r', items: [], dataSources: [{ id: 'd1' }] };
|
||||
mount(WrapEvents({} as any, emit, services));
|
||||
|
||||
services.dataSourceService.emit(
|
||||
'update',
|
||||
{ id: 'd1', type: 'base', fields: [] },
|
||||
{ changeRecords: [{ propPath: 'title' }, {}] },
|
||||
);
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
expect(dataSourceManager.get).toHaveBeenCalledWith('d1');
|
||||
expect(services.depService.clearIdleTasks).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('dataSource remove 重新收集依赖并从 app 中移除数据源', async () => {
|
||||
const dataSourceManager = mkDataSourceManager();
|
||||
const app: any = { dsl: {}, dataSourceManager };
|
||||
services.editorService.state.stage = mkReadyStage(app);
|
||||
services.editorService.state.root = {
|
||||
id: 'r',
|
||||
items: [],
|
||||
dataSources: [{ id: 'd1' }],
|
||||
dataSourceDeps: { d1: { n1: {} } },
|
||||
};
|
||||
mount(WrapEvents({} as any, emit, services));
|
||||
|
||||
services.dataSourceService.emit('remove', 'd1');
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
expect(dataSourceManager.removeDataSource).toHaveBeenCalledWith('d1');
|
||||
expect(services.depService.removeTarget).toHaveBeenCalledWith('d1', DepTargetType.DATA_SOURCE);
|
||||
expect(services.depService.removeTarget).toHaveBeenCalledWith('d1', DepTargetType.DATA_SOURCE_COND);
|
||||
expect(services.depService.removeTarget).toHaveBeenCalledWith('d1', DepTargetType.DATA_SOURCE_METHOD);
|
||||
expect(app.dsl.dataSources).toEqual([{ id: 'd1' }]);
|
||||
});
|
||||
|
||||
test('dataSource remove 收集未完成时不移除数据源', async () => {
|
||||
const dataSourceManager = mkDataSourceManager();
|
||||
const app: any = { dsl: {}, dataSourceManager };
|
||||
services.editorService.state.stage = mkReadyStage(app);
|
||||
services.editorService.state.root = { id: 'r', items: [] };
|
||||
vi.mocked(getNodes).mockReturnValueOnce([{ id: 'n1', type: 'text' }] as any);
|
||||
services.depService.collectIdle.mockResolvedValue(false);
|
||||
mount(WrapEvents({} as any, emit, services));
|
||||
|
||||
services.dataSourceService.emit('remove', 'd1');
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
expect(dataSourceManager.removeDataSource).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@ -16,11 +16,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { describe, expect, test } from 'vitest';
|
||||
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import events from '@editor/services/events';
|
||||
|
||||
describe('events', () => {
|
||||
beforeEach(() => {
|
||||
events.resetState();
|
||||
});
|
||||
|
||||
test('setEvent', () => {
|
||||
const event = [{ label: '点击', value: 'magic:common:events:click' }];
|
||||
events.setEvent('button', event);
|
||||
@ -42,6 +47,37 @@ describe('events', () => {
|
||||
expect(events.getEvent('text')).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('setEvents 增量合并,不动入参中不存在的类型', () => {
|
||||
events.setEvents({
|
||||
Image: [{ label: 'click', value: 'click' }],
|
||||
Text: [{ label: 'init', value: 'init' }],
|
||||
} as any);
|
||||
events.setEvents({
|
||||
Image: [{ label: 'hover', value: 'hover' }],
|
||||
} as any);
|
||||
expect(events.getEvent('image')).toEqual([{ label: 'hover', value: 'hover' }]);
|
||||
expect(events.getEvent('text')).toEqual([{ label: 'init', value: 'init' }]);
|
||||
});
|
||||
|
||||
test('setEvents 空对象是空操作', () => {
|
||||
events.setEvent('button', [{ label: 'click', value: 'click' }]);
|
||||
events.setEvents({});
|
||||
expect(events.getEvent('button')).toEqual([{ label: 'click', value: 'click' }]);
|
||||
});
|
||||
|
||||
test('setEvents 入参类型名按 toLine 归一后写入', () => {
|
||||
events.setEvent('foo-bar', [{ label: 'a', value: 'a' }]);
|
||||
events.setEvents({
|
||||
fooBar: [{ label: 'b', value: 'b' }],
|
||||
} as any);
|
||||
expect(events.getEvent('foo-bar')).toEqual([{ label: 'b', value: 'b' }]);
|
||||
});
|
||||
|
||||
test('setEvents 缺省列表按空数组写入', () => {
|
||||
events.setEvents({ button: undefined } as any);
|
||||
expect(events.getEvent('button')).toEqual([]);
|
||||
});
|
||||
|
||||
test('setMethods 批量设置', () => {
|
||||
events.setMethods({
|
||||
Image: [{ label: 'show', value: 'show' }],
|
||||
@ -49,6 +85,29 @@ describe('events', () => {
|
||||
expect(events.getMethod('image', {})).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('setMethods 增量合并,不动入参中不存在的类型', () => {
|
||||
events.setMethods({
|
||||
Image: [{ label: 'show', value: 'show' }],
|
||||
Video: [{ label: 'play', value: 'play' }],
|
||||
} as any);
|
||||
events.setMethods({
|
||||
Video: [{ label: 'pause', value: 'pause' }],
|
||||
} as any);
|
||||
expect(events.getMethod('video', {})).toEqual([{ label: 'pause', value: 'pause' }]);
|
||||
expect(events.getMethod('image', {})).toEqual([{ label: 'show', value: 'show' }]);
|
||||
});
|
||||
|
||||
test('setMethods 缺省列表按空数组写入', () => {
|
||||
events.setMethods({ video: undefined } as any);
|
||||
expect(events.getMethod('video')).toEqual([]);
|
||||
});
|
||||
|
||||
test('setMethods 空对象是空操作', () => {
|
||||
events.setMethod('button', [{ label: 'open', value: 'open' }]);
|
||||
events.setMethods({});
|
||||
expect(events.getMethod('button')).toEqual([{ label: 'open', value: 'open' }]);
|
||||
});
|
||||
|
||||
test('getEvent / getMethod 支持节点上下文参数', () => {
|
||||
const node = { id: 'n1', type: 'button' } as any;
|
||||
events.setEvent('button', [{ label: '点击', value: 'click' }]);
|
||||
@ -64,7 +123,58 @@ describe('events', () => {
|
||||
|
||||
test('resetState 清空所有事件 / 方法', () => {
|
||||
events.setEvent('foo', [{ label: 'l', value: 'v' }]);
|
||||
events.setMethod('foo', [{ label: 'm', value: 'm' }]);
|
||||
events.resetState();
|
||||
expect(events.getEvent('foo')).toEqual([]);
|
||||
expect(events.getMethod('foo')).toEqual([]);
|
||||
});
|
||||
|
||||
test('resetState 原地清空后仍可继续写入', () => {
|
||||
events.setEvent('foo', [{ label: 'l', value: 'v' }]);
|
||||
events.resetState();
|
||||
events.setEvent('bar', [{ label: 'click', value: 'click' }]);
|
||||
events.setMethod('bar', [{ label: 'open', value: 'open' }]);
|
||||
expect(events.getEvent('bar')).toEqual([{ label: 'click', value: 'click' }]);
|
||||
expect(events.getMethod('bar')).toEqual([{ label: 'open', value: 'open' }]);
|
||||
});
|
||||
|
||||
test('resetState 原地清空会使已有 computed 失效', () => {
|
||||
events.setEvent('foo', [{ label: 'l', value: 'v' }]);
|
||||
events.setMethod('foo', [{ label: 'm', value: 'm' }]);
|
||||
const eventList = computed(() => events.getEvent('foo'));
|
||||
const methodList = computed(() => events.getMethod('foo'));
|
||||
expect(eventList.value).toHaveLength(1);
|
||||
expect(methodList.value).toHaveLength(1);
|
||||
events.resetState();
|
||||
expect(eventList.value).toEqual([]);
|
||||
expect(methodList.value).toEqual([]);
|
||||
});
|
||||
|
||||
test('切换 runtime 版本:宿主先 resetState 再写入新版本事件表', () => {
|
||||
events.setEvents({
|
||||
button: [{ label: 'click', value: 'click' }],
|
||||
video: [{ label: 'play', value: 'play' }],
|
||||
} as any);
|
||||
|
||||
// 是否清掉上一个版本的数据由业务决定,需要清掉时自行调用 resetState
|
||||
events.resetState();
|
||||
events.setEvents({ button: [{ label: 'click', value: 'click' }] } as any);
|
||||
|
||||
expect(events.getEvent('video')).toEqual([]);
|
||||
expect(events.getEvent('button')).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('usePlugin 钩子生效,destroy 后重置状态并移除插件', () => {
|
||||
const afterGetEvent = vi.fn((result: any[]) => [...result, { label: 'extra', value: 'extra' }]);
|
||||
events.usePlugin({ afterGetEvent } as any);
|
||||
events.setEvent('button', [{ label: 'click', value: 'click' }]);
|
||||
expect(events.getEvent('button')).toHaveLength(2);
|
||||
|
||||
events.destroy();
|
||||
expect(events.getEvent('button')).toEqual([]);
|
||||
|
||||
events.setEvent('button', [{ label: 'click', value: 'click' }]);
|
||||
expect(events.getEvent('button')).toHaveLength(1);
|
||||
expect(afterGetEvent).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user