mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2025-12-13 04:03:07 +00:00
test: increase branch coverage percentage of designer to 81.66%
This commit is contained in:
parent
3dd0b6d0a8
commit
8f237b1089
@ -6,7 +6,8 @@
|
|||||||
],
|
],
|
||||||
"nohoist": [
|
"nohoist": [
|
||||||
"**/css-modules-typescript-loader",
|
"**/css-modules-typescript-loader",
|
||||||
"**/@alife/theme-lowcode-*"
|
"**/@alifc/theme-lowcode-*",
|
||||||
|
"**/jest"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ const jestConfig = {
|
|||||||
// // '^.+\\.(js|jsx)$': 'babel-jest',
|
// // '^.+\\.(js|jsx)$': 'babel-jest',
|
||||||
// },
|
// },
|
||||||
// testMatch: ['**/document/node/node.test.ts'],
|
// testMatch: ['**/document/node/node.test.ts'],
|
||||||
// testMatch: ['**/component-meta.test.ts'],
|
// testMatch: ['**/history/history.test.ts'],
|
||||||
// testMatch: ['**/plugin/plugin-manager.test.ts'],
|
// testMatch: ['**/plugin/plugin-manager.test.ts'],
|
||||||
// testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
|
// testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
|
||||||
transformIgnorePatterns: [
|
transformIgnorePatterns: [
|
||||||
|
|||||||
@ -3,27 +3,12 @@ import { autorun, reaction, mobx, untracked, globalContext, Editor } from '@alil
|
|||||||
import { NodeSchema } from '@alilc/lowcode-types';
|
import { NodeSchema } from '@alilc/lowcode-types';
|
||||||
import { History as ShellHistory } from '@alilc/lowcode-shell';
|
import { History as ShellHistory } from '@alilc/lowcode-shell';
|
||||||
|
|
||||||
// TODO: cache to localStorage
|
export interface Serialization<K = NodeSchema, T = string> {
|
||||||
|
serialize(data: K): T;
|
||||||
export interface Serialization<T = any> {
|
unserialize(data: T): K;
|
||||||
serialize(data: NodeSchema): T;
|
|
||||||
unserialize(data: T): NodeSchema;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentSerialization: Serialization<any> = {
|
export class History<T = NodeSchema> {
|
||||||
serialize(data: NodeSchema): string {
|
|
||||||
return JSON.stringify(data);
|
|
||||||
},
|
|
||||||
unserialize(data: string) {
|
|
||||||
return JSON.parse(data);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export function setSerialization(serialization: Serialization) {
|
|
||||||
currentSerialization = serialization;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class History {
|
|
||||||
private session: Session;
|
private session: Session;
|
||||||
|
|
||||||
private records: Session[];
|
private records: Session[];
|
||||||
@ -34,16 +19,29 @@ export class History {
|
|||||||
|
|
||||||
private asleep = false;
|
private asleep = false;
|
||||||
|
|
||||||
constructor(logger: () => any, private redoer: (data: NodeSchema) => void, private timeGap: number = 1000) {
|
private currentSerialization: Serialization<T, string> = {
|
||||||
|
serialize(data: T): string {
|
||||||
|
return JSON.stringify(data);
|
||||||
|
},
|
||||||
|
unserialize(data: string) {
|
||||||
|
return JSON.parse(data);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
setSerialization(serialization: Serialization<T, string>) {
|
||||||
|
this.currentSerialization = serialization;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(dataFn: () => T, private redoer: (data: T) => void, private timeGap: number = 1000) {
|
||||||
this.session = new Session(0, null, this.timeGap);
|
this.session = new Session(0, null, this.timeGap);
|
||||||
this.records = [this.session];
|
this.records = [this.session];
|
||||||
|
|
||||||
reaction(() => {
|
reaction(() => {
|
||||||
return logger();
|
return dataFn();
|
||||||
}, (data) => {
|
}, (data: T) => {
|
||||||
if (this.asleep) return;
|
if (this.asleep) return;
|
||||||
untracked(() => {
|
untracked(() => {
|
||||||
const log = currentSerialization.serialize(data);
|
const log = this.currentSerialization.serialize(data);
|
||||||
if (this.session.isActive()) {
|
if (this.session.isActive()) {
|
||||||
this.session.log(log);
|
this.session.log(log);
|
||||||
} else {
|
} else {
|
||||||
@ -98,9 +96,9 @@ export class History {
|
|||||||
|
|
||||||
this.sleep();
|
this.sleep();
|
||||||
try {
|
try {
|
||||||
this.redoer(currentSerialization.unserialize(hotData));
|
this.redoer(this.currentSerialization.unserialize(hotData));
|
||||||
this.emitter.emit('cursor', hotData);
|
this.emitter.emit('cursor', hotData);
|
||||||
} catch (e) {
|
} catch (e) /* istanbul ignore next */ {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +199,7 @@ export class History {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Session {
|
export class Session {
|
||||||
private _data: any;
|
private _data: any;
|
||||||
|
|
||||||
private activeTimer: any;
|
private activeTimer: any;
|
||||||
|
|||||||
@ -148,7 +148,7 @@ export class LowCodePluginManager implements ILowCodePluginManager {
|
|||||||
for (const pluginName of sequence) {
|
for (const pluginName of sequence) {
|
||||||
try {
|
try {
|
||||||
await this.pluginsMap.get(pluginName)!.init();
|
await this.pluginsMap.get(pluginName)!.init();
|
||||||
} catch (e) {
|
} catch (e) /* istanbul ignore next */ {
|
||||||
logger.error(
|
logger.error(
|
||||||
`Failed to init plugin:${pluginName}, it maybe affect those plugins which depend on this.`,
|
`Failed to init plugin:${pluginName}, it maybe affect those plugins which depend on this.`,
|
||||||
);
|
);
|
||||||
@ -189,6 +189,7 @@ export class LowCodePluginManager implements ILowCodePluginManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
setDisabled(pluginName: string, flag = true) {
|
setDisabled(pluginName: string, flag = true) {
|
||||||
logger.warn(`plugin:${pluginName} has been set disable:${flag}`);
|
logger.warn(`plugin:${pluginName} has been set disable:${flag}`);
|
||||||
this.pluginsMap.get(pluginName)?.setDisabled(flag);
|
this.pluginsMap.get(pluginName)?.setDisabled(flag);
|
||||||
|
|||||||
@ -2,7 +2,6 @@ export class DocumentModel {
|
|||||||
a = 1;
|
a = 1;
|
||||||
c = {};
|
c = {};
|
||||||
constructor() {
|
constructor() {
|
||||||
console.log('xxxxxxxxxxxxxxxxxxxx');
|
|
||||||
const b = { x: { y: 2 } };
|
const b = { x: { y: 2 } };
|
||||||
const c: number = 2;
|
const c: number = 2;
|
||||||
this.a = b?.x?.y;
|
this.a = b?.x?.y;
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`History data function & records 1`] = `"{\\"data\\":1,\\"children\\":[{\\"data\\":2,\\"children\\":[]}]}"`;
|
||||||
|
|
||||||
|
exports[`History data function & records 2`] = `"{\\"data\\":3,\\"children\\":[{\\"data\\":2,\\"children\\":[]}]}"`;
|
||||||
|
|
||||||
|
exports[`History data function & records 3`] = `"{\\"data\\":5,\\"children\\":[{\\"data\\":2,\\"children\\":[]}]}"`;
|
||||||
|
|
||||||
|
exports[`History data function & records 4`] = `"{\\"data\\":7,\\"children\\":[{\\"data\\":2,\\"children\\":[]}]}"`;
|
||||||
353
packages/designer/tests/document/history/history.test.ts
Normal file
353
packages/designer/tests/document/history/history.test.ts
Normal file
@ -0,0 +1,353 @@
|
|||||||
|
import '../../fixtures/window';
|
||||||
|
import { mobx, makeAutoObservable, globalContext, Editor } from '@alilc/lowcode-editor-core';
|
||||||
|
import { History } from '../../../src/document/history';
|
||||||
|
import { delay } from '../../utils/misc';
|
||||||
|
|
||||||
|
class Node {
|
||||||
|
data: number;
|
||||||
|
children: Node[] = [];
|
||||||
|
|
||||||
|
constructor(data: number) {
|
||||||
|
makeAutoObservable(this);
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
addNode(node: Node) {
|
||||||
|
this.children.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
toObject() {
|
||||||
|
return {
|
||||||
|
data: this.data,
|
||||||
|
children: this.children.map((c) => c.toObject()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let tree: Node = null;
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = new Node(1);
|
||||||
|
tree.addNode(new Node(2));
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
tree = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('History', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
globalContext.register(new Editor(), Editor);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('data function & records', async () => {
|
||||||
|
const mockRedoFn = jest.fn();
|
||||||
|
const mockDataFn = jest.fn();
|
||||||
|
const history = new History<Node>(() => {
|
||||||
|
const data = tree.toObject();
|
||||||
|
mockDataFn(data);
|
||||||
|
return data;
|
||||||
|
}, mockRedoFn);
|
||||||
|
|
||||||
|
expect(mockDataFn).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mockDataFn).toHaveBeenCalledWith({ data: 1, children: [{ data: 2, children: [] }] });
|
||||||
|
expect(history.hotData).toMatchSnapshot();
|
||||||
|
// @ts-ignore
|
||||||
|
expect(history.session.cursor).toBe(0);
|
||||||
|
// @ts-ignore
|
||||||
|
expect(history.records).toHaveLength(1);
|
||||||
|
|
||||||
|
tree.data = 3;
|
||||||
|
expect(mockDataFn).toHaveBeenCalledTimes(2);
|
||||||
|
expect(mockDataFn).toHaveBeenCalledWith({ data: 3, children: [{ data: 2, children: [] }] });
|
||||||
|
expect(history.hotData).toMatchSnapshot();
|
||||||
|
// @ts-ignore
|
||||||
|
expect(history.session.cursor).toBe(0);
|
||||||
|
// @ts-ignore
|
||||||
|
expect(history.records).toHaveLength(1);
|
||||||
|
|
||||||
|
// modify data after timeGap
|
||||||
|
await delay(1200);
|
||||||
|
tree.data = 5;
|
||||||
|
expect(mockDataFn).toHaveBeenCalledTimes(3);
|
||||||
|
expect(mockDataFn).toHaveBeenCalledWith({ data: 5, children: [{ data: 2, children: [] }] });
|
||||||
|
expect(history.hotData).toMatchSnapshot();
|
||||||
|
// @ts-ignore
|
||||||
|
expect(history.session.cursor).toBe(1);
|
||||||
|
// @ts-ignore
|
||||||
|
expect(history.records).toHaveLength(2);
|
||||||
|
|
||||||
|
history.setSerialization({
|
||||||
|
serialize(data: Node): string {
|
||||||
|
return JSON.stringify(data);
|
||||||
|
},
|
||||||
|
unserialize(data: string) {
|
||||||
|
return JSON.parse(data);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// modify data after timeGap
|
||||||
|
await delay(1200);
|
||||||
|
tree.data = 7;
|
||||||
|
expect(mockDataFn).toHaveBeenCalledTimes(4);
|
||||||
|
expect(mockDataFn).toHaveBeenCalledWith({ data: 7, children: [{ data: 2, children: [] }] });
|
||||||
|
expect(history.hotData).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isSavePoint & savePoint', async () => {
|
||||||
|
const history = new History<Node>(
|
||||||
|
() => {
|
||||||
|
const data = tree.toObject();
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(history.isSavePoint()).toBeFalsy();
|
||||||
|
expect(history.isModified()).toBeFalsy();
|
||||||
|
|
||||||
|
await delay(1200);
|
||||||
|
tree.data = 3;
|
||||||
|
expect(history.isSavePoint()).toBeTruthy();
|
||||||
|
|
||||||
|
history.savePoint();
|
||||||
|
expect(history.isSavePoint()).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('go & forward & back & onCursor', async () => {
|
||||||
|
const mockRedoFn = jest.fn();
|
||||||
|
const mockCursorFn = jest.fn();
|
||||||
|
const mockStateFn = jest.fn();
|
||||||
|
const history = new History<Node>(
|
||||||
|
() => {
|
||||||
|
const data = tree.toObject();
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
(data) => {
|
||||||
|
mockRedoFn(data);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// undoable ❌ & redoable ❌ & modified ❌
|
||||||
|
expect(history.getState()).toBe(0);
|
||||||
|
|
||||||
|
await delay(1200);
|
||||||
|
tree.data = 3;
|
||||||
|
|
||||||
|
await delay(1200);
|
||||||
|
tree.data = 5;
|
||||||
|
|
||||||
|
await delay(1200);
|
||||||
|
tree.data = 7;
|
||||||
|
|
||||||
|
const dataCursor0 = { data: 1, children: [{ data: 2, children: [] }] };
|
||||||
|
const dataCursor1 = { data: 3, children: [{ data: 2, children: [] }] };
|
||||||
|
const dataCursor2 = { data: 5, children: [{ data: 2, children: [] }] };
|
||||||
|
const dataCursor3 = { data: 7, children: [{ data: 2, children: [] }] };
|
||||||
|
|
||||||
|
// redoable ❌
|
||||||
|
expect(history.getState()).toBe(7 - 2);
|
||||||
|
|
||||||
|
const off1 = history.onCursor(mockCursorFn);
|
||||||
|
const off2 = history.onStateChange(mockStateFn);
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
expect(history.records).toHaveLength(4);
|
||||||
|
// @ts-ignore
|
||||||
|
expect(history.session.cursor).toBe(3);
|
||||||
|
|
||||||
|
// step 1
|
||||||
|
history.back();
|
||||||
|
expect(mockCursorFn).toHaveBeenNthCalledWith(
|
||||||
|
1,
|
||||||
|
JSON.stringify(dataCursor2),
|
||||||
|
);
|
||||||
|
expect(mockStateFn).toHaveBeenNthCalledWith(1, 7);
|
||||||
|
expect(mockRedoFn).toHaveBeenNthCalledWith(1, dataCursor2);
|
||||||
|
|
||||||
|
// step 2
|
||||||
|
history.back();
|
||||||
|
expect(mockCursorFn).toHaveBeenNthCalledWith(
|
||||||
|
2,
|
||||||
|
JSON.stringify(dataCursor1),
|
||||||
|
);
|
||||||
|
expect(mockStateFn).toHaveBeenNthCalledWith(2, 7);
|
||||||
|
expect(mockRedoFn).toHaveBeenNthCalledWith(2, dataCursor1);
|
||||||
|
|
||||||
|
// step 3
|
||||||
|
history.back();
|
||||||
|
expect(mockCursorFn).toHaveBeenNthCalledWith(
|
||||||
|
3,
|
||||||
|
JSON.stringify(dataCursor0),
|
||||||
|
);
|
||||||
|
expect(mockStateFn).toHaveBeenNthCalledWith(3, 7 - 4 - 1);
|
||||||
|
expect(mockRedoFn).toHaveBeenNthCalledWith(3, dataCursor0);
|
||||||
|
|
||||||
|
// step 4
|
||||||
|
history.forward();
|
||||||
|
expect(mockCursorFn).toHaveBeenNthCalledWith(
|
||||||
|
4,
|
||||||
|
JSON.stringify(dataCursor1),
|
||||||
|
);
|
||||||
|
expect(mockStateFn).toHaveBeenNthCalledWith(4, 7);
|
||||||
|
expect(mockRedoFn).toHaveBeenNthCalledWith(4, dataCursor1);
|
||||||
|
|
||||||
|
// step 5
|
||||||
|
history.forward();
|
||||||
|
expect(mockCursorFn).toHaveBeenNthCalledWith(
|
||||||
|
5,
|
||||||
|
JSON.stringify(dataCursor2),
|
||||||
|
);
|
||||||
|
expect(mockStateFn).toHaveBeenNthCalledWith(5, 7);
|
||||||
|
expect(mockRedoFn).toHaveBeenNthCalledWith(5, dataCursor2);
|
||||||
|
|
||||||
|
// step 6
|
||||||
|
history.go(3);
|
||||||
|
expect(mockCursorFn).toHaveBeenNthCalledWith(
|
||||||
|
6,
|
||||||
|
JSON.stringify(dataCursor3),
|
||||||
|
);
|
||||||
|
expect(mockStateFn).toHaveBeenNthCalledWith(6, 7 - 2);
|
||||||
|
expect(mockRedoFn).toHaveBeenNthCalledWith(6, dataCursor3);
|
||||||
|
|
||||||
|
// step 7
|
||||||
|
history.go(0);
|
||||||
|
expect(mockCursorFn).toHaveBeenNthCalledWith(
|
||||||
|
7,
|
||||||
|
JSON.stringify(dataCursor0),
|
||||||
|
);
|
||||||
|
expect(mockStateFn).toHaveBeenNthCalledWith(7, 7 - 4 - 1);
|
||||||
|
expect(mockRedoFn).toHaveBeenNthCalledWith(7, dataCursor0);
|
||||||
|
|
||||||
|
off1();
|
||||||
|
off2();
|
||||||
|
mockStateFn.mockClear();
|
||||||
|
mockCursorFn.mockClear();
|
||||||
|
history.go(1);
|
||||||
|
expect(mockStateFn).not.toHaveBeenCalled();
|
||||||
|
expect(mockCursorFn).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('go() - edge case of cursor', async () => {
|
||||||
|
const mockRedoFn = jest.fn();
|
||||||
|
const mockCursorFn = jest.fn();
|
||||||
|
const mockStateFn = jest.fn();
|
||||||
|
const history = new History<Node>(
|
||||||
|
() => {
|
||||||
|
const data = tree.toObject();
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
(data) => {
|
||||||
|
mockRedoFn(data);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
await delay(1200);
|
||||||
|
tree.data = 3;
|
||||||
|
|
||||||
|
await delay(1200);
|
||||||
|
tree.data = 5;
|
||||||
|
|
||||||
|
history.go(-1);
|
||||||
|
// @ts-ignore
|
||||||
|
expect(history.session.cursor).toBe(0);
|
||||||
|
|
||||||
|
history.go(3);
|
||||||
|
// @ts-ignore
|
||||||
|
expect(history.session.cursor).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('destroy()', async () => {
|
||||||
|
const history = new History<Node>(
|
||||||
|
() => {
|
||||||
|
const data = tree.toObject();
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
(data) => {
|
||||||
|
mockRedoFn(data);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
history.destroy();
|
||||||
|
// @ts-ignore
|
||||||
|
expect(history.records).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('internalToShellHistory()', async () => {
|
||||||
|
const history = new History<Node>(
|
||||||
|
() => {
|
||||||
|
const data = tree.toObject();
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
(data) => {
|
||||||
|
mockRedoFn(data);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(history.internalToShellHistory().isModified).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sleep & wakeup', async () => {
|
||||||
|
const mockRedoFn = jest.fn();
|
||||||
|
const history = new History<Node>(
|
||||||
|
() => {
|
||||||
|
const data = tree.toObject();
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
(data) => {
|
||||||
|
mockRedoFn(data);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
history.sleep();
|
||||||
|
|
||||||
|
await delay(1200);
|
||||||
|
tree.data = 3;
|
||||||
|
// no record has been pushed into records because of history is asleep.
|
||||||
|
// @ts-ignore
|
||||||
|
expect(history.records).toHaveLength(1);
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
history.wakeup();
|
||||||
|
tree.data = 4;
|
||||||
|
// @ts-ignore
|
||||||
|
expect(history.records).toHaveLength(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('History - errors', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
globalContext.replace(Editor, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('no editor', () => {
|
||||||
|
const history = new History<Node>(
|
||||||
|
() => {
|
||||||
|
const data = tree.toObject();
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
(data) => {
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
history.back();
|
||||||
|
history.forward();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('no session', () => {
|
||||||
|
const history = new History<Node>(
|
||||||
|
() => {
|
||||||
|
const data = tree.toObject();
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
(data) => {
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
history.session = undefined;
|
||||||
|
history.back();
|
||||||
|
history.forward();
|
||||||
|
history.savePoint();
|
||||||
|
});
|
||||||
|
});
|
||||||
57
packages/designer/tests/document/history/session.test.ts
Normal file
57
packages/designer/tests/document/history/session.test.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import '../../fixtures/window';
|
||||||
|
import { Session } from '../../../src/document/history';
|
||||||
|
import { delay } from '../../utils/misc';
|
||||||
|
|
||||||
|
describe('Session', () => {
|
||||||
|
it('constructor', () => {
|
||||||
|
const session = new Session(1, { a: 1 });
|
||||||
|
expect(session.cursor).toBe(1);
|
||||||
|
expect(session.data).toEqual({ a: 1 });
|
||||||
|
// @ts-ignore
|
||||||
|
expect(session.timeGap).toBe(1000);
|
||||||
|
expect(session.isActive()).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('log()', () => {
|
||||||
|
const session = new Session(1, { a: 1 });
|
||||||
|
|
||||||
|
session.log({ a: 2 });
|
||||||
|
session.log({ a: 3 });
|
||||||
|
expect(session.data).toEqual({ a: 3 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('end()', () => {
|
||||||
|
const session = new Session(1, { a: 1 });
|
||||||
|
|
||||||
|
session.end();
|
||||||
|
expect(session.isActive()).toBeFalsy();
|
||||||
|
session.log({ a: 2 });
|
||||||
|
// log is not possible if current session is inactive
|
||||||
|
expect(session.data).toEqual({ a: 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('timeGap', async () => {
|
||||||
|
const session = new Session(1, { a: 1 });
|
||||||
|
|
||||||
|
expect(session.isActive()).toBeTruthy();
|
||||||
|
await delay(1200);
|
||||||
|
expect(session.isActive()).toBeFalsy();
|
||||||
|
session.log({ a: 2 });
|
||||||
|
// log is not possible if current session is inactive
|
||||||
|
expect(session.data).toEqual({ a: 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('custom timeGap', async () => {
|
||||||
|
const session = new Session(1, { a: 1 }, 2000);
|
||||||
|
|
||||||
|
expect(session.isActive()).toBeTruthy();
|
||||||
|
await delay(1200);
|
||||||
|
expect(session.isActive()).toBeTruthy();
|
||||||
|
await delay(1000);
|
||||||
|
expect(session.isActive()).toBeFalsy();
|
||||||
|
session.log({ a: 2 });
|
||||||
|
// log is not possible if current session is inactive
|
||||||
|
expect(session.data).toEqual({ a: 1 });
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -2,6 +2,7 @@ import '../fixtures/window';
|
|||||||
import { Editor, engineConfig } from '@alilc/lowcode-editor-core';
|
import { Editor, engineConfig } from '@alilc/lowcode-editor-core';
|
||||||
import { LowCodePluginManager } from '../../src/plugin/plugin-manager';
|
import { LowCodePluginManager } from '../../src/plugin/plugin-manager';
|
||||||
import { ILowCodePluginContext, ILowCodePluginManager } from '../../src/plugin/plugin-types';
|
import { ILowCodePluginContext, ILowCodePluginManager } from '../../src/plugin/plugin-types';
|
||||||
|
|
||||||
const editor = new Editor();
|
const editor = new Editor();
|
||||||
|
|
||||||
describe('plugin 测试', () => {
|
describe('plugin 测试', () => {
|
||||||
@ -15,14 +16,14 @@ describe('plugin 测试', () => {
|
|||||||
|
|
||||||
it('注册插件,插件参数生成函数能被调用,且能拿到正确的 ctx ', () => {
|
it('注册插件,插件参数生成函数能被调用,且能拿到正确的 ctx ', () => {
|
||||||
const mockFn = jest.fn();
|
const mockFn = jest.fn();
|
||||||
const creater = (ctx: ILowCodePluginContext) => {
|
const creator2 = (ctx: ILowCodePluginContext) => {
|
||||||
mockFn(ctx);
|
mockFn(ctx);
|
||||||
return {
|
return {
|
||||||
init: jest.fn(),
|
init: jest.fn(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
creater.pluginName = 'demo1';
|
creator2.pluginName = 'demo1';
|
||||||
pluginManager.register(creater);
|
pluginManager.register(creator2);
|
||||||
|
|
||||||
const [expectedCtx] = mockFn.mock.calls[0];
|
const [expectedCtx] = mockFn.mock.calls[0];
|
||||||
expect(expectedCtx).toHaveProperty('project');
|
expect(expectedCtx).toHaveProperty('project');
|
||||||
@ -39,7 +40,7 @@ describe('plugin 测试', () => {
|
|||||||
|
|
||||||
it('注册插件,调用插件 init 方法', async () => {
|
it('注册插件,调用插件 init 方法', async () => {
|
||||||
const mockFn = jest.fn();
|
const mockFn = jest.fn();
|
||||||
const creater = (ctx: ILowCodePluginContext) => {
|
const creator2 = (ctx: ILowCodePluginContext) => {
|
||||||
return {
|
return {
|
||||||
init: mockFn,
|
init: mockFn,
|
||||||
exports() {
|
exports() {
|
||||||
@ -50,8 +51,8 @@ describe('plugin 测试', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
creater.pluginName = 'demo1';
|
creator2.pluginName = 'demo1';
|
||||||
pluginManager.register(creater);
|
pluginManager.register(creator2);
|
||||||
await pluginManager.init();
|
await pluginManager.init();
|
||||||
expect(pluginManager.size).toBe(1);
|
expect(pluginManager.size).toBe(1);
|
||||||
expect(pluginManager.has('demo1')).toBeTruthy();
|
expect(pluginManager.has('demo1')).toBeTruthy();
|
||||||
@ -59,35 +60,52 @@ describe('plugin 测试', () => {
|
|||||||
expect(pluginManager.demo1).toBeTruthy();
|
expect(pluginManager.demo1).toBeTruthy();
|
||||||
expect(pluginManager.demo1.x).toBe(1);
|
expect(pluginManager.demo1.x).toBe(1);
|
||||||
expect(pluginManager.demo1.y).toBe(2);
|
expect(pluginManager.demo1.y).toBe(2);
|
||||||
|
expect(pluginManager.demo1.z).toBeUndefined();
|
||||||
expect(mockFn).toHaveBeenCalled();
|
expect(mockFn).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('注册插件,调用 setDisabled 方法', async () => {
|
it('注册插件,调用 setDisabled 方法', async () => {
|
||||||
const mockFn = jest.fn();
|
const mockFn = jest.fn();
|
||||||
const creater = (ctx: ILowCodePluginContext) => {
|
const creator2 = (ctx: ILowCodePluginContext) => {
|
||||||
return {
|
return {
|
||||||
init: mockFn,
|
init: mockFn,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
creater.pluginName = 'demo1';
|
creator2.pluginName = 'demo1';
|
||||||
|
|
||||||
pluginManager.register(creater);
|
pluginManager.register(creator2);
|
||||||
await pluginManager.init();
|
await pluginManager.init();
|
||||||
expect(pluginManager.demo1).toBeTruthy();
|
expect(pluginManager.demo1).toBeTruthy();
|
||||||
pluginManager.setDisabled('demo1', true);
|
pluginManager.setDisabled('demo1', true);
|
||||||
expect(pluginManager.demo1).toBeUndefined();
|
expect(pluginManager.demo1).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('注册插件,调用 plugin.setDisabled 方法', async () => {
|
||||||
|
const mockFn = jest.fn();
|
||||||
|
const creator2 = (ctx: ILowCodePluginContext) => {
|
||||||
|
return {
|
||||||
|
init: mockFn,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
creator2.pluginName = 'demo1';
|
||||||
|
|
||||||
|
pluginManager.register(creator2);
|
||||||
|
await pluginManager.init();
|
||||||
|
expect(pluginManager.demo1).toBeTruthy();
|
||||||
|
pluginManager.get('demo1').setDisabled();
|
||||||
|
expect(pluginManager.demo1).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
it('删除插件,调用插件 destroy 方法', async () => {
|
it('删除插件,调用插件 destroy 方法', async () => {
|
||||||
const mockFn = jest.fn();
|
const mockFn = jest.fn();
|
||||||
const creater = (ctx: ILowCodePluginContext) => {
|
const creator2 = (ctx: ILowCodePluginContext) => {
|
||||||
return {
|
return {
|
||||||
init: jest.fn(),
|
init: jest.fn(),
|
||||||
destroy: mockFn,
|
destroy: mockFn,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
creater.pluginName = 'demo1';
|
creator2.pluginName = 'demo1';
|
||||||
pluginManager.register(creater);
|
pluginManager.register(creator2);
|
||||||
|
|
||||||
await pluginManager.init();
|
await pluginManager.init();
|
||||||
await pluginManager.delete('demo1');
|
await pluginManager.delete('demo1');
|
||||||
@ -95,109 +113,185 @@ describe('plugin 测试', () => {
|
|||||||
await pluginManager.delete('non-existing');
|
await pluginManager.delete('non-existing');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('dep 依赖', async () => {
|
describe('dependencies 依赖', () => {
|
||||||
const mockFn = jest.fn();
|
it('dependencies 依赖', async () => {
|
||||||
const creater1 = (ctx: ILowCodePluginContext) => {
|
const mockFn = jest.fn();
|
||||||
return {
|
const creator21 = (ctx: ILowCodePluginContext) => {
|
||||||
// dep: ['demo2'],
|
return {
|
||||||
init: () => mockFn('demo1'),
|
init: () => mockFn('demo1'),
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
creator21.pluginName = 'demo1';
|
||||||
creater1.pluginName = 'demo1';
|
creator21.meta = {
|
||||||
creater1.meta = {
|
dependencies: ['demo2'],
|
||||||
dependencies: ['demo2'],
|
|
||||||
};
|
|
||||||
pluginManager.register(creater1);
|
|
||||||
const creater2 = (ctx: ILowCodePluginContext) => {
|
|
||||||
return {
|
|
||||||
init: () => mockFn('demo2'),
|
|
||||||
};
|
};
|
||||||
};
|
pluginManager.register(creator21);
|
||||||
creater2.pluginName = 'demo2';
|
const creator22 = (ctx: ILowCodePluginContext) => {
|
||||||
pluginManager.register(creater2);
|
return {
|
||||||
|
init: () => mockFn('demo2'),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
creator22.pluginName = 'demo2';
|
||||||
|
pluginManager.register(creator22);
|
||||||
|
|
||||||
await pluginManager.init();
|
await pluginManager.init();
|
||||||
expect(mockFn).toHaveBeenNthCalledWith(1, 'demo2');
|
expect(mockFn).toHaveBeenNthCalledWith(1, 'demo2');
|
||||||
expect(mockFn).toHaveBeenNthCalledWith(2, 'demo1');
|
expect(mockFn).toHaveBeenNthCalledWith(2, 'demo1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('dependencies 依赖 - string', async () => {
|
||||||
|
const mockFn = jest.fn();
|
||||||
|
const creator21 = (ctx: ILowCodePluginContext) => {
|
||||||
|
return {
|
||||||
|
init: () => mockFn('demo1'),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
creator21.pluginName = 'demo1';
|
||||||
|
creator21.meta = {
|
||||||
|
dependencies: 'demo2',
|
||||||
|
};
|
||||||
|
pluginManager.register(creator21);
|
||||||
|
const creator22 = (ctx: ILowCodePluginContext) => {
|
||||||
|
return {
|
||||||
|
init: () => mockFn('demo2'),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
creator22.pluginName = 'demo2';
|
||||||
|
pluginManager.register(creator22);
|
||||||
|
|
||||||
|
await pluginManager.init();
|
||||||
|
expect(mockFn).toHaveBeenNthCalledWith(1, 'demo2');
|
||||||
|
expect(mockFn).toHaveBeenNthCalledWith(2, 'demo1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('dependencies 依赖 - 兼容 dep', async () => {
|
||||||
|
const mockFn = jest.fn();
|
||||||
|
const creator21 = (ctx: ILowCodePluginContext) => {
|
||||||
|
return {
|
||||||
|
dep: ['demo4'],
|
||||||
|
init: () => mockFn('demo3'),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
creator21.pluginName = 'demo3';
|
||||||
|
pluginManager.register(creator21);
|
||||||
|
const creator22 = (ctx: ILowCodePluginContext) => {
|
||||||
|
return {
|
||||||
|
init: () => mockFn('demo4'),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
creator22.pluginName = 'demo4';
|
||||||
|
pluginManager.register(creator22);
|
||||||
|
|
||||||
|
await pluginManager.init();
|
||||||
|
expect(mockFn).toHaveBeenNthCalledWith(1, 'demo4');
|
||||||
|
expect(mockFn).toHaveBeenNthCalledWith(2, 'demo3');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('dependencies 依赖 - 兼容 dep & string', async () => {
|
||||||
|
const mockFn = jest.fn();
|
||||||
|
const creator21 = (ctx: ILowCodePluginContext) => {
|
||||||
|
return {
|
||||||
|
dep: 'demo4',
|
||||||
|
init: () => mockFn('demo3'),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
creator21.pluginName = 'demo3';
|
||||||
|
pluginManager.register(creator21);
|
||||||
|
const creator22 = (ctx: ILowCodePluginContext) => {
|
||||||
|
return {
|
||||||
|
init: () => mockFn('demo4'),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
creator22.pluginName = 'demo4';
|
||||||
|
pluginManager.register(creator22);
|
||||||
|
|
||||||
|
await pluginManager.init();
|
||||||
|
expect(mockFn).toHaveBeenNthCalledWith(1, 'demo4');
|
||||||
|
expect(mockFn).toHaveBeenNthCalledWith(2, 'demo3');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('version 依赖', async () => {
|
it('version 依赖', async () => {
|
||||||
const mockFn = jest.fn();
|
const mockFn = jest.fn();
|
||||||
const creater1 = (ctx: ILowCodePluginContext) => {
|
const creator21 = (ctx: ILowCodePluginContext) => {
|
||||||
return {
|
return {
|
||||||
init: () => mockFn('demo1'),
|
init: () => mockFn('demo1'),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
creater1.pluginName = 'demo1';
|
creator21.pluginName = 'demo1';
|
||||||
creater1.meta = {
|
creator21.meta = {
|
||||||
engines: {
|
engines: {
|
||||||
lowcodeEngine: '^1.1.0',
|
lowcodeEngine: '^1.1.0',
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
engineConfig.set('ENGINE_VERSION', '1.0.1');
|
engineConfig.set('ENGINE_VERSION', '1.0.1');
|
||||||
|
|
||||||
console.log('version: ', engineConfig.get('ENGINE_VERSION'));
|
console.log('version: ', engineConfig.get('ENGINE_VERSION'));
|
||||||
// not match should skip
|
// not match should skip
|
||||||
pluginManager.register(creater1).catch(e => {
|
pluginManager.register(creator21).catch((e) => {
|
||||||
expect(e).toEqual(new Error('plugin demo1 skipped, engine check failed, current engine version is 1.0.1, meta.engines.lowcodeEngine is ^1.1.0'));
|
expect(e).toEqual(
|
||||||
|
new Error(
|
||||||
|
'plugin demo1 skipped, engine check failed, current engine version is 1.0.1, meta.engines.lowcodeEngine is ^1.1.0',
|
||||||
|
),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(pluginManager.plugins.length).toBe(0);
|
expect(pluginManager.plugins.length).toBe(0);
|
||||||
|
|
||||||
const creater2 = (ctx: ILowCodePluginContext) => {
|
const creator22 = (ctx: ILowCodePluginContext) => {
|
||||||
return {
|
return {
|
||||||
init: () => mockFn('demo2'),
|
init: () => mockFn('demo2'),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
creater2.pluginName = 'demo2';
|
creator22.pluginName = 'demo2';
|
||||||
creater2.meta = {
|
creator22.meta = {
|
||||||
engines: {
|
engines: {
|
||||||
lowcodeEngine: '^1.0.1',
|
lowcodeEngine: '^1.0.1',
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
engineConfig.set('ENGINE_VERSION', '1.0.3');
|
engineConfig.set('ENGINE_VERSION', '1.0.3');
|
||||||
pluginManager.register(creater2);
|
pluginManager.register(creator22);
|
||||||
expect(pluginManager.plugins.length).toBe(1);
|
expect(pluginManager.plugins.length).toBe(1);
|
||||||
|
|
||||||
const creater3 = (ctx: ILowCodePluginContext) => {
|
const creator23 = (ctx: ILowCodePluginContext) => {
|
||||||
return {
|
return {
|
||||||
init: () => mockFn('demo3'),
|
init: () => mockFn('demo3'),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
creater3.pluginName = 'demo3';
|
creator23.pluginName = 'demo3';
|
||||||
creater3.meta = {
|
creator23.meta = {
|
||||||
engines: {
|
engines: {
|
||||||
lowcodeEngine: '1.x',
|
lowcodeEngine: '1.x',
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
engineConfig.set('ENGINE_VERSION', '1.1.1');
|
engineConfig.set('ENGINE_VERSION', '1.1.1');
|
||||||
pluginManager.register(creater3);
|
pluginManager.register(creator23);
|
||||||
expect(pluginManager.plugins.length).toBe(2);
|
expect(pluginManager.plugins.length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('autoInit 功能', async () => {
|
it('autoInit 功能', async () => {
|
||||||
const mockFn = jest.fn();
|
const mockFn = jest.fn();
|
||||||
const creater = (ctx: ILowCodePluginContext) => {
|
const creator2 = (ctx: ILowCodePluginContext) => {
|
||||||
return {
|
return {
|
||||||
init: mockFn,
|
init: mockFn,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
creater.pluginName = 'demo1';
|
creator2.pluginName = 'demo1';
|
||||||
await pluginManager.register(creater, { autoInit: true });
|
await pluginManager.register(creator2, { autoInit: true });
|
||||||
expect(mockFn).toHaveBeenCalled();
|
expect(mockFn).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('插件不会重复 init,除非强制重新 init', async () => {
|
it('插件不会重复 init,除非强制重新 init', async () => {
|
||||||
const mockFn = jest.fn();
|
const mockFn = jest.fn();
|
||||||
const creater = (ctx: ILowCodePluginContext) => {
|
const creator2 = (ctx: ILowCodePluginContext) => {
|
||||||
return {
|
return {
|
||||||
name: 'demo1',
|
name: 'demo1',
|
||||||
init: mockFn,
|
init: mockFn,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
creater.pluginName = 'demo1';
|
creator2.pluginName = 'demo1';
|
||||||
pluginManager.register(creater);
|
pluginManager.register(creator2);
|
||||||
await pluginManager.init();
|
await pluginManager.init();
|
||||||
expect(mockFn).toHaveBeenCalledTimes(1);
|
expect(mockFn).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
@ -217,7 +311,7 @@ describe('plugin 测试', () => {
|
|||||||
};
|
};
|
||||||
mockPlugin.pluginName = 'demoDuplicated';
|
mockPlugin.pluginName = 'demoDuplicated';
|
||||||
pluginManager.register(mockPlugin);
|
pluginManager.register(mockPlugin);
|
||||||
pluginManager.register(mockPlugin).catch(e => {
|
pluginManager.register(mockPlugin).catch((e) => {
|
||||||
expect(e).toEqual(new Error('Plugin with name demoDuplicated exists'));
|
expect(e).toEqual(new Error('Plugin with name demoDuplicated exists'));
|
||||||
});
|
});
|
||||||
await pluginManager.init();
|
await pluginManager.init();
|
||||||
@ -255,33 +349,35 @@ describe('plugin 测试', () => {
|
|||||||
|
|
||||||
it('内部事件机制', async () => {
|
it('内部事件机制', async () => {
|
||||||
const mockFn = jest.fn();
|
const mockFn = jest.fn();
|
||||||
const creater = (ctx: ILowCodePluginContext) => {
|
const creator2 = (ctx: ILowCodePluginContext) => {
|
||||||
return {
|
return {};
|
||||||
};
|
};
|
||||||
}
|
creator2.pluginName = 'demo1';
|
||||||
creater.pluginName = 'demo1';
|
pluginManager.register(creator2);
|
||||||
pluginManager.register(creater);
|
|
||||||
await pluginManager.init();
|
await pluginManager.init();
|
||||||
const plugin = pluginManager.get('demo1')!;
|
const plugin = pluginManager.get('demo1')!;
|
||||||
|
|
||||||
plugin.on('haha', mockFn);
|
const off = plugin.on('haha', mockFn);
|
||||||
plugin.emit('haha', 1, 2, 3);
|
plugin.emit('haha', 1, 2, 3);
|
||||||
|
|
||||||
expect(mockFn).toHaveBeenCalledTimes(1);
|
expect(mockFn).toHaveBeenCalledTimes(1);
|
||||||
expect(mockFn).toHaveBeenCalledWith(1, 2, 3);
|
expect(mockFn).toHaveBeenCalledWith(1, 2, 3);
|
||||||
|
|
||||||
|
off();
|
||||||
|
plugin.emit('haha', 1, 2, 3);
|
||||||
|
expect(mockFn).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
plugin.removeAllListeners('haha');
|
plugin.removeAllListeners('haha');
|
||||||
plugin.emit('haha', 1, 2, 3);
|
plugin.emit('haha', 1, 2, 3);
|
||||||
expect(mockFn).toHaveBeenCalledTimes(1);
|
expect(mockFn).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('dispose 方法', async () => {
|
it('dispose 方法', async () => {
|
||||||
const creater = (ctx: ILowCodePluginContext) => {
|
const creator2 = (ctx: ILowCodePluginContext) => {
|
||||||
return {
|
return {};
|
||||||
};
|
};
|
||||||
}
|
creator2.pluginName = 'demo1';
|
||||||
creater.pluginName = 'demo1';
|
pluginManager.register(creator2);
|
||||||
pluginManager.register(creater);
|
|
||||||
await pluginManager.init();
|
await pluginManager.init();
|
||||||
const plugin = pluginManager.get('demo1')!;
|
const plugin = pluginManager.get('demo1')!;
|
||||||
await plugin.dispose();
|
await plugin.dispose();
|
||||||
@ -289,30 +385,61 @@ describe('plugin 测试', () => {
|
|||||||
expect(pluginManager.has('demo1')).toBeFalsy();
|
expect(pluginManager.has('demo1')).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('注册插件,调用插件 init 方法并传入preference,可以成功获取', async () => {
|
it('getAll 方法', async () => {
|
||||||
|
const creator2 = (ctx: ILowCodePluginContext) => {
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
creator2.pluginName = 'demo1';
|
||||||
|
pluginManager.register(creator2);
|
||||||
|
await pluginManager.init();
|
||||||
|
|
||||||
|
expect(pluginManager.getAll()).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getPluginPreference 方法 - null', async () => {
|
||||||
|
const creator2 = (ctx: ILowCodePluginContext) => {
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
creator2.pluginName = 'demo1';
|
||||||
|
pluginManager.register(creator2);
|
||||||
|
await pluginManager.init();
|
||||||
|
|
||||||
|
expect(pluginManager.getPluginPreference()).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getPluginPreference 方法', async () => {
|
||||||
|
const creator2 = (ctx: ILowCodePluginContext) => {
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
const preference = new Map();
|
||||||
|
preference.set('demo1', { a: 1, b: 2 });
|
||||||
|
creator2.pluginName = 'demo1';
|
||||||
|
pluginManager.register(creator2);
|
||||||
|
await pluginManager.init(preference);
|
||||||
|
|
||||||
|
expect(pluginManager.getPluginPreference('demo1')).toEqual({ a: 1, b: 2 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('注册插件,调用插件 init 方法并传入 preference,可以成功获取', async () => {
|
||||||
const mockFn = jest.fn();
|
const mockFn = jest.fn();
|
||||||
const mockFnForCtx = jest.fn();
|
const mockFnForCtx = jest.fn();
|
||||||
|
const mockFnForCtx2 = jest.fn();
|
||||||
const mockPreference = new Map();
|
const mockPreference = new Map();
|
||||||
mockPreference.set('demo1',{
|
mockPreference.set('demo1', {
|
||||||
key1: 'value for key1',
|
key1: 'value for key1',
|
||||||
key2: false,
|
key2: false,
|
||||||
key3: 123,
|
key3: 123,
|
||||||
key5: 'value for key5, but declared, should not work'
|
key5: 'value for key5, but declared, should not work',
|
||||||
});
|
|
||||||
mockPreference.set('demo2',{
|
|
||||||
key1: 'value for demo2.key1',
|
|
||||||
key2: false,
|
|
||||||
key3: 123,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const creater = (ctx: ILowCodePluginContext) => {
|
const creator2 = (ctx: ILowCodePluginContext) => {
|
||||||
mockFnForCtx(ctx);
|
mockFnForCtx(ctx);
|
||||||
return {
|
return {
|
||||||
init: jest.fn(),
|
init: jest.fn(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
creater.pluginName = 'demo1';
|
creator2.pluginName = 'demo1';
|
||||||
creater.meta = {
|
creator2.meta = {
|
||||||
preferenceDeclaration: {
|
preferenceDeclaration: {
|
||||||
title: 'demo1的的参数定义',
|
title: 'demo1的的参数定义',
|
||||||
properties: [
|
properties: [
|
||||||
@ -338,13 +465,34 @@ describe('plugin 测试', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
pluginManager.register(creater);
|
const creator22 = (ctx: ILowCodePluginContext) => {
|
||||||
|
mockFnForCtx2(ctx);
|
||||||
|
return {
|
||||||
|
init: jest.fn(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
creator22.pluginName = 'demo2';
|
||||||
|
creator22.meta = {
|
||||||
|
preferenceDeclaration: {
|
||||||
|
title: 'demo1的的参数定义',
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
key: 'key1',
|
||||||
|
type: 'string',
|
||||||
|
description: 'this is description for key1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
pluginManager.register(creator2);
|
||||||
|
pluginManager.register(creator22);
|
||||||
expect(mockFnForCtx).toHaveBeenCalledTimes(1);
|
expect(mockFnForCtx).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
await pluginManager.init(mockPreference);
|
await pluginManager.init(mockPreference);
|
||||||
// creater only get excuted once
|
// creator2 only get excuted once
|
||||||
expect(mockFnForCtx).toHaveBeenCalledTimes(1);
|
expect(mockFnForCtx).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
const [expectedCtx, expectedOptions] = mockFnForCtx.mock.calls[0];
|
const [expectedCtx, expectedOptions] = mockFnForCtx.mock.calls[0];
|
||||||
expect(expectedCtx).toHaveProperty('preference');
|
expect(expectedCtx).toHaveProperty('preference');
|
||||||
|
|
||||||
@ -352,9 +500,47 @@ describe('plugin 测试', () => {
|
|||||||
expect(expectedCtx.preference.getPreferenceValue('key1', 'default')).toBe('value for key1');
|
expect(expectedCtx.preference.getPreferenceValue('key1', 'default')).toBe('value for key1');
|
||||||
|
|
||||||
// test default value logic
|
// test default value logic
|
||||||
expect(expectedCtx.preference.getPreferenceValue('key4', 'default for key4')).toBe('default for key4');
|
expect(expectedCtx.preference.getPreferenceValue('key4', 'default for key4')).toBe(
|
||||||
|
'default for key4',
|
||||||
|
);
|
||||||
|
|
||||||
// test undeclared key
|
// test undeclared key
|
||||||
expect(expectedCtx.preference.getPreferenceValue('key5', 'default for key5')).toBeUndefined();
|
expect(expectedCtx.preference.getPreferenceValue('key5', 'default for key5')).toBeUndefined();
|
||||||
|
|
||||||
|
// no preference defined
|
||||||
|
const [expectedCtx2] = mockFnForCtx2.mock.calls[0];
|
||||||
|
expect(expectedCtx2.preference.getPreferenceValue('key1')).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('注册插件,没有填写 pluginName,默认值为 anonymous', async () => {
|
||||||
|
const mockFn = jest.fn();
|
||||||
|
|
||||||
|
const creator2 = (ctx: ILowCodePluginContext) => {
|
||||||
|
return {
|
||||||
|
name: 'xxx',
|
||||||
|
init: () => mockFn('anonymous'),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
await pluginManager.register(creator2);
|
||||||
|
expect(pluginManager.get('anonymous')).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('自定义/扩展 plugin context', async () => {
|
||||||
|
const mockFn = jest.fn();
|
||||||
|
const mockFn2 = jest.fn();
|
||||||
|
|
||||||
|
const creator2 = (ctx: ILowCodePluginContext) => {
|
||||||
|
mockFn2(ctx);
|
||||||
|
return {
|
||||||
|
init: () => mockFn('anonymous'),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
creator2.pluginName = 'yyy';
|
||||||
|
editor.set('enhancePluginContextHook', (originalContext) => {
|
||||||
|
originalContext.newProp = 1;
|
||||||
|
});
|
||||||
|
await pluginManager.register(creator2);
|
||||||
|
const [expectedCtx] = mockFn2.mock.calls[0];
|
||||||
|
expect(expectedCtx).toHaveProperty('newProp');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
85
packages/designer/tests/plugin/plugin-utils.test.ts
Normal file
85
packages/designer/tests/plugin/plugin-utils.test.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import '../fixtures/window';
|
||||||
|
import { isValidPreferenceKey, filterValidOptions } from '../../src/plugin/plugin-utils';
|
||||||
|
|
||||||
|
describe('plugin utils 测试', () => {
|
||||||
|
it('isValidPreferenceKey', () => {
|
||||||
|
expect(isValidPreferenceKey('x')).toBeFalsy();
|
||||||
|
expect(isValidPreferenceKey('x', { properties: {} })).toBeFalsy();
|
||||||
|
expect(isValidPreferenceKey('x', { properties: 1 })).toBeFalsy();
|
||||||
|
expect(isValidPreferenceKey('x', { properties: 'str' })).toBeFalsy();
|
||||||
|
expect(isValidPreferenceKey('x', { properties: [] })).toBeFalsy();
|
||||||
|
expect(
|
||||||
|
isValidPreferenceKey('x', {
|
||||||
|
title: 'title',
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
key: 'y',
|
||||||
|
type: 'string',
|
||||||
|
description: 'x desc',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
).toBeFalsy();
|
||||||
|
expect(
|
||||||
|
isValidPreferenceKey('x', {
|
||||||
|
title: 'title',
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
key: 'x',
|
||||||
|
type: 'string',
|
||||||
|
description: 'x desc',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('filterValidOptions', () => {
|
||||||
|
const mockDeclaration = {
|
||||||
|
title: 'title',
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
key: 'x',
|
||||||
|
type: 'string',
|
||||||
|
description: 'x desc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'y',
|
||||||
|
type: 'string',
|
||||||
|
description: 'y desc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'z',
|
||||||
|
type: 'string',
|
||||||
|
description: 'z desc',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(filterValidOptions()).toBeUndefined();
|
||||||
|
expect(filterValidOptions(1)).toBe(1);
|
||||||
|
expect(filterValidOptions({
|
||||||
|
x: 1,
|
||||||
|
y: 2,
|
||||||
|
}, mockDeclaration)).toEqual({
|
||||||
|
x: 1,
|
||||||
|
y: 2,
|
||||||
|
});
|
||||||
|
expect(filterValidOptions({
|
||||||
|
x: 1,
|
||||||
|
y: undefined,
|
||||||
|
}, mockDeclaration)).toEqual({
|
||||||
|
x: 1,
|
||||||
|
});
|
||||||
|
expect(filterValidOptions({
|
||||||
|
x: 1,
|
||||||
|
z: null,
|
||||||
|
}, mockDeclaration)).toEqual({
|
||||||
|
x: 1,
|
||||||
|
});
|
||||||
|
expect(filterValidOptions({
|
||||||
|
a: 1,
|
||||||
|
}, mockDeclaration)).toEqual({
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -113,6 +113,8 @@ describe.only('Project 方法测试', () => {
|
|||||||
expect(project.documents.length).toBe(4);
|
expect(project.documents.length).toBe(4);
|
||||||
|
|
||||||
expect(project.getDocument(project.currentDocument?.id)).toBe(doc3);
|
expect(project.getDocument(project.currentDocument?.id)).toBe(doc3);
|
||||||
|
expect(project.getDocumentByFileName(project.currentDocument?.fileName)).toBe(doc3);
|
||||||
|
expect(project.getDocumentByFileName('unknown')).toBeNull();
|
||||||
expect(project.checkExclusive(project.currentDocument));
|
expect(project.checkExclusive(project.currentDocument));
|
||||||
|
|
||||||
expect(project.documents[0].opened).toBeTruthy();
|
expect(project.documents[0].opened).toBeTruthy();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user