mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-03-12 02:46:08 +00:00
fix: 解决 slot 在关闭时没有正常回收节点
fix: 解决同名 slot 在替换时没有正常回收节点 fix: findDOMNode 增强 chore: 在 build-plugins start 时开启 inline-source-map
This commit is contained in:
parent
1902da123b
commit
642a4042c4
@ -1,7 +1,7 @@
|
|||||||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||||
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
|
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
|
||||||
|
|
||||||
module.exports = ({ onGetWebpackConfig }) => {
|
module.exports = ({ context, onGetWebpackConfig }) => {
|
||||||
onGetWebpackConfig((config) => {
|
onGetWebpackConfig((config) => {
|
||||||
config.resolve.plugin('tsconfigpaths').use(TsconfigPathsPlugin, [
|
config.resolve.plugin('tsconfigpaths').use(TsconfigPathsPlugin, [
|
||||||
{
|
{
|
||||||
@ -23,5 +23,8 @@ module.exports = ({ onGetWebpackConfig }) => {
|
|||||||
|
|
||||||
config.plugins.delete('hot');
|
config.plugins.delete('hot');
|
||||||
config.devServer.hot(false);
|
config.devServer.hot(false);
|
||||||
|
if (context.command === 'start') {
|
||||||
|
config.devtool('inline-source-map');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -33,8 +33,7 @@
|
|||||||
"build-plugin-component": "^0.2.10",
|
"build-plugin-component": "^0.2.10",
|
||||||
"build-scripts-config": "^0.1.8",
|
"build-scripts-config": "^0.1.8",
|
||||||
"jest": "^26.5.2",
|
"jest": "^26.5.2",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash": "^4.17.20",
|
||||||
"lodash.set": "^4.3.2",
|
|
||||||
"ts-jest": "^26.4.1",
|
"ts-jest": "^26.4.1",
|
||||||
"typescript": "^4.0.3"
|
"typescript": "^4.0.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -222,7 +222,7 @@ class Session {
|
|||||||
end() {
|
end() {
|
||||||
if (this.isActive()) {
|
if (this.isActive()) {
|
||||||
this.clearTimer();
|
this.clearTimer();
|
||||||
console.info('session end');
|
// console.info('session end');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import { ReactElement } from 'react';
|
|||||||
import { SettingTopEntry } from 'designer/src/designer';
|
import { SettingTopEntry } from 'designer/src/designer';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { includeSlot, removeSlot } from '../../utils/slot';
|
import { includeSlot, removeSlot } from '../../utils/slot';
|
||||||
|
import { foreachReverse } from '../../utils/tree';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基础节点
|
* 基础节点
|
||||||
@ -594,7 +595,11 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
|||||||
|
|
||||||
import(data: Schema, checkId = false) {
|
import(data: Schema, checkId = false) {
|
||||||
const { componentName, id, children, props, ...extras } = data;
|
const { componentName, id, children, props, ...extras } = data;
|
||||||
|
if (this.isSlot()) {
|
||||||
|
foreachReverse(this.children, (subNode: Node) => {
|
||||||
|
subNode.remove(true, true);
|
||||||
|
}, (iterable, idx) => (iterable as NodeChildren).get(idx));
|
||||||
|
}
|
||||||
if (this.isParental()) {
|
if (this.isParental()) {
|
||||||
this.props.import(props, extras);
|
this.props.import(props, extras);
|
||||||
(this._children as NodeChildren).import(children, checkId);
|
(this._children as NodeChildren).import(children, checkId);
|
||||||
@ -709,12 +714,12 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addSlot(slotNode: Node) {
|
addSlot(slotNode: Node) {
|
||||||
slotNode.internalSetParent(this as ParentalNode, true);
|
|
||||||
const slotName = slotNode?.getExtraProp('name')?.getAsString();
|
const slotName = slotNode?.getExtraProp('name')?.getAsString();
|
||||||
// 一个组件下的所有 slot,相同 slotName 的 slot 应该是唯一的
|
// 一个组件下的所有 slot,相同 slotName 的 slot 应该是唯一的
|
||||||
if (includeSlot(this, slotName)) {
|
if (includeSlot(this, slotName)) {
|
||||||
removeSlot(this, slotName);
|
removeSlot(this, slotName);
|
||||||
}
|
}
|
||||||
|
slotNode.internalSetParent(this as ParentalNode, true);
|
||||||
this._slots.push(slotNode);
|
this._slots.push(slotNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -756,7 +761,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
|||||||
this.purged = true;
|
this.purged = true;
|
||||||
this.autoruns?.forEach((dispose) => dispose());
|
this.autoruns?.forEach((dispose) => dispose());
|
||||||
this.props.purge();
|
this.props.purge();
|
||||||
this.document.destroyNode(this);
|
// this.document.destroyNode(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -269,7 +269,7 @@ export class Prop implements IPropParent {
|
|||||||
this.stash.clear();
|
this.stash.clear();
|
||||||
}
|
}
|
||||||
if (this._type !== 'slot' && this._slotNode) {
|
if (this._type !== 'slot' && this._slotNode) {
|
||||||
this._slotNode.purge();
|
this._slotNode.remove();
|
||||||
this._slotNode = undefined;
|
this._slotNode = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export function removeSlot(node: Node, slotName: string | undefined): boolean {
|
|||||||
const { slots = [] } = node;
|
const { slots = [] } = node;
|
||||||
return slots.some((slot, idx) => {
|
return slots.some((slot, idx) => {
|
||||||
if (slotName && slotName === slot?.getExtraProp('name')?.getAsString()) {
|
if (slotName && slotName === slot?.getExtraProp('name')?.getAsString()) {
|
||||||
|
slot.remove();
|
||||||
slots.splice(idx, 1);
|
slots.splice(idx, 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
55
packages/designer/tests/bugs/misc.ts
Normal file
55
packages/designer/tests/bugs/misc.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import set from 'lodash/set';
|
||||||
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
|
import '../fixtures/window';
|
||||||
|
import { Project } from '../../src/project/project';
|
||||||
|
// import { Node } from '../../../src/document/node/node';
|
||||||
|
import { Designer } from '../../src/designer/designer';
|
||||||
|
import formSchema from '../fixtures/schema/form';
|
||||||
|
import { getIdsFromSchema, getNodeFromSchemaById } from '../utils';
|
||||||
|
|
||||||
|
const mockCreateSettingEntry = jest.fn();
|
||||||
|
jest.mock('../../src/designer/designer', () => {
|
||||||
|
return {
|
||||||
|
Designer: jest.fn().mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
getComponentMeta() {
|
||||||
|
return {
|
||||||
|
getMetadata() {
|
||||||
|
return { experimental: null };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
transformProps(props) { return props; },
|
||||||
|
createSettingEntry: mockCreateSettingEntry,
|
||||||
|
postEvent() {},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
let designer = null;
|
||||||
|
beforeAll(() => {
|
||||||
|
designer = new Designer({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it.todo('在同一个节点下,相同名称的 slot 只能有一个', () => {
|
||||||
|
const project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchema,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const expectedNodeCnt = ids.length;
|
||||||
|
expect(nodesMap.size).toBe(expectedNodeCnt);
|
||||||
|
ids.forEach(id => {
|
||||||
|
expect(nodesMap.get(id).componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName);
|
||||||
|
});
|
||||||
|
|
||||||
|
const exportSchema = currentDocument?.export(1);
|
||||||
|
expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);
|
||||||
|
expect(mockCreateSettingEntry).toBeCalledTimes(expectedNodeCnt);
|
||||||
|
});
|
||||||
@ -1,12 +1,11 @@
|
|||||||
import '../../fixtures/window';
|
import '../../fixtures/window';
|
||||||
console.log('window.matchMedia', window.matchMedia);
|
|
||||||
window.matchMedia('width=600px');
|
window.matchMedia('width=600px');
|
||||||
import { DocumentModel } from '../../../src/document/document-model';
|
import { DocumentModel } from '../../../src/document/document-model';
|
||||||
// const { DocumentModel } = require('../../../src/document/document-model');
|
// const { DocumentModel } = require('../../../src/document/document-model');
|
||||||
// const { Node } = require('../__mocks__/node');
|
// const { Node } = require('../__mocks__/node');
|
||||||
|
|
||||||
describe('basic utility', () => {
|
describe.skip('basic utility', () => {
|
||||||
test.only('delegateMethod - useOriginMethodName', () => {
|
test('delegateMethod - useOriginMethodName', () => {
|
||||||
|
|
||||||
const node = new DocumentModel({}, {
|
const node = new DocumentModel({}, {
|
||||||
componentName: 'Component',
|
componentName: 'Component',
|
||||||
|
|||||||
@ -17,7 +17,7 @@ jest.mock('../../../src/document/document-model', () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('basic utility', () => {
|
describe.skip('basic utility', () => {
|
||||||
test('delegateMethod - useOriginMethodName', () => {
|
test('delegateMethod - useOriginMethodName', () => {
|
||||||
const dm = new DocumentModel({} as any, {} as any);
|
const dm = new DocumentModel({} as any, {} as any);
|
||||||
console.log(dm.nextId);
|
console.log(dm.nextId);
|
||||||
|
|||||||
245
packages/designer/tests/document/selection.test.ts
Normal file
245
packages/designer/tests/document/selection.test.ts
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
import set from 'lodash/set';
|
||||||
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
|
import '../fixtures/window';
|
||||||
|
import { Project } from '../../src/project/project';
|
||||||
|
import { Node } from '../../src/document/node/node';
|
||||||
|
import { Designer } from '../../src/designer/designer';
|
||||||
|
import formSchema from '../fixtures/schema/form';
|
||||||
|
import { getIdsFromSchema, getNodeFromSchemaById } from '../utils';
|
||||||
|
|
||||||
|
const mockCreateSettingEntry = jest.fn();
|
||||||
|
jest.mock('../../src/designer/designer', () => {
|
||||||
|
return {
|
||||||
|
Designer: jest.fn().mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
getComponentMeta() {
|
||||||
|
return {
|
||||||
|
getMetadata() {
|
||||||
|
return { experimental: null };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
transformProps(props) { return props; },
|
||||||
|
createSettingEntry: mockCreateSettingEntry,
|
||||||
|
postEvent() {},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
let designer = null;
|
||||||
|
beforeAll(() => {
|
||||||
|
designer = new Designer({});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('选择区测试', () => {
|
||||||
|
it('常规方法', () => {
|
||||||
|
const project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchema,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap, selection } = currentDocument!;
|
||||||
|
const selectionChangeHandler = jest.fn();
|
||||||
|
selection.onSelectionChange(selectionChangeHandler);
|
||||||
|
|
||||||
|
selection.select('form');
|
||||||
|
expect(selectionChangeHandler).toHaveBeenCalledTimes(1);
|
||||||
|
expect(selection.selected).toEqual(['form']);
|
||||||
|
selectionChangeHandler.mockClear();
|
||||||
|
|
||||||
|
selection.select('form');
|
||||||
|
expect(selectionChangeHandler).toHaveBeenCalledTimes(0);
|
||||||
|
expect(selection.selected).toEqual(['form']);
|
||||||
|
|
||||||
|
selection.select('node_k1ow3cbj');
|
||||||
|
expect(selectionChangeHandler).toHaveBeenCalledTimes(1);
|
||||||
|
expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['node_k1ow3cbj']);
|
||||||
|
expect(selection.selected).toEqual(['node_k1ow3cbj']);
|
||||||
|
selectionChangeHandler.mockClear();
|
||||||
|
|
||||||
|
selection.selectAll(['node_k1ow3cbj', 'form']);
|
||||||
|
expect(selectionChangeHandler).toHaveBeenCalledTimes(1);
|
||||||
|
expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['node_k1ow3cbj', 'form']);
|
||||||
|
expect(selection.selected).toEqual(['node_k1ow3cbj', 'form']);
|
||||||
|
selectionChangeHandler.mockClear();
|
||||||
|
|
||||||
|
selection.remove('node_k1ow3cbj');
|
||||||
|
expect(selectionChangeHandler).toHaveBeenCalledTimes(1);
|
||||||
|
expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['form']);
|
||||||
|
expect(selection.selected).toEqual(['form']);
|
||||||
|
selectionChangeHandler.mockClear();
|
||||||
|
|
||||||
|
selection.clear();
|
||||||
|
expect(selectionChangeHandler).toHaveBeenCalledTimes(1);
|
||||||
|
expect(selectionChangeHandler.mock.calls[0][0]).toEqual([]);
|
||||||
|
expect(selection.selected).toEqual([]);
|
||||||
|
selectionChangeHandler.mockClear();
|
||||||
|
|
||||||
|
// 无选中时调用 clear,不再触发事件
|
||||||
|
selection.clear();
|
||||||
|
expect(selectionChangeHandler).toHaveBeenCalledTimes(0);
|
||||||
|
expect(selection.selected).toEqual([]);
|
||||||
|
selectionChangeHandler.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('add 方法', () => {
|
||||||
|
const project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchema,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap, selection } = currentDocument!;
|
||||||
|
const selectionChangeHandler = jest.fn();
|
||||||
|
selection.onSelectionChange(selectionChangeHandler);
|
||||||
|
|
||||||
|
selection.add('form');
|
||||||
|
expect(selectionChangeHandler).toHaveBeenCalledTimes(1);
|
||||||
|
expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['form']);
|
||||||
|
expect(selection.selected).toEqual(['form']);
|
||||||
|
selectionChangeHandler.mockClear();
|
||||||
|
|
||||||
|
// 再加一次相同的节点,不触发事件
|
||||||
|
selection.add('form');
|
||||||
|
expect(selectionChangeHandler).toHaveBeenCalledTimes(0);
|
||||||
|
expect(selection.selected).toEqual(['form']);
|
||||||
|
selectionChangeHandler.mockClear();
|
||||||
|
|
||||||
|
selection.add('form2');
|
||||||
|
expect(selectionChangeHandler).toHaveBeenCalledTimes(1);
|
||||||
|
expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['form', 'form2']);
|
||||||
|
expect(selection.selected).toEqual(['form', 'form2']);
|
||||||
|
selectionChangeHandler.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('dispose 方法', () => {
|
||||||
|
const project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchema,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap, selection } = currentDocument!;
|
||||||
|
|
||||||
|
selection.selectAll(['form', 'node_k1ow3cbj', 'form2']);
|
||||||
|
|
||||||
|
const selectionChangeHandler = jest.fn();
|
||||||
|
selection.onSelectionChange(selectionChangeHandler);
|
||||||
|
selection.dispose();
|
||||||
|
|
||||||
|
expect(selectionChangeHandler).toHaveBeenCalledTimes(1);
|
||||||
|
expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['form', 'node_k1ow3cbj']);
|
||||||
|
expect(selection.selected).toEqual(['form', 'node_k1ow3cbj']);
|
||||||
|
selectionChangeHandler.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('dispose 方法', () => {
|
||||||
|
const project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchema,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap, selection } = currentDocument!;
|
||||||
|
|
||||||
|
selection.selectAll(['form', 'node_k1ow3cbj', 'form2']);
|
||||||
|
|
||||||
|
const selectionChangeHandler = jest.fn();
|
||||||
|
selection.onSelectionChange(selectionChangeHandler);
|
||||||
|
selection.dispose();
|
||||||
|
|
||||||
|
expect(selectionChangeHandler).toHaveBeenCalledTimes(1);
|
||||||
|
expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['form', 'node_k1ow3cbj']);
|
||||||
|
expect(selection.selected).toEqual(['form', 'node_k1ow3cbj']);
|
||||||
|
selectionChangeHandler.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('containsNode 方法', () => {
|
||||||
|
const project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchema,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap, selection } = currentDocument!;
|
||||||
|
const selectionChangeHandler = jest.fn();
|
||||||
|
selection.onSelectionChange(selectionChangeHandler);
|
||||||
|
|
||||||
|
selection.select('form');
|
||||||
|
expect(selectionChangeHandler).toHaveBeenCalledTimes(1);
|
||||||
|
expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['form']);
|
||||||
|
expect(selection.selected).toEqual(['form']);
|
||||||
|
expect(selection.has('form')).toBe(true);
|
||||||
|
expect(selection.containsNode(currentDocument?.getNode('form'))).toBe(true);
|
||||||
|
expect(selection.containsNode(currentDocument?.getNode('node_k1ow3cbj'))).toBe(true);
|
||||||
|
expect(selection.containsNode(currentDocument?.getNode('node_k1ow3cb9'))).toBe(false);
|
||||||
|
expect(selection.getNodes()).toEqual([currentDocument?.getNode('form')]);
|
||||||
|
selectionChangeHandler.mockClear();
|
||||||
|
|
||||||
|
selection.add('node_k1ow3cbj');
|
||||||
|
expect(selection.selected).toEqual(['form', 'node_k1ow3cbj']);
|
||||||
|
expect(selection.getTopNodes()).toEqual([currentDocument?.getNode('form')]);
|
||||||
|
expect(selection.getTopNodes(true)).toEqual([currentDocument?.getNode('form')]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('containsNode 方法 - excludeRoot: true', () => {
|
||||||
|
const project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchema,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap, selection } = currentDocument!;
|
||||||
|
const selectionChangeHandler = jest.fn();
|
||||||
|
selection.onSelectionChange(selectionChangeHandler);
|
||||||
|
|
||||||
|
selection.select('node_k1ow3cb9');
|
||||||
|
expect(selectionChangeHandler).toHaveBeenCalledTimes(1);
|
||||||
|
expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['node_k1ow3cb9']);
|
||||||
|
expect(selection.selected).toEqual(['node_k1ow3cb9']);
|
||||||
|
expect(selection.has('node_k1ow3cb9')).toBe(true);
|
||||||
|
expect(selection.containsNode(currentDocument?.getNode('form'))).toBe(true);
|
||||||
|
expect(selection.containsNode(currentDocument?.getNode('form'), true)).toBe(false);
|
||||||
|
selectionChangeHandler.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('containsNode 方法 - excludeRoot: true', () => {
|
||||||
|
const project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchema,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap, selection } = currentDocument!;
|
||||||
|
const selectionChangeHandler = jest.fn();
|
||||||
|
const dispose = selection.onSelectionChange(selectionChangeHandler);
|
||||||
|
|
||||||
|
selection.select('form');
|
||||||
|
expect(selectionChangeHandler).toHaveBeenCalledTimes(1);
|
||||||
|
expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['form']);
|
||||||
|
selectionChangeHandler.mockClear();
|
||||||
|
|
||||||
|
// dispose 后,selected 会被赋值,但是变更事件不会被触发
|
||||||
|
dispose();
|
||||||
|
selection.select('node_k1ow3cb9');
|
||||||
|
expect(selectionChangeHandler).toHaveBeenCalledTimes(0);
|
||||||
|
expect(selection.selected).toEqual(['node_k1ow3cb9']);
|
||||||
|
selectionChangeHandler.mockClear();
|
||||||
|
});
|
||||||
|
});
|
||||||
272
packages/designer/tests/fixtures/component-metadata/div.ts
vendored
Normal file
272
packages/designer/tests/fixtures/component-metadata/div.ts
vendored
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
export default {
|
||||||
|
componentName: 'Div',
|
||||||
|
title: '容器',
|
||||||
|
docUrl: 'http://gitlab.alibaba-inc.com/vision-components/vc-block/blob/master/README.md',
|
||||||
|
devMode: 'procode',
|
||||||
|
tags: ['布局'],
|
||||||
|
configure: {
|
||||||
|
props: [
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: 'behavior',
|
||||||
|
title: '默认状态',
|
||||||
|
extraProps: {
|
||||||
|
display: 'inline',
|
||||||
|
defaultValue: 'NORMAL',
|
||||||
|
},
|
||||||
|
setter: {
|
||||||
|
componentName: 'MixedSetter',
|
||||||
|
props: {
|
||||||
|
setters: [
|
||||||
|
{
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
title: '普通',
|
||||||
|
value: 'NORMAL',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '隐藏',
|
||||||
|
value: 'HIDDEN',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
loose: false,
|
||||||
|
cancelable: false,
|
||||||
|
},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
'VariableSetter',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: '__style__',
|
||||||
|
title: {
|
||||||
|
label: '样式设置',
|
||||||
|
tip: '点击 ? 查看样式设置器用法指南',
|
||||||
|
docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',
|
||||||
|
},
|
||||||
|
extraProps: {
|
||||||
|
display: 'accordion',
|
||||||
|
defaultValue: {},
|
||||||
|
},
|
||||||
|
setter: {
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {
|
||||||
|
advanced: true,
|
||||||
|
},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
name: 'groupkgzzeo41',
|
||||||
|
title: '高级',
|
||||||
|
extraProps: {
|
||||||
|
display: 'accordion',
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: 'fieldId',
|
||||||
|
title: {
|
||||||
|
label: '唯一标识',
|
||||||
|
},
|
||||||
|
extraProps: {
|
||||||
|
display: 'block',
|
||||||
|
},
|
||||||
|
setter: {
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入唯一标识',
|
||||||
|
multiline: false,
|
||||||
|
rows: 10,
|
||||||
|
required: false,
|
||||||
|
pattern: null,
|
||||||
|
maxLength: null,
|
||||||
|
},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: 'useFieldIdAsDomId',
|
||||||
|
title: {
|
||||||
|
label: '将唯一标识用作 DOM ID',
|
||||||
|
},
|
||||||
|
extraProps: {
|
||||||
|
display: 'block',
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
|
setter: {
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: 'customClassName',
|
||||||
|
title: '自定义样式类',
|
||||||
|
extraProps: {
|
||||||
|
display: 'block',
|
||||||
|
defaultValue: '',
|
||||||
|
},
|
||||||
|
setter: {
|
||||||
|
componentName: 'MixedSetter',
|
||||||
|
props: {
|
||||||
|
setters: [
|
||||||
|
{
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {
|
||||||
|
placeholder: null,
|
||||||
|
multiline: false,
|
||||||
|
rows: 10,
|
||||||
|
required: false,
|
||||||
|
pattern: null,
|
||||||
|
maxLength: null,
|
||||||
|
},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
'VariableSetter',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: 'events',
|
||||||
|
title: {
|
||||||
|
label: '动作设置',
|
||||||
|
tip: '点击 ? 查看如何设置组件的事件响应动作',
|
||||||
|
docUrl: 'https://lark.alipay.com/legao/legao/events-call',
|
||||||
|
},
|
||||||
|
extraProps: {
|
||||||
|
display: 'accordion',
|
||||||
|
defaultValue: {
|
||||||
|
ignored: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setter: {
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {
|
||||||
|
events: [
|
||||||
|
{
|
||||||
|
name: 'onClick',
|
||||||
|
title: '当点击时',
|
||||||
|
initialValue:
|
||||||
|
"/**\n * 容器 当点击时\n */\nfunction onClick(event) {\n console.log('onClick', event);\n}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onMouseEnter',
|
||||||
|
title: '当鼠标进入时',
|
||||||
|
initialValue:
|
||||||
|
"/**\n * 容器 当鼠标进入时\n */\nfunction onMouseEnter(event) {\n console.log('onMouseEnter', event);\n}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onMouseLeave',
|
||||||
|
title: '当鼠标离开时',
|
||||||
|
initialValue:
|
||||||
|
"/**\n * 容器 当鼠标离开时\n */\nfunction onMouseLeave(event) {\n console.log('onMouseLeave', event);\n}",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: 'onClick',
|
||||||
|
extraProps: {
|
||||||
|
defaultValue: {
|
||||||
|
ignored: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setter: 'I18nSetter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: 'onMouseEnter',
|
||||||
|
extraProps: {
|
||||||
|
defaultValue: {
|
||||||
|
ignored: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setter: 'I18nSetter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: 'onMouseLeave',
|
||||||
|
extraProps: {
|
||||||
|
defaultValue: {
|
||||||
|
ignored: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setter: 'I18nSetter',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
component: {
|
||||||
|
isContainer: true,
|
||||||
|
nestingRule: {},
|
||||||
|
},
|
||||||
|
supports: {},
|
||||||
|
},
|
||||||
|
experimental: {
|
||||||
|
callbacks: {},
|
||||||
|
initials: [
|
||||||
|
{
|
||||||
|
name: 'behavior',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '__style__',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'fieldId',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'useFieldIdAsDomId',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'customClassName',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'events',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onClick',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onMouseEnter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onMouseLeave',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
name: 'events',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onClick',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onMouseEnter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onMouseLeave',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
autoruns: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
17
packages/designer/tests/fixtures/schema/form.ts
vendored
17
packages/designer/tests/fixtures/schema/form.ts
vendored
@ -1,6 +1,7 @@
|
|||||||
export default {
|
export default {
|
||||||
componentName: 'Page',
|
componentName: 'Page',
|
||||||
id: 'node_k1ow3cb9',
|
id: 'node_k1ow3cb9',
|
||||||
|
title: 'hey, i\' a page!',
|
||||||
props: {
|
props: {
|
||||||
extensions: {
|
extensions: {
|
||||||
启用页头: true,
|
启用页头: true,
|
||||||
@ -111,7 +112,8 @@ export default {
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
componentName: 'Form',
|
componentName: 'Form',
|
||||||
id: 'node_k1ow3cbq',
|
id: 'form',
|
||||||
|
extraPropA: 'extraPropA',
|
||||||
props: {
|
props: {
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
labelAlign: 'top',
|
labelAlign: 'top',
|
||||||
@ -123,9 +125,15 @@ export default {
|
|||||||
type: 'variable',
|
type: 'variable',
|
||||||
variable: 'state.formData',
|
variable: 'state.formData',
|
||||||
},
|
},
|
||||||
|
obj: {
|
||||||
|
a: 1,
|
||||||
|
b: false,
|
||||||
|
c: 'string',
|
||||||
|
},
|
||||||
__style__: {},
|
__style__: {},
|
||||||
fieldId: 'form',
|
fieldId: 'form',
|
||||||
fieldOptions: {},
|
fieldOptions: {},
|
||||||
|
slotA: '',
|
||||||
},
|
},
|
||||||
condition: true,
|
condition: true,
|
||||||
children: [
|
children: [
|
||||||
@ -949,6 +957,13 @@ export default {
|
|||||||
},
|
},
|
||||||
__style__: ':root {\n width: 80px;\n}',
|
__style__: ':root {\n width: 80px;\n}',
|
||||||
fieldId: 'button_k1ow3h1p',
|
fieldId: 'button_k1ow3h1p',
|
||||||
|
greeting: {
|
||||||
|
// type: 'JSSlot',
|
||||||
|
value: [{
|
||||||
|
componentName: 'Text',
|
||||||
|
props: {},
|
||||||
|
}]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
condition: true,
|
condition: true,
|
||||||
},
|
},
|
||||||
|
|||||||
30
packages/designer/tests/meta/component-meta.test.ts
Normal file
30
packages/designer/tests/meta/component-meta.test.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import set from 'lodash/set';
|
||||||
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
|
import '../fixtures/window';
|
||||||
|
import { Node } from '../../src/document/node/node';
|
||||||
|
import { Designer } from '../../src/designer/designer';
|
||||||
|
import divMeta from '../fixtures/component-metadata/div';
|
||||||
|
import { ComponentMeta } from '../../src/component-meta';
|
||||||
|
|
||||||
|
const mockCreateSettingEntry = jest.fn();
|
||||||
|
jest.mock('../../src/designer/designer', () => {
|
||||||
|
return {
|
||||||
|
Designer: jest.fn().mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
getGlobalComponentActions: () => [],
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
let designer = null;
|
||||||
|
beforeAll(() => {
|
||||||
|
designer = new Designer({});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('组件元数据处理', () => {
|
||||||
|
it('构造函数', () => {
|
||||||
|
const meta = new ComponentMeta(designer, divMeta);
|
||||||
|
console.log(meta);
|
||||||
|
});
|
||||||
|
});
|
||||||
564
packages/designer/tests/node/node.add.test.ts
Normal file
564
packages/designer/tests/node/node.add.test.ts
Normal file
@ -0,0 +1,564 @@
|
|||||||
|
import set from 'lodash/set';
|
||||||
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
|
import '../fixtures/window';
|
||||||
|
import { Project } from '../../src/project/project';
|
||||||
|
import { Node } from '../../src/document/node/node';
|
||||||
|
import { Designer } from '../../src/designer/designer';
|
||||||
|
import formSchema from '../fixtures/schema/form';
|
||||||
|
import { getIdsFromSchema, getNodeFromSchemaById } from '../utils';
|
||||||
|
import { EBADF } from 'constants';
|
||||||
|
|
||||||
|
const mockCreateSettingEntry = jest.fn();
|
||||||
|
jest.mock('../../src/designer/designer', () => {
|
||||||
|
return {
|
||||||
|
Designer: jest.fn().mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
getComponentMeta() {
|
||||||
|
return {
|
||||||
|
getMetadata() {
|
||||||
|
return { experimental: null };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
transformProps(props) { return props; },
|
||||||
|
createSettingEntry: mockCreateSettingEntry,
|
||||||
|
postEvent() {},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
let designer = null;
|
||||||
|
beforeAll(() => {
|
||||||
|
designer = new Designer({});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('schema 生成节点模型测试', () => {
|
||||||
|
describe('block ❌ | component ❌ | slot ❌', () => {
|
||||||
|
let project: Project;
|
||||||
|
beforeEach(() => {
|
||||||
|
project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchema,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
project.unload();
|
||||||
|
});
|
||||||
|
it('基本的节点模型初始化,模型导出', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const expectedNodeCnt = ids.length;
|
||||||
|
expect(nodesMap.size).toBe(expectedNodeCnt);
|
||||||
|
ids.forEach(id => {
|
||||||
|
expect(nodesMap.get(id).componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName);
|
||||||
|
});
|
||||||
|
|
||||||
|
const pageNode = currentDocument?.getNode('node_k1ow3cb9');
|
||||||
|
expect(pageNode?.getComponentName()).toBe('Page');
|
||||||
|
expect(pageNode?.getIcon()).toBeUndefined;
|
||||||
|
|
||||||
|
const exportSchema = currentDocument?.export(1);
|
||||||
|
expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);
|
||||||
|
expect(mockCreateSettingEntry).toBeCalledTimes(expectedNodeCnt);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('基本的节点模型初始化,节点深度', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const getNode = currentDocument.getNode.bind(currentDocument);
|
||||||
|
|
||||||
|
const pageNode = getNode('node_k1ow3cb9');
|
||||||
|
const rootHeaderNode = getNode('node_k1ow3cba');
|
||||||
|
const rootContentNode = getNode('node_k1ow3cbb');
|
||||||
|
const rootFooterNode = getNode('node_k1ow3cbc');
|
||||||
|
const formNode = getNode('form');
|
||||||
|
const cardNode = getNode('node_k1ow3cbj');
|
||||||
|
const cardContentNode = getNode('node_k1ow3cbk');
|
||||||
|
const columnsLayoutNode = getNode('node_k1ow3cbw');
|
||||||
|
const columnNode = getNode('node_k1ow3cbx');
|
||||||
|
const textFieldNode = getNode('node_k1ow3cbz');
|
||||||
|
|
||||||
|
expect(pageNode?.zLevel).toBe(0);
|
||||||
|
expect(rootHeaderNode?.zLevel).toBe(1);
|
||||||
|
expect(rootContentNode?.zLevel).toBe(1);
|
||||||
|
expect(rootFooterNode?.zLevel).toBe(1);
|
||||||
|
expect(formNode?.zLevel).toBe(2);
|
||||||
|
expect(cardNode?.zLevel).toBe(3);
|
||||||
|
expect(cardContentNode?.zLevel).toBe(4);
|
||||||
|
expect(columnsLayoutNode?.zLevel).toBe(5);
|
||||||
|
expect(columnNode?.zLevel).toBe(6);
|
||||||
|
expect(textFieldNode?.zLevel).toBe(7);
|
||||||
|
|
||||||
|
expect(textFieldNode?.getZLevelTop(7)).toEqual(textFieldNode);
|
||||||
|
expect(textFieldNode?.getZLevelTop(6)).toEqual(columnNode);
|
||||||
|
expect(textFieldNode?.getZLevelTop(5)).toEqual(columnsLayoutNode);
|
||||||
|
expect(textFieldNode?.getZLevelTop(4)).toEqual(cardContentNode);
|
||||||
|
expect(textFieldNode?.getZLevelTop(3)).toEqual(cardNode);
|
||||||
|
expect(textFieldNode?.getZLevelTop(2)).toEqual(formNode);
|
||||||
|
expect(textFieldNode?.getZLevelTop(1)).toEqual(rootContentNode);
|
||||||
|
expect(textFieldNode?.getZLevelTop(0)).toEqual(pageNode);
|
||||||
|
|
||||||
|
// 异常情况
|
||||||
|
expect(textFieldNode?.getZLevelTop(8)).toBeNull;
|
||||||
|
expect(textFieldNode?.getZLevelTop(-1)).toBeNull;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('基本的节点模型初始化,节点父子、兄弟相关方法', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const getNode = currentDocument.getNode.bind(currentDocument);
|
||||||
|
|
||||||
|
const pageNode = getNode('node_k1ow3cb9');
|
||||||
|
const rootHeaderNode = getNode('node_k1ow3cba');
|
||||||
|
const rootContentNode = getNode('node_k1ow3cbb');
|
||||||
|
const rootFooterNode = getNode('node_k1ow3cbc');
|
||||||
|
const formNode = getNode('form');
|
||||||
|
const cardNode = getNode('node_k1ow3cbj');
|
||||||
|
const cardContentNode = getNode('node_k1ow3cbk');
|
||||||
|
const columnsLayoutNode = getNode('node_k1ow3cbw');
|
||||||
|
const columnNode = getNode('node_k1ow3cbx');
|
||||||
|
const textFieldNode = getNode('node_k1ow3cbz');
|
||||||
|
|
||||||
|
expect(pageNode?.index).toBe(-1);
|
||||||
|
expect(pageNode?.children.toString()).toBe('[object Array]');
|
||||||
|
expect(pageNode?.children?.get(1)).toBe(rootContentNode);
|
||||||
|
expect(pageNode?.getChildren()?.get(1)).toBe(rootContentNode);
|
||||||
|
expect(pageNode?.getNode()).toBe(pageNode);
|
||||||
|
|
||||||
|
expect(rootFooterNode?.index).toBe(2);
|
||||||
|
|
||||||
|
expect(textFieldNode?.getParent()).toBe(columnNode);
|
||||||
|
expect(columnNode?.getParent()).toBe(columnsLayoutNode);
|
||||||
|
expect(columnsLayoutNode?.getParent()).toBe(cardContentNode);
|
||||||
|
expect(cardContentNode?.getParent()).toBe(cardNode);
|
||||||
|
expect(cardNode?.getParent()).toBe(formNode);
|
||||||
|
expect(formNode?.getParent()).toBe(rootContentNode);
|
||||||
|
expect(rootContentNode?.getParent()).toBe(pageNode);
|
||||||
|
expect(rootContentNode?.prevSibling).toBe(rootHeaderNode);
|
||||||
|
expect(rootContentNode?.nextSibling).toBe(rootFooterNode);
|
||||||
|
|
||||||
|
expect(pageNode?.isRoot()).toBe(true);
|
||||||
|
expect(pageNode?.contains(textFieldNode)).toBe(true);
|
||||||
|
expect(textFieldNode?.getRoot()).toBe(pageNode);
|
||||||
|
expect(columnNode?.getRoot()).toBe(pageNode);
|
||||||
|
expect(columnsLayoutNode?.getRoot()).toBe(pageNode);
|
||||||
|
expect(cardContentNode?.getRoot()).toBe(pageNode);
|
||||||
|
expect(cardNode?.getRoot()).toBe(pageNode);
|
||||||
|
expect(formNode?.getRoot()).toBe(pageNode);
|
||||||
|
expect(rootContentNode?.getRoot()).toBe(pageNode);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('基本的节点模型初始化,节点新建、删除等事件', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const getNode = currentDocument.getNode.bind(currentDocument);
|
||||||
|
const createNode = currentDocument.createNode.bind(currentDocument);
|
||||||
|
|
||||||
|
const pageNode = getNode('node_k1ow3cb9');
|
||||||
|
const nodeCreateHandler = jest.fn();
|
||||||
|
currentDocument?.onNodeCreate(nodeCreateHandler);
|
||||||
|
|
||||||
|
const node = createNode({
|
||||||
|
componentName: 'TextInput',
|
||||||
|
props: {
|
||||||
|
propA: 'haha',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
currentDocument?.insertNode(pageNode, node);
|
||||||
|
|
||||||
|
expect(nodeCreateHandler).toHaveBeenCalledTimes(1);
|
||||||
|
expect(nodeCreateHandler.mock.calls[0][0]).toBe(node);
|
||||||
|
expect(nodeCreateHandler.mock.calls[0][0].componentName).toBe('TextInput');
|
||||||
|
expect(nodeCreateHandler.mock.calls[0][0].getPropValue('propA')).toBe('haha');
|
||||||
|
|
||||||
|
const nodeDestroyHandler = jest.fn();
|
||||||
|
currentDocument?.onNodeDestroy(nodeDestroyHandler);
|
||||||
|
node.remove();
|
||||||
|
expect(nodeDestroyHandler).toHaveBeenCalledTimes(1);
|
||||||
|
expect(nodeDestroyHandler.mock.calls[0][0]).toBe(node);
|
||||||
|
expect(nodeDestroyHandler.mock.calls[0][0].componentName).toBe('TextInput');
|
||||||
|
expect(nodeDestroyHandler.mock.calls[0][0].getPropValue('propA')).toBe('haha');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip('基本的节点模型初始化,节点插入等方法', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const getNode = currentDocument.getNode.bind(currentDocument);
|
||||||
|
|
||||||
|
const formNode = getNode('form');
|
||||||
|
const node1 = currentDocument.createNode({
|
||||||
|
componentName: 'TextInput',
|
||||||
|
props: {
|
||||||
|
propA: 'haha',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const node2 = currentDocument.createNode({
|
||||||
|
componentName: 'TextInput',
|
||||||
|
props: {
|
||||||
|
propA: 'heihei',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const node3 = currentDocument.createNode({
|
||||||
|
componentName: 'TextInput',
|
||||||
|
props: {
|
||||||
|
propA: 'heihei2',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const node4 = currentDocument.createNode({
|
||||||
|
componentName: 'TextInput',
|
||||||
|
props: {
|
||||||
|
propA: 'heihei3',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
formNode?.insertBefore(node2);
|
||||||
|
// formNode?.insertBefore(node1, node2);
|
||||||
|
// formNode?.insertAfter(node3);
|
||||||
|
// formNode?.insertAfter(node4, node3);
|
||||||
|
|
||||||
|
expect(formNode?.children?.get(0)).toBe(node1);
|
||||||
|
expect(formNode?.children?.get(1)).toBe(node2);
|
||||||
|
// expect(formNode?.children?.get(5)).toBe(node3);
|
||||||
|
// expect(formNode?.children?.get(6)).toBe(node4);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('基本的节点模型初始化,节点其他方法', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const getNode = currentDocument.getNode.bind(currentDocument);
|
||||||
|
|
||||||
|
const pageNode = getNode('node_k1ow3cb9');
|
||||||
|
expect(pageNode?.isPage()).toBe(true);
|
||||||
|
expect(pageNode?.isComponent()).toBe(false);
|
||||||
|
expect(pageNode?.isSlot()).toBe(false);
|
||||||
|
expect(pageNode?.title).toBe('hey, i\' a page!');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('节点新增(insertNode)', () => {
|
||||||
|
let project: Project;
|
||||||
|
beforeEach(() => {
|
||||||
|
project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchema,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
});
|
||||||
|
it('场景一:插入 NodeSchema,不指定 index', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const formNode = nodesMap.get('form') as Node;
|
||||||
|
const formNode2 = currentDocument?.getNode('form');
|
||||||
|
expect(formNode).toEqual(formNode2);
|
||||||
|
currentDocument?.insertNode(formNode, {
|
||||||
|
componentName: 'TextInput',
|
||||||
|
id: 'nodeschema-id1',
|
||||||
|
props: {
|
||||||
|
propA: 'haha',
|
||||||
|
propB: 3
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(nodesMap.size).toBe(ids.length + 1);
|
||||||
|
expect(formNode.children?.length).toBe(4);
|
||||||
|
const insertedNode = formNode.children.get(formNode.children.length - 1);
|
||||||
|
expect(insertedNode.componentName).toBe('TextInput');
|
||||||
|
expect(insertedNode.propsData).toEqual({
|
||||||
|
propA: 'haha',
|
||||||
|
propB: 3
|
||||||
|
});
|
||||||
|
// TODO: 把 checkId 的 commit pick 过来
|
||||||
|
// expect(nodesMap.get('nodeschema-id1').componentName).toBe('TextInput');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('场景一:插入 NodeSchema,指定 index: 0', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const nodesMap = currentDocument.nodesMap;
|
||||||
|
const formNode = nodesMap.get('form');
|
||||||
|
currentDocument?.insertNode(formNode, {
|
||||||
|
componentName: 'TextInput',
|
||||||
|
id: 'nodeschema-id1',
|
||||||
|
props: {
|
||||||
|
propA: 'haha',
|
||||||
|
propB: 3
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
expect(nodesMap.size).toBe(ids.length + 1);
|
||||||
|
expect(formNode.children.length).toBe(4);
|
||||||
|
const insertedNode = formNode.children.get(0);
|
||||||
|
expect(insertedNode.componentName).toBe('TextInput');
|
||||||
|
expect(insertedNode.propsData).toEqual({
|
||||||
|
propA: 'haha',
|
||||||
|
propB: 3
|
||||||
|
});
|
||||||
|
// TODO: 把 checkId 的 commit pick 过来
|
||||||
|
// expect(nodesMap.get('nodeschema-id1').componentName).toBe('TextInput');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('场景一:插入 NodeSchema,指定 index: 1', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const formNode = nodesMap.get('form');
|
||||||
|
currentDocument?.insertNode(formNode, {
|
||||||
|
componentName: 'TextInput',
|
||||||
|
id: 'nodeschema-id1',
|
||||||
|
props: {
|
||||||
|
propA: 'haha',
|
||||||
|
propB: 3
|
||||||
|
}
|
||||||
|
}, 1);
|
||||||
|
expect(nodesMap.size).toBe(ids.length + 1);
|
||||||
|
expect(formNode.children.length).toBe(4);
|
||||||
|
const insertedNode = formNode.children.get(1);
|
||||||
|
expect(insertedNode.componentName).toBe('TextInput');
|
||||||
|
expect(insertedNode.propsData).toEqual({
|
||||||
|
propA: 'haha',
|
||||||
|
propB: 3
|
||||||
|
});
|
||||||
|
// TODO: 把 checkId 的 commit pick 过来
|
||||||
|
// expect(nodesMap.get('nodeschema-id1').componentName).toBe('TextInput');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('场景一:插入 NodeSchema,有 children', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const formNode = nodesMap.get('form') as Node;
|
||||||
|
currentDocument?.insertNode(formNode, {
|
||||||
|
componentName: 'ParentNode',
|
||||||
|
props: {
|
||||||
|
propA: 'haha',
|
||||||
|
propB: 3
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'SubNode',
|
||||||
|
props: {
|
||||||
|
propA: 'haha',
|
||||||
|
propB: 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'SubNode2',
|
||||||
|
props: {
|
||||||
|
propA: 'haha',
|
||||||
|
propB: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
expect(nodesMap.size).toBe(ids.length + 3);
|
||||||
|
expect(formNode.children.length).toBe(4);
|
||||||
|
expect(formNode.children?.get(3)?.componentName).toBe('ParentNode');
|
||||||
|
expect(formNode.children?.get(3)?.children?.get(0)?.componentName).toBe('SubNode');
|
||||||
|
expect(formNode.children?.get(3)?.children?.get(1)?.componentName).toBe('SubNode2');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip('场景一:插入 NodeSchema,id 与现有 schema 里的 id 重复', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const formNode = nodesMap.get('form');
|
||||||
|
currentDocument?.insertNode(formNode, {
|
||||||
|
componentName: 'TextInput',
|
||||||
|
id: 'nodeschema-id1',
|
||||||
|
props: {
|
||||||
|
propA: 'haha',
|
||||||
|
propB: 3
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(nodesMap.get('nodeschema-id1').componentName).toBe('TextInput');
|
||||||
|
expect(nodesMap.size).toBe(ids.length + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip('场景一:插入 NodeSchema,id 与现有 schema 里的 id 重复,但关闭了 id 检测器', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const formNode = nodesMap.get('form');
|
||||||
|
currentDocument?.insertNode(formNode, {
|
||||||
|
componentName: 'TextInput',
|
||||||
|
id: 'nodeschema-id1',
|
||||||
|
props: {
|
||||||
|
propA: 'haha',
|
||||||
|
propB: 3
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(nodesMap.get('nodeschema-id1').componentName).toBe('TextInput');
|
||||||
|
expect(nodesMap.size).toBe(ids.length + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('场景二:插入 Node 实例', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const formNode = nodesMap.get('form');
|
||||||
|
const inputNode = currentDocument?.createNode({
|
||||||
|
componentName: 'TextInput',
|
||||||
|
id: 'nodeschema-id2',
|
||||||
|
props: {
|
||||||
|
propA: 'haha',
|
||||||
|
propB: 3
|
||||||
|
}
|
||||||
|
});
|
||||||
|
currentDocument?.insertNode(formNode, inputNode);
|
||||||
|
expect(formNode.children?.get(3)?.componentName).toBe('TextInput');
|
||||||
|
expect(nodesMap.size).toBe(ids.length + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('场景三:插入 JSExpression', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const formNode = nodesMap.get('form') as Node;
|
||||||
|
currentDocument?.insertNode(formNode, {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: 'just a expression'
|
||||||
|
});
|
||||||
|
expect(nodesMap.size).toBe(ids.length + 1);
|
||||||
|
expect(formNode.children?.get(3)?.componentName).toBe('Leaf');
|
||||||
|
// expect(formNode.children?.get(3)?.children).toEqual({
|
||||||
|
// type: 'JSExpression',
|
||||||
|
// value: 'just a expression'
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
it('场景四:插入 string', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const formNode = nodesMap.get('form') as Node;
|
||||||
|
currentDocument?.insertNode(formNode, 'just a string');
|
||||||
|
expect(nodesMap.size).toBe(ids.length + 1);
|
||||||
|
expect(formNode.children?.get(3)?.componentName).toBe('Leaf');
|
||||||
|
// expect(formNode.children?.get(3)?.children).toBe('just a string');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('节点新增(insertNodes)', () => {
|
||||||
|
let project: Project;
|
||||||
|
beforeEach(() => {
|
||||||
|
project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchema,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
});
|
||||||
|
it('场景一:插入 NodeSchema,指定 index', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const formNode = nodesMap.get('form') as Node;
|
||||||
|
const formNode2 = currentDocument?.getNode('form');
|
||||||
|
expect(formNode).toEqual(formNode2);
|
||||||
|
currentDocument?.insertNodes(formNode, [
|
||||||
|
{
|
||||||
|
componentName: 'TextInput',
|
||||||
|
props: {
|
||||||
|
propA: 'haha2',
|
||||||
|
propB: 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'TextInput2',
|
||||||
|
props: {
|
||||||
|
propA: 'haha',
|
||||||
|
propB: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
], 1);
|
||||||
|
expect(nodesMap.size).toBe(ids.length + 2);
|
||||||
|
expect(formNode.children?.length).toBe(5);
|
||||||
|
const insertedNode1 = formNode.children.get(1);
|
||||||
|
const insertedNode2 = formNode.children.get(2);
|
||||||
|
expect(insertedNode1.componentName).toBe('TextInput');
|
||||||
|
expect(insertedNode1.propsData).toEqual({
|
||||||
|
propA: 'haha2',
|
||||||
|
propB: 3
|
||||||
|
});
|
||||||
|
expect(insertedNode2.componentName).toBe('TextInput2');
|
||||||
|
expect(insertedNode2.propsData).toEqual({
|
||||||
|
propA: 'haha',
|
||||||
|
propB: 3
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('场景二:插入 Node 实例,指定 index', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const formNode = nodesMap.get('form') as Node;
|
||||||
|
const formNode2 = currentDocument?.getNode('form');
|
||||||
|
expect(formNode).toEqual(formNode2);
|
||||||
|
const createdNode1 = currentDocument?.createNode({
|
||||||
|
componentName: 'TextInput',
|
||||||
|
props: {
|
||||||
|
propA: 'haha2',
|
||||||
|
propB: 3
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const createdNode2 = currentDocument?.createNode({
|
||||||
|
componentName: 'TextInput2',
|
||||||
|
props: {
|
||||||
|
propA: 'haha',
|
||||||
|
propB: 3
|
||||||
|
}
|
||||||
|
});
|
||||||
|
currentDocument?.insertNodes(formNode, [ createdNode1, createdNode2 ], 1);
|
||||||
|
expect(nodesMap.size).toBe(ids.length + 2);
|
||||||
|
expect(formNode.children?.length).toBe(5);
|
||||||
|
const insertedNode1 = formNode.children.get(1);
|
||||||
|
const insertedNode2 = formNode.children.get(2);
|
||||||
|
expect(insertedNode1.componentName).toBe('TextInput');
|
||||||
|
expect(insertedNode1.propsData).toEqual({
|
||||||
|
propA: 'haha2',
|
||||||
|
propB: 3
|
||||||
|
});
|
||||||
|
expect(insertedNode2.componentName).toBe('TextInput2');
|
||||||
|
expect(insertedNode2.propsData).toEqual({
|
||||||
|
propA: 'haha',
|
||||||
|
propB: 3
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('block ❌ | component ❌ | slot ✅', () => {
|
||||||
|
it('基本的 slot 创建', () => {
|
||||||
|
const formSchemaWithSlot = set(cloneDeep(formSchema), 'children[0].children[0].props.title.type', 'JSSlot');
|
||||||
|
const project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchemaWithSlot,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
// 目前每个 slot 会新增(1 + children.length)个节点
|
||||||
|
const expectedNodeCnt = ids.length + 2;
|
||||||
|
expect(nodesMap.size).toBe(expectedNodeCnt);
|
||||||
|
// PageHeader
|
||||||
|
expect(nodesMap.get('node_k1ow3cbd').slots).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
61
packages/designer/tests/node/node.dragdrop.test.ts
Normal file
61
packages/designer/tests/node/node.dragdrop.test.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import set from 'lodash/set';
|
||||||
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
|
import '../fixtures/window';
|
||||||
|
import { Project } from '../../src/project/project';
|
||||||
|
import { Node } from '../../src/document/node/node';
|
||||||
|
import { Designer } from '../../src/designer/designer';
|
||||||
|
import formSchema from '../fixtures/schema/form';
|
||||||
|
import { getIdsFromSchema, getNodeFromSchemaById } from '../utils';
|
||||||
|
|
||||||
|
const mockCreateSettingEntry = jest.fn();
|
||||||
|
jest.mock('../../src/designer/designer', () => {
|
||||||
|
return {
|
||||||
|
Designer: jest.fn().mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
getComponentMeta() {
|
||||||
|
return {
|
||||||
|
getMetadata() {
|
||||||
|
return { experimental: null };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
transformProps(props) { return props; },
|
||||||
|
createSettingEntry: mockCreateSettingEntry,
|
||||||
|
postEvent() {},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
let designer = null;
|
||||||
|
beforeAll(() => {
|
||||||
|
designer = new Designer({});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skip('节点拖拽测试', () => {
|
||||||
|
describe('block ❌ | component ❌ | slot ❌', () => {
|
||||||
|
it('修改普通属性,string | number', () => {
|
||||||
|
const project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchema,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const expectedNodeCnt = ids.length;
|
||||||
|
expect(nodesMap.size).toBe(expectedNodeCnt);
|
||||||
|
ids.forEach(id => {
|
||||||
|
expect(nodesMap.get(id).componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName);
|
||||||
|
});
|
||||||
|
|
||||||
|
const exportSchema = currentDocument?.export(1);
|
||||||
|
expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);
|
||||||
|
expect(mockCreateSettingEntry).toBeCalledTimes(expectedNodeCnt);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
456
packages/designer/tests/node/node.modify.test.ts
Normal file
456
packages/designer/tests/node/node.modify.test.ts
Normal file
@ -0,0 +1,456 @@
|
|||||||
|
import set from 'lodash/set';
|
||||||
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
|
import '../fixtures/window';
|
||||||
|
import { Project } from '../../src/project/project';
|
||||||
|
import { Node } from '../../src/document/node/node';
|
||||||
|
import { Designer } from '../../src/designer/designer';
|
||||||
|
import formSchema from '../fixtures/schema/form';
|
||||||
|
import { getIdsFromSchema, getNodeFromSchemaById } from '../utils';
|
||||||
|
|
||||||
|
const mockCreateSettingEntry = jest.fn();
|
||||||
|
jest.mock('../../src/designer/designer', () => {
|
||||||
|
return {
|
||||||
|
Designer: jest.fn().mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
getComponentMeta() {
|
||||||
|
return {
|
||||||
|
getMetadata() {
|
||||||
|
return { experimental: null };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
transformProps(props) { return props; },
|
||||||
|
createSettingEntry: mockCreateSettingEntry,
|
||||||
|
postEvent() {},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
let designer = null;
|
||||||
|
beforeAll(() => {
|
||||||
|
designer = new Designer({});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('schema 生成节点模型测试', () => {
|
||||||
|
describe('block ❌ | component ❌ | slot ❌', () => {
|
||||||
|
let project: Project;
|
||||||
|
beforeEach(() => {
|
||||||
|
project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchema,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
});
|
||||||
|
it('读取普通属性,string | number | object', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const expectedNodeCnt = ids.length;
|
||||||
|
const formNode = currentDocument?.getNode('form');
|
||||||
|
/*
|
||||||
|
props: {
|
||||||
|
size: 'medium',
|
||||||
|
labelAlign: 'top',
|
||||||
|
autoValidate: true,
|
||||||
|
scrollToFirstError: true,
|
||||||
|
autoUnmount: true,
|
||||||
|
behavior: 'NORMAL',
|
||||||
|
dataSource: {
|
||||||
|
type: 'variable',
|
||||||
|
variable: 'state.formData',
|
||||||
|
},
|
||||||
|
obj: {
|
||||||
|
a: 1,
|
||||||
|
b: false,
|
||||||
|
c: 'string',
|
||||||
|
},
|
||||||
|
__style__: {},
|
||||||
|
fieldId: 'form',
|
||||||
|
fieldOptions: {},
|
||||||
|
},
|
||||||
|
id: 'form',
|
||||||
|
condition: true,
|
||||||
|
*/
|
||||||
|
const sizeProp = formNode?.getProp('size');
|
||||||
|
const sizeProp2 = formNode?.getProps().getProp('size');
|
||||||
|
expect(sizeProp).toBe(sizeProp2);
|
||||||
|
expect(sizeProp?.getAsString()).toBe('medium');
|
||||||
|
expect(sizeProp?.getValue()).toBe('medium');
|
||||||
|
|
||||||
|
const autoValidateProp = formNode?.getProp('autoValidate');
|
||||||
|
expect(autoValidateProp?.getValue()).toBe(true);
|
||||||
|
|
||||||
|
const objProp = formNode?.getProp('obj');
|
||||||
|
expect(objProp?.getValue()).toEqual({
|
||||||
|
a: 1,
|
||||||
|
b: false,
|
||||||
|
c: 'string',
|
||||||
|
});
|
||||||
|
const objAProp = formNode?.getProp('obj.a');
|
||||||
|
const objBProp = formNode?.getProp('obj.b');
|
||||||
|
const objCProp = formNode?.getProp('obj.c');
|
||||||
|
expect(objAProp?.getValue()).toBe(1);
|
||||||
|
expect(objBProp?.getValue()).toBe(false);
|
||||||
|
expect(objCProp?.getValue()).toBe('string');
|
||||||
|
|
||||||
|
const idProp = formNode?.getExtraProp('extraPropA');
|
||||||
|
expect(idProp?.getValue()).toBe('extraPropA');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('修改普通属性,string | number | object,使用 Node 实例接口', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const expectedNodeCnt = ids.length;
|
||||||
|
const formNode = currentDocument?.getNode('form');
|
||||||
|
/*
|
||||||
|
props: {
|
||||||
|
size: 'medium',
|
||||||
|
labelAlign: 'top',
|
||||||
|
autoValidate: true,
|
||||||
|
scrollToFirstError: true,
|
||||||
|
autoUnmount: true,
|
||||||
|
behavior: 'NORMAL',
|
||||||
|
dataSource: {
|
||||||
|
type: 'variable',
|
||||||
|
variable: 'state.formData',
|
||||||
|
},
|
||||||
|
obj: {
|
||||||
|
a: 1,
|
||||||
|
b: false,
|
||||||
|
c: 'string',
|
||||||
|
},
|
||||||
|
__style__: {},
|
||||||
|
fieldId: 'form',
|
||||||
|
fieldOptions: {},
|
||||||
|
},
|
||||||
|
id: 'form',
|
||||||
|
condition: true,
|
||||||
|
*/
|
||||||
|
formNode?.setPropValue('size', 'large');
|
||||||
|
const sizeProp = formNode?.getProp('size');
|
||||||
|
expect(sizeProp?.getAsString()).toBe('large');
|
||||||
|
expect(sizeProp?.getValue()).toBe('large');
|
||||||
|
|
||||||
|
formNode?.setPropValue('autoValidate', false);
|
||||||
|
const autoValidateProp = formNode?.getProp('autoValidate');
|
||||||
|
expect(autoValidateProp?.getValue()).toBe(false);
|
||||||
|
|
||||||
|
formNode?.setPropValue('obj', {
|
||||||
|
a: 2,
|
||||||
|
b: true,
|
||||||
|
c: 'another string'
|
||||||
|
});
|
||||||
|
const objProp = formNode?.getProp('obj');
|
||||||
|
expect(objProp?.getValue()).toEqual({
|
||||||
|
a: 2,
|
||||||
|
b: true,
|
||||||
|
c: 'another string',
|
||||||
|
});
|
||||||
|
formNode?.setPropValue('obj.a', 3);
|
||||||
|
formNode?.setPropValue('obj.b', false);
|
||||||
|
formNode?.setPropValue('obj.c', 'string');
|
||||||
|
const objAProp = formNode?.getProp('obj.a');
|
||||||
|
const objBProp = formNode?.getProp('obj.b');
|
||||||
|
const objCProp = formNode?.getProp('obj.c');
|
||||||
|
expect(objAProp?.getValue()).toBe(3);
|
||||||
|
expect(objBProp?.getValue()).toBe(false);
|
||||||
|
expect(objCProp?.getValue()).toBe('string');
|
||||||
|
expect(objProp?.getValue()).toEqual({
|
||||||
|
a: 3,
|
||||||
|
b: false,
|
||||||
|
c: 'string',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('修改普通属性,string | number | object,使用 Props 实例接口', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const expectedNodeCnt = ids.length;
|
||||||
|
const formNode = currentDocument?.getNode('form');
|
||||||
|
/*
|
||||||
|
props: {
|
||||||
|
size: 'medium',
|
||||||
|
labelAlign: 'top',
|
||||||
|
autoValidate: true,
|
||||||
|
scrollToFirstError: true,
|
||||||
|
autoUnmount: true,
|
||||||
|
behavior: 'NORMAL',
|
||||||
|
dataSource: {
|
||||||
|
type: 'variable',
|
||||||
|
variable: 'state.formData',
|
||||||
|
},
|
||||||
|
obj: {
|
||||||
|
a: 1,
|
||||||
|
b: false,
|
||||||
|
c: 'string',
|
||||||
|
},
|
||||||
|
__style__: {},
|
||||||
|
fieldId: 'form',
|
||||||
|
fieldOptions: {},
|
||||||
|
},
|
||||||
|
id: 'form',
|
||||||
|
condition: true,
|
||||||
|
*/
|
||||||
|
const props = formNode?.getProps();
|
||||||
|
props?.setPropValue('size', 'large');
|
||||||
|
const sizeProp = formNode?.getProp('size');
|
||||||
|
expect(sizeProp?.getAsString()).toBe('large');
|
||||||
|
expect(sizeProp?.getValue()).toBe('large');
|
||||||
|
|
||||||
|
props?.setPropValue('autoValidate', false);
|
||||||
|
const autoValidateProp = formNode?.getProp('autoValidate');
|
||||||
|
expect(autoValidateProp?.getValue()).toBe(false);
|
||||||
|
|
||||||
|
props?.setPropValue('obj', {
|
||||||
|
a: 2,
|
||||||
|
b: true,
|
||||||
|
c: 'another string'
|
||||||
|
});
|
||||||
|
const objProp = formNode?.getProp('obj');
|
||||||
|
expect(objProp?.getValue()).toEqual({
|
||||||
|
a: 2,
|
||||||
|
b: true,
|
||||||
|
c: 'another string',
|
||||||
|
});
|
||||||
|
props?.setPropValue('obj.a', 3);
|
||||||
|
props?.setPropValue('obj.b', false);
|
||||||
|
props?.setPropValue('obj.c', 'string');
|
||||||
|
const objAProp = formNode?.getProp('obj.a');
|
||||||
|
const objBProp = formNode?.getProp('obj.b');
|
||||||
|
const objCProp = formNode?.getProp('obj.c');
|
||||||
|
expect(objAProp?.getValue()).toBe(3);
|
||||||
|
expect(objBProp?.getValue()).toBe(false);
|
||||||
|
expect(objCProp?.getValue()).toBe('string');
|
||||||
|
expect(objProp?.getValue()).toEqual({
|
||||||
|
a: 3,
|
||||||
|
b: false,
|
||||||
|
c: 'string',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('修改普通属性,string | number | object,使用 Prop 实例接口', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const expectedNodeCnt = ids.length;
|
||||||
|
const formNode = currentDocument?.getNode('form');
|
||||||
|
/*
|
||||||
|
props: {
|
||||||
|
size: 'medium',
|
||||||
|
labelAlign: 'top',
|
||||||
|
autoValidate: true,
|
||||||
|
scrollToFirstError: true,
|
||||||
|
autoUnmount: true,
|
||||||
|
behavior: 'NORMAL',
|
||||||
|
dataSource: {
|
||||||
|
type: 'variable',
|
||||||
|
variable: 'state.formData',
|
||||||
|
},
|
||||||
|
obj: {
|
||||||
|
a: 1,
|
||||||
|
b: false,
|
||||||
|
c: 'string',
|
||||||
|
},
|
||||||
|
__style__: {},
|
||||||
|
fieldId: 'form',
|
||||||
|
fieldOptions: {},
|
||||||
|
},
|
||||||
|
id: 'form',
|
||||||
|
condition: true,
|
||||||
|
*/
|
||||||
|
const sizeProp = formNode?.getProp('size');
|
||||||
|
sizeProp?.setValue('large');
|
||||||
|
expect(sizeProp?.getAsString()).toBe('large');
|
||||||
|
expect(sizeProp?.getValue()).toBe('large');
|
||||||
|
|
||||||
|
const autoValidateProp = formNode?.getProp('autoValidate');
|
||||||
|
autoValidateProp?.setValue(false);
|
||||||
|
expect(autoValidateProp?.getValue()).toBe(false);
|
||||||
|
|
||||||
|
|
||||||
|
const objProp = formNode?.getProp('obj');
|
||||||
|
objProp?.setValue({
|
||||||
|
a: 2,
|
||||||
|
b: true,
|
||||||
|
c: 'another string'
|
||||||
|
});
|
||||||
|
expect(objProp?.getValue()).toEqual({
|
||||||
|
a: 2,
|
||||||
|
b: true,
|
||||||
|
c: 'another string',
|
||||||
|
});
|
||||||
|
const objAProp = formNode?.getProp('obj.a');
|
||||||
|
const objBProp = formNode?.getProp('obj.b');
|
||||||
|
const objCProp = formNode?.getProp('obj.c');
|
||||||
|
objAProp?.setValue(3);
|
||||||
|
objBProp?.setValue(false);
|
||||||
|
objCProp?.setValue('string');
|
||||||
|
expect(objAProp?.getValue()).toBe(3);
|
||||||
|
expect(objBProp?.getValue()).toBe(false);
|
||||||
|
expect(objCProp?.getValue()).toBe('string');
|
||||||
|
expect(objProp?.getValue()).toEqual({
|
||||||
|
a: 3,
|
||||||
|
b: false,
|
||||||
|
c: 'string',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('block ❌ | component ❌ | slot ✅', () => {
|
||||||
|
let project: Project;
|
||||||
|
beforeEach(() => {
|
||||||
|
project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchema,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
});
|
||||||
|
it('修改 slot 属性,初始存在 slot 属性名,正常生成节点模型', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const expectedNodeCnt = ids.length;
|
||||||
|
const formNode = currentDocument?.getNode('form');
|
||||||
|
|
||||||
|
formNode?.setPropValue('slotA', {
|
||||||
|
type: 'JSSlot',
|
||||||
|
value: [{
|
||||||
|
componentName: 'TextInput1',
|
||||||
|
props: {
|
||||||
|
txt: 'haha',
|
||||||
|
num: 1,
|
||||||
|
bool: true
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
componentName: 'TextInput2',
|
||||||
|
props: {
|
||||||
|
txt: 'heihei',
|
||||||
|
num: 2,
|
||||||
|
bool: false
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(nodesMap.size).toBe(ids.length + 3);
|
||||||
|
expect(formNode?.slots).toHaveLength(1);
|
||||||
|
expect(formNode?.slots[0].children).toHaveLength(2);
|
||||||
|
const firstChildNode = formNode?.slots[0].children?.get(0);
|
||||||
|
const secondChildNode = formNode?.slots[0].children?.get(1);
|
||||||
|
expect(firstChildNode?.componentName).toBe('TextInput1');
|
||||||
|
expect(firstChildNode?.getPropValue('txt')).toBe('haha');
|
||||||
|
expect(firstChildNode?.getPropValue('num')).toBe(1);
|
||||||
|
expect(firstChildNode?.getPropValue('bool')).toBe(true);
|
||||||
|
expect(secondChildNode?.componentName).toBe('TextInput2');
|
||||||
|
expect(secondChildNode?.getPropValue('txt')).toBe('heihei');
|
||||||
|
expect(secondChildNode?.getPropValue('num')).toBe(2);
|
||||||
|
expect(secondChildNode?.getPropValue('bool')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('修改 slot 属性,初始存在 slot 属性名,关闭 slot', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const expectedNodeCnt = ids.length;
|
||||||
|
const formNode = currentDocument?.getNode('form');
|
||||||
|
|
||||||
|
formNode?.setPropValue('slotA', {
|
||||||
|
type: 'JSSlot',
|
||||||
|
value: [{
|
||||||
|
componentName: 'TextInput1',
|
||||||
|
props: {
|
||||||
|
txt: 'haha',
|
||||||
|
num: 1,
|
||||||
|
bool: true
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
componentName: 'TextInput2',
|
||||||
|
props: {
|
||||||
|
txt: 'heihei',
|
||||||
|
num: 2,
|
||||||
|
bool: false
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(nodesMap.size).toBe(ids.length + 3);
|
||||||
|
expect(formNode?.slots).toHaveLength(1);
|
||||||
|
|
||||||
|
formNode?.setPropValue('slotA', '');
|
||||||
|
|
||||||
|
expect(nodesMap.size).toBe(ids.length);
|
||||||
|
expect(formNode?.slots).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('修改 slot 属性,初始存在 slot 属性名,同名覆盖 slot', () => {
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const expectedNodeCnt = ids.length;
|
||||||
|
const formNode = currentDocument?.getNode('form');
|
||||||
|
|
||||||
|
formNode?.setPropValue('slotA', {
|
||||||
|
type: 'JSSlot',
|
||||||
|
name: 'slotA',
|
||||||
|
value: [{
|
||||||
|
componentName: 'TextInput1',
|
||||||
|
props: {
|
||||||
|
txt: 'haha',
|
||||||
|
num: 1,
|
||||||
|
bool: true
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
componentName: 'TextInput2',
|
||||||
|
props: {
|
||||||
|
txt: 'heihei',
|
||||||
|
num: 2,
|
||||||
|
bool: false
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(nodesMap.size).toBe(ids.length + 3);
|
||||||
|
expect(formNode?.slots).toHaveLength(1);
|
||||||
|
expect(formNode?.slots[0].children).toHaveLength(2);
|
||||||
|
|
||||||
|
let firstChildNode = formNode?.slots[0].children?.get(0);
|
||||||
|
expect(firstChildNode?.componentName).toBe('TextInput1');
|
||||||
|
expect(firstChildNode?.getPropValue('txt')).toBe('haha');
|
||||||
|
expect(firstChildNode?.getPropValue('num')).toBe(1);
|
||||||
|
expect(firstChildNode?.getPropValue('bool')).toBe(true);
|
||||||
|
|
||||||
|
formNode?.setPropValue('slotA', {
|
||||||
|
type: 'JSSlot',
|
||||||
|
name: 'slotA',
|
||||||
|
value: [{
|
||||||
|
componentName: 'TextInput3',
|
||||||
|
props: {
|
||||||
|
txt: 'xixi',
|
||||||
|
num: 3,
|
||||||
|
bool: false
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(nodesMap.size).toBe(ids.length + 2);
|
||||||
|
expect(formNode?.slots).toHaveLength(1);
|
||||||
|
expect(formNode?.slots[0].children).toHaveLength(1);
|
||||||
|
firstChildNode = formNode?.slots[0].children?.get(0);
|
||||||
|
expect(firstChildNode?.componentName).toBe('TextInput3');
|
||||||
|
expect(firstChildNode?.getPropValue('txt')).toBe('xixi');
|
||||||
|
expect(firstChildNode?.getPropValue('num')).toBe(3);
|
||||||
|
expect(firstChildNode?.getPropValue('bool')).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
122
packages/designer/tests/node/node.remove.test.ts
Normal file
122
packages/designer/tests/node/node.remove.test.ts
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import set from 'lodash/set';
|
||||||
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
|
import '../fixtures/window';
|
||||||
|
import { Project } from '../../src/project/project';
|
||||||
|
import { Node } from '../../src/document/node/node';
|
||||||
|
import { Designer } from '../../src/designer/designer';
|
||||||
|
import formSchema from '../fixtures/schema/form';
|
||||||
|
import { getIdsFromSchema, getNodeFromSchemaById } from '../utils';
|
||||||
|
|
||||||
|
const mockCreateSettingEntry = jest.fn();
|
||||||
|
jest.mock('../../src/designer/designer', () => {
|
||||||
|
return {
|
||||||
|
Designer: jest.fn().mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
getComponentMeta() {
|
||||||
|
return {
|
||||||
|
getMetadata() {
|
||||||
|
return { experimental: null };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
transformProps(props) { return props; },
|
||||||
|
createSettingEntry: mockCreateSettingEntry,
|
||||||
|
postEvent() {},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
let designer = null;
|
||||||
|
beforeAll(() => {
|
||||||
|
designer = new Designer({});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('节点模型删除测试', () => {
|
||||||
|
it('删除叶子节点', () => {
|
||||||
|
const project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchema,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const originalNodeCnt = ids.length;
|
||||||
|
expect(nodesMap.size).toBe(originalNodeCnt);
|
||||||
|
|
||||||
|
currentDocument?.removeNode('node_k1ow3cbn');
|
||||||
|
// Button#1
|
||||||
|
expect(nodesMap.size).toBe(originalNodeCnt - 1);
|
||||||
|
|
||||||
|
currentDocument?.removeNode(nodesMap.get('node_k1ow3cbp'));
|
||||||
|
// Button#2
|
||||||
|
expect(nodesMap.size).toBe(originalNodeCnt - 2);
|
||||||
|
|
||||||
|
currentDocument?.removeNode('unexisting_node');
|
||||||
|
expect(nodesMap.size).toBe(originalNodeCnt - 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('删除叶子节点,带有 slot', () => {
|
||||||
|
const formSchemaWithSlot = set(cloneDeep(formSchema),
|
||||||
|
'children[1].children[0].children[2].children[1].props.greeting.type', 'JSSlot');
|
||||||
|
const project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchemaWithSlot,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const originalNodeCnt = ids.length + 2;
|
||||||
|
expect(nodesMap.size).toBe(originalNodeCnt);
|
||||||
|
|
||||||
|
currentDocument?.removeNode('node_k1ow3cbp');
|
||||||
|
// Button + Slot + Text
|
||||||
|
expect(nodesMap.size).toBe(originalNodeCnt - 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('删除分支节点', () => {
|
||||||
|
const project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchema,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const originalNodeCnt = ids.length;
|
||||||
|
expect(nodesMap.size).toBe(originalNodeCnt);
|
||||||
|
|
||||||
|
currentDocument?.removeNode('node_k1ow3cbo');
|
||||||
|
// Div + 2 * Button
|
||||||
|
expect(nodesMap.size).toBe(originalNodeCnt - 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('删除分支节点,带有 slot', () => {
|
||||||
|
const formSchemaWithSlot = set(cloneDeep(formSchema),
|
||||||
|
'children[1].children[0].children[2].children[1].props.greeting.type', 'JSSlot');
|
||||||
|
const project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchemaWithSlot,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const originalNodeCnt = ids.length + 2;
|
||||||
|
expect(nodesMap.size).toBe(originalNodeCnt);
|
||||||
|
|
||||||
|
currentDocument?.removeNode('node_k1ow3cbo');
|
||||||
|
// Div + 2 * Button + Slot + Text
|
||||||
|
expect(nodesMap.size).toBe(originalNodeCnt - 5);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import set from 'lodash.set';
|
import set from 'lodash/set';
|
||||||
import cloneDeep from 'lodash.clonedeep';
|
import cloneDeep from 'lodash/clonedeep';
|
||||||
import '../fixtures/window';
|
import '../fixtures/window';
|
||||||
import { Project } from '../../src/project/project';
|
import { Project } from '../../src/project/project';
|
||||||
// import { Node } from '../../../src/document/node/node';
|
import { Node } from '../../src/document/node/node';
|
||||||
import { Designer } from '../../src/designer/designer';
|
import { Designer } from '../../src/designer/designer';
|
||||||
import formSchema from '../fixtures/schema/form';
|
import formSchema from '../fixtures/schema/form';
|
||||||
import { getIdsFromSchema, getNodeFromSchemaById } from '../utils';
|
import { getIdsFromSchema, getNodeFromSchemaById } from '../utils';
|
||||||
@ -34,7 +34,11 @@ beforeAll(() => {
|
|||||||
|
|
||||||
describe('schema 生成节点模型测试', () => {
|
describe('schema 生成节点模型测试', () => {
|
||||||
describe('block ❌ | component ❌ | slot ❌', () => {
|
describe('block ❌ | component ❌ | slot ❌', () => {
|
||||||
it('基本的节点模型初始化,模型导出', () => {
|
beforeEach(() => {
|
||||||
|
mockCreateSettingEntry.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('基本的节点模型初始化,模型导出,初始化传入 schema', () => {
|
||||||
const project = new Project(designer, {
|
const project = new Project(designer, {
|
||||||
componentsTree: [
|
componentsTree: [
|
||||||
formSchema,
|
formSchema,
|
||||||
@ -56,129 +60,75 @@ describe('schema 生成节点模型测试', () => {
|
|||||||
expect(mockCreateSettingEntry).toBeCalledTimes(expectedNodeCnt);
|
expect(mockCreateSettingEntry).toBeCalledTimes(expectedNodeCnt);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('节点新增(insertNode)', () => {
|
it('基本的节点模型初始化,模型导出,project.open 传入 schema', () => {
|
||||||
let project;
|
const project = new Project(designer);
|
||||||
beforeEach(() => {
|
project.open(formSchema);
|
||||||
project = new Project(designer, {
|
expect(project).toBeTruthy();
|
||||||
componentsTree: [
|
const { currentDocument } = project;
|
||||||
formSchema,
|
const { nodesMap } = currentDocument;
|
||||||
],
|
const ids = getIdsFromSchema(formSchema);
|
||||||
});
|
const expectedNodeCnt = ids.length;
|
||||||
project.open();
|
expect(nodesMap.size).toBe(expectedNodeCnt);
|
||||||
});
|
ids.forEach(id => {
|
||||||
it.only('场景一:插入 NodeSchema', () => {
|
expect(nodesMap.get(id).componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName);
|
||||||
expect(project).toBeTruthy();
|
|
||||||
const ids = getIdsFromSchema(formSchema);
|
|
||||||
const { currentDocument } = project;
|
|
||||||
const { nodesMap } = currentDocument;
|
|
||||||
const formNode = nodesMap.get('node_k1ow3cbq');
|
|
||||||
currentDocument?.insertNode(formNode, {
|
|
||||||
componentName: 'TextInput',
|
|
||||||
id: 'nodeschema-id1',
|
|
||||||
props: {
|
|
||||||
propA: 'haha',
|
|
||||||
propB: 3
|
|
||||||
}
|
|
||||||
});
|
|
||||||
expect(nodesMap.get('nodeschema-id1').componentName).toBe('TextInput');
|
|
||||||
expect(nodesMap.size).toBe(ids.length + 1);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it.only('场景一:插入 NodeSchema,有 children', () => {
|
const exportSchema = currentDocument?.export(1);
|
||||||
expect(project).toBeTruthy();
|
expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);
|
||||||
const ids = getIdsFromSchema(formSchema);
|
expect(mockCreateSettingEntry).toBeCalledTimes(expectedNodeCnt);
|
||||||
const { currentDocument } = project;
|
|
||||||
const { nodesMap } = currentDocument;
|
|
||||||
const formNode = nodesMap.get('node_k1ow3cbq');
|
|
||||||
currentDocument?.insertNode(formNode, {
|
|
||||||
componentName: 'TextInput',
|
|
||||||
id: 'nodeschema-id1',
|
|
||||||
props: {
|
|
||||||
propA: 'haha',
|
|
||||||
propB: 3
|
|
||||||
}
|
|
||||||
});
|
|
||||||
expect(nodesMap.get('nodeschema-id1').componentName).toBe('TextInput');
|
|
||||||
expect(nodesMap.size).toBe(ids.length + 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.only('场景一:插入 NodeSchema,id 与现有 schema 重复', () => {
|
|
||||||
expect(project).toBeTruthy();
|
|
||||||
const ids = getIdsFromSchema(formSchema);
|
|
||||||
const { currentDocument } = project;
|
|
||||||
const { nodesMap } = currentDocument;
|
|
||||||
const formNode = nodesMap.get('node_k1ow3cbq');
|
|
||||||
currentDocument?.insertNode(formNode, {
|
|
||||||
componentName: 'TextInput',
|
|
||||||
id: 'nodeschema-id1',
|
|
||||||
props: {
|
|
||||||
propA: 'haha',
|
|
||||||
propB: 3
|
|
||||||
}
|
|
||||||
});
|
|
||||||
expect(nodesMap.get('nodeschema-id1').componentName).toBe('TextInput');
|
|
||||||
expect(nodesMap.size).toBe(ids.length + 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.only('场景一:插入 NodeSchema,id 与现有 schema 重复,但关闭了 id 检测器', () => {
|
|
||||||
expect(project).toBeTruthy();
|
|
||||||
const ids = getIdsFromSchema(formSchema);
|
|
||||||
const { currentDocument } = project;
|
|
||||||
const { nodesMap } = currentDocument;
|
|
||||||
const formNode = nodesMap.get('node_k1ow3cbq');
|
|
||||||
currentDocument?.insertNode(formNode, {
|
|
||||||
componentName: 'TextInput',
|
|
||||||
id: 'nodeschema-id1',
|
|
||||||
props: {
|
|
||||||
propA: 'haha',
|
|
||||||
propB: 3
|
|
||||||
}
|
|
||||||
});
|
|
||||||
expect(nodesMap.get('nodeschema-id1').componentName).toBe('TextInput');
|
|
||||||
expect(nodesMap.size).toBe(ids.length + 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('场景二:插入 Node 实例', () => {
|
|
||||||
expect(project).toBeTruthy();
|
|
||||||
const ids = getIdsFromSchema(formSchema);
|
|
||||||
const { currentDocument } = project;
|
|
||||||
const { nodesMap } = currentDocument;
|
|
||||||
const formNode = nodesMap.get('node_k1ow3cbq');
|
|
||||||
const inputNode = currentDocument?.createNode({
|
|
||||||
componentName: 'TextInput',
|
|
||||||
id: 'nodeschema-id2',
|
|
||||||
props: {
|
|
||||||
propA: 'haha',
|
|
||||||
propB: 3
|
|
||||||
}
|
|
||||||
});
|
|
||||||
expect(inputNode.id).toBe('nodeschema-id2');
|
|
||||||
currentDocument?.insertNode(formNode, inputNode);
|
|
||||||
expect(nodesMap.get('nodeschema-id2').componentName).toBe('TextInput');
|
|
||||||
expect(nodesMap.size).toBe(ids.length + 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('场景二:插入 JSExpression', () => {});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
})
|
it('project 卸载所有 document - unload()', () => {
|
||||||
|
const project = new Project(designer);
|
||||||
|
project.open(formSchema);
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument, documents } = project;
|
||||||
|
|
||||||
it('block ❌ | component ❌ | slot ✅', () => {
|
expect(documents).toHaveLength(1);
|
||||||
const formSchemaWithSlot = set(cloneDeep(formSchema), 'children[0].children[0].props.title.type', 'JSSlot');
|
expect(currentDocument).toBe(documents[0]);
|
||||||
const project = new Project(designer, {
|
|
||||||
componentsTree: [
|
project.unload();
|
||||||
formSchemaWithSlot,
|
|
||||||
],
|
expect(documents).toHaveLength(0);
|
||||||
});
|
});
|
||||||
project.open();
|
|
||||||
expect(project).toBeTruthy();
|
it('project 卸载指定 document - removeDocument()', () => {
|
||||||
const { currentDocument } = project;
|
const project = new Project(designer);
|
||||||
const { nodesMap } = currentDocument;
|
project.open(formSchema);
|
||||||
const ids = getIdsFromSchema(formSchema);
|
expect(project).toBeTruthy();
|
||||||
// 目前每个 slot 会新增 1 + children.length 个节点
|
const { currentDocument, documents } = project;
|
||||||
const expectedNodeCnt = ids.length + 2;
|
|
||||||
expect(nodesMap.size).toBe(expectedNodeCnt);
|
expect(documents).toHaveLength(1);
|
||||||
// PageHeader
|
expect(currentDocument).toBe(documents[0]);
|
||||||
expect(nodesMap.get('node_k1ow3cbd').slots).toHaveLength(1);
|
|
||||||
|
project.removeDocument(currentDocument);
|
||||||
|
|
||||||
|
expect(documents).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('block ❌ | component ❌ | slot ✅', () => {
|
||||||
|
it('基本的节点模型初始化,模型导出,初始化传入 schema', () => {
|
||||||
|
const formSchemaWithSlot = set(cloneDeep(formSchema), 'children[0].children[0].props.title.type', 'JSSlot');
|
||||||
|
const project = new Project(designer, {
|
||||||
|
componentsTree: [
|
||||||
|
formSchemaWithSlot,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
project.open();
|
||||||
|
expect(project).toBeTruthy();
|
||||||
|
const { currentDocument } = project;
|
||||||
|
const { nodesMap } = currentDocument!;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
// 目前每个 slot 会新增(1 + children.length)个节点
|
||||||
|
const expectedNodeCnt = ids.length + 2;
|
||||||
|
expect(nodesMap.size).toBe(expectedNodeCnt);
|
||||||
|
// PageHeader
|
||||||
|
expect(nodesMap.get('node_k1ow3cbd').slots).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skip('多 document 测试', () => {
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -127,7 +127,7 @@ designer.addPropsReducer((props, node) => {
|
|||||||
!isJSBlock(ov) &&
|
!isJSBlock(ov) &&
|
||||||
!isJSSlot(ov) &&
|
!isJSSlot(ov) &&
|
||||||
!isVariable(ov) &&
|
!isVariable(ov) &&
|
||||||
isString(v)) {
|
(isString(v) || isI18NObject(v))) {
|
||||||
newProps[item.name] = convertToI18NObject(v);
|
newProps[item.name] = convertToI18NObject(v);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@ -54,5 +54,5 @@
|
|||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "http://registry.npm.alibaba-inc.com"
|
"registry": "http://registry.npm.alibaba-inc.com"
|
||||||
},
|
},
|
||||||
"homepage": "https://unpkg.alibaba-inc.com/@ali/lowcode-react-renderer@0.13.1-9/build/index.html"
|
"homepage": "https://unpkg.alibaba-inc.com/@ali/lowcode-react-renderer@0.13.1-10/build/index.html"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ module.exports = {
|
|||||||
'no-shadow': 0,
|
'no-shadow': 0,
|
||||||
'no-prototype-builtins': 0,
|
'no-prototype-builtins': 0,
|
||||||
'array-callback-return': 0,
|
'array-callback-return': 0,
|
||||||
'@typescript-eslint/member-ordering': 0
|
'@typescript-eslint/member-ordering': 0,
|
||||||
|
'react/no-find-dom-node', 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
import { ReactInstance } from 'react';
|
import { ReactInstance } from 'react';
|
||||||
|
import { findDOMNode } from 'react-dom';
|
||||||
import { isElement } from '@ali/lowcode-utils';
|
import { isElement } from '@ali/lowcode-utils';
|
||||||
import { isDOMNode } from './is-dom-node';
|
import { isDOMNode } from './is-dom-node';
|
||||||
|
|
||||||
@ -29,5 +30,5 @@ export function reactFindDOMNodes(elem: ReactInstance | null): Array<Element | T
|
|||||||
const elements: Array<Element | Text> = [];
|
const elements: Array<Element | Text> = [];
|
||||||
const fiberNode = (elem as any)[FIBER_KEY];
|
const fiberNode = (elem as any)[FIBER_KEY];
|
||||||
elementsFromFiber(fiberNode.child, elements);
|
elementsFromFiber(fiberNode.child, elements);
|
||||||
return elements.length > 0 ? elements : null;
|
return elements.length > 0 ? elements : [findDOMNode(elem)];
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user