diff --git a/packages/designer/jest.config.js b/packages/designer/jest.config.js index d58fe368f..53081b4ec 100644 --- a/packages/designer/jest.config.js +++ b/packages/designer/jest.config.js @@ -17,7 +17,7 @@ module.exports = { collectCoverageFrom: [ 'src/**/*.{ts,tsx}', '!src/**/*.d.ts', - '!src/icons', + '!src/icons/**', '!**/node_modules/**', '!**/vendor/**', ], diff --git a/packages/designer/package.json b/packages/designer/package.json index 860c9b311..f5459458e 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -18,6 +18,8 @@ "@ali/lowcode-types": "^1.0.23", "@ali/lowcode-utils": "^1.0.23", "classnames": "^2.2.6", + "enzyme": "^3.11.0", + "enzyme-adapter-react-16": "^1.15.5", "event": "^1.0.0", "react": "^16", "react-dom": "^16.7.0" @@ -26,6 +28,8 @@ "@ali/lowcode-test-mate": "^1.0.1", "@alib/build-scripts": "^0.1.29", "@types/classnames": "^2.2.7", + "@types/jest": "^26.0.16", + "@types/lodash": "^4.14.165", "@types/medium-editor": "^5.0.3", "@types/node": "^13.7.1", "@types/react": "^16", @@ -33,7 +37,7 @@ "babel-jest": "^26.5.2", "build-plugin-component": "^0.2.10", "build-scripts-config": "^0.1.8", - "jest": "^26.5.2", + "jest": "^26.6.3", "lodash": "^4.17.20", "typescript": "^4.0.3" }, diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index b0b02f772..08ee11af1 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -71,7 +71,7 @@ export class ComponentMeta { } set npm(_npm) { - this._npm = _npm; + this.setNpm(_npm); } private _componentName?: string; diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 98db49a05..d4fa6b5a0 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -916,8 +916,8 @@ export class Node { || (typeof rootCanDropIn === 'function' && rootCanDropIn(node))) { return { container: this, ref }; } - // 假如最后找不到合适位置,返回 undefined 阻止继续插入节点 - return undefined; + // 假如最后找不到合适位置,返回 null 阻止继续插入节点 + return null; } const canDropIn = this.componentMeta?.prototype?.options?.canDropIn; diff --git a/packages/designer/tests/builtin-simulator/host-view.test.tsx b/packages/designer/tests/builtin-simulator/host-view.test.tsx index 53d2225e0..af26e5ab9 100644 --- a/packages/designer/tests/builtin-simulator/host-view.test.tsx +++ b/packages/designer/tests/builtin-simulator/host-view.test.tsx @@ -1,6 +1,6 @@ import React from 'react'; import set from 'lodash/set'; -import cloneDeep from 'lodash/clonedeep'; +import cloneDeep from 'lodash/cloneDeep'; import '../fixtures/window'; import { Editor } from '@ali/lowcode-editor-core'; import { Project } from '../../src/project/project'; diff --git a/packages/designer/tests/builtin-simulator/host.test.tsx b/packages/designer/tests/builtin-simulator/host.test.tsx index fdeb0943a..b1b9fca6e 100644 --- a/packages/designer/tests/builtin-simulator/host.test.tsx +++ b/packages/designer/tests/builtin-simulator/host.test.tsx @@ -1,6 +1,6 @@ import React from 'react'; import set from 'lodash/set'; -import cloneDeep from 'lodash/clonedeep'; +import cloneDeep from 'lodash/cloneDeep'; import '../fixtures/window'; import { Editor } from '@ali/lowcode-editor-core'; import { diff --git a/packages/designer/tests/builtin-simulator/renderer.test.tsx b/packages/designer/tests/builtin-simulator/renderer.test.tsx index 6cead4122..1988ce3a8 100644 --- a/packages/designer/tests/builtin-simulator/renderer.test.tsx +++ b/packages/designer/tests/builtin-simulator/renderer.test.tsx @@ -1,6 +1,6 @@ import React from 'react'; import set from 'lodash/set'; -import cloneDeep from 'lodash/clonedeep'; +import cloneDeep from 'lodash/cloneDeep'; import '../fixtures/window'; import { Editor } from '@ali/lowcode-editor-core'; import { Project } from '../../src/project/project'; diff --git a/packages/designer/tests/designer/builtin-hotkey.test.ts b/packages/designer/tests/designer/builtin-hotkey.test.ts index cc010f85c..7e45bd7e8 100644 --- a/packages/designer/tests/designer/builtin-hotkey.test.ts +++ b/packages/designer/tests/designer/builtin-hotkey.test.ts @@ -1,5 +1,5 @@ import set from 'lodash/set'; -import cloneDeep from 'lodash/clonedeep'; +import cloneDeep from 'lodash/cloneDeep'; import '../fixtures/window'; import { Editor, globalContext } from '@ali/lowcode-editor-core'; import { Designer } from '../../src/designer/designer'; diff --git a/packages/designer/tests/designer/setting-entry/setting-prop-entry.test.ts b/packages/designer/tests/designer/setting-entry/setting-prop-entry.test.ts index 8ddf63f0b..ab07f6fec 100644 --- a/packages/designer/tests/designer/setting-entry/setting-prop-entry.test.ts +++ b/packages/designer/tests/designer/setting-entry/setting-prop-entry.test.ts @@ -1,5 +1,5 @@ import set from 'lodash/set'; -import cloneDeep from 'lodash/clonedeep'; +import cloneDeep from 'lodash/cloneDeep'; import '../../fixtures/window'; import { Editor } from '@ali/lowcode-editor-core'; import { Project } from '../../../src/project/project'; @@ -7,7 +7,7 @@ import { Node } from '../../../src/document/node/node'; import { Designer } from '../../../src/designer/designer'; import formSchema from '../../../fixtures/schema/form'; import settingSchema from '../../fixtures/schema/setting'; -import divMeta from '../../fixtures/prototype/div-meta'; +import divMeta from '../../fixtures/component-metadata/div'; import { getIdsFromSchema, getNodeFromSchemaById } from '../../utils'; const editor = new Editor(); @@ -48,7 +48,6 @@ describe('setting-prop-entry 测试', () => { // expect(behaviorProp.getValue()).toBe('SMALL'); behaviorProp.setValue('NORMAL'); expect(behaviorProp.getValue()).toBe('NORMAL'); - behaviorProp.clearValue(); behaviorProp.clearPropValue(); expect(settingEntry.getProp('behavior').getValue()).toBeUndefined; diff --git a/packages/designer/tests/designer/setting-entry/setting-top-entry.test.ts b/packages/designer/tests/designer/setting-entry/setting-top-entry.test.ts index e7e5dab24..b7faf27d4 100644 --- a/packages/designer/tests/designer/setting-entry/setting-top-entry.test.ts +++ b/packages/designer/tests/designer/setting-entry/setting-top-entry.test.ts @@ -1,5 +1,5 @@ import set from 'lodash/set'; -import cloneDeep from 'lodash/clonedeep'; +import cloneDeep from 'lodash/cloneDeep'; import '../../fixtures/window'; import { Editor } from '@ali/lowcode-editor-core'; import { Project } from '../../../src/project/project'; @@ -7,7 +7,7 @@ import { Node } from '../../../src/document/node/node'; import { Designer } from '../../../src/designer/designer'; import formSchema from '../../fixtures/schema/form'; import settingSchema from '../../fixtures/schema/setting'; -import divMeta from '../../fixtures/prototype/div-meta'; +import divMeta from '../../fixtures/component-metadata/div'; import { getIdsFromSchema, getNodeFromSchemaById } from '../../utils'; const editor = new Editor(); diff --git a/packages/designer/tests/document/document-model/__snapshots__/document-model.test.ts.snap b/packages/designer/tests/document/document-model/__snapshots__/document-model.test.ts.snap new file mode 100644 index 000000000..7f77cff89 --- /dev/null +++ b/packages/designer/tests/document/document-model/__snapshots__/document-model.test.ts.snap @@ -0,0 +1,1040 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`document-model 测试 各种方法测试 1`] = ` +Object { + "componentsMap": Array [], + "componentsTree": Array [ + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "componentName": "PageHeader", + "condition": true, + "id": "node_k1ow3cbd", + "props": Object { + "__slot__action": false, + "__slot__content": false, + "__slot__crumb": false, + "__slot__extraContent": false, + "__slot__logo": false, + "__slot__tab": false, + "__style__": Object {}, + "action": "", + "content": "", + "crumb": "", + "extraContent": "", + "fieldId": "pageHeader_k1ow3h1i", + "logo": "", + "subTitle": false, + "tab": "", + "title": Object { + "value": Array [ + Object { + "componentName": "Text", + "condition": true, + "id": "node_k1ow3cbf", + "props": Object { + "__style__": Object {}, + "behavior": "NORMAL", + "content": Object { + "en_US": "Title", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "个人信息", + }, + "fieldId": "text_k1ow3h1j", + "maxLine": 0, + "showTitle": false, + }, + }, + ], + }, + }, + }, + ], + "componentName": "RootHeader", + "condition": true, + "id": "node_k1ow3cba", + "props": Object {}, + }, + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "componentName": "TextField", + "condition": true, + "id": "node_k1ow3cbz", + "props": Object { + "__category__": "form", + "__style__": Object {}, + "__useMediator": "value", + "addonAfter": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "addonBefore": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "autoFocus": false, + "autoHeight": false, + "behavior": "NORMAL", + "cutString": false, + "fieldId": "textField_k1ow3h1w", + "fieldName": "name", + "hasClear": false, + "hasLimitHint": false, + "htmlType": "input", + "label": Object { + "en_US": "TextField", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "姓名", + }, + "labelAlign": "top", + "labelColOffset": 0, + "labelColSpan": 4, + "labelTextAlign": "right", + "labelTipsIcon": "", + "labelTipsText": Object { + "en_US": null, + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "labelTipsTypes": "none", + "placeholder": Object { + "en_US": "please input", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "请输入", + }, + "rows": 4, + "size": "medium", + "state": "", + "tips": Object { + "en_US": "", + "type": "i18n", + "zh_CN": "", + }, + "trim": false, + "validation": Array [ + Object { + "type": "required", + }, + ], + "value": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "wrapperColOffset": 0, + "wrapperColSpan": 0, + }, + }, + Object { + "componentName": "TextField", + "condition": true, + "id": "node_k1ow3cc1", + "props": Object { + "__category__": "form", + "__style__": Object {}, + "__useMediator": "value", + "addonAfter": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "addonBefore": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "autoFocus": false, + "autoHeight": false, + "behavior": "NORMAL", + "cutString": false, + "fieldId": "textField_k1ow3h1y", + "fieldName": "englishName", + "hasClear": false, + "hasLimitHint": false, + "htmlType": "input", + "label": Object { + "en_US": "TextField", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "英文名", + }, + "labelAlign": "top", + "labelColOffset": 0, + "labelColSpan": 4, + "labelTextAlign": "right", + "labelTipsIcon": "", + "labelTipsText": Object { + "en_US": null, + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "labelTipsTypes": "none", + "placeholder": Object { + "en_US": "please input", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "请输入", + }, + "rows": 4, + "size": "medium", + "state": "", + "tips": Object { + "en_US": "", + "type": "i18n", + "zh_CN": "", + }, + "trim": false, + "validation": Array [], + "value": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "wrapperColOffset": 0, + "wrapperColSpan": 0, + }, + }, + Object { + "componentName": "TextField", + "condition": true, + "id": "node_k1ow3cc3", + "props": Object { + "__category__": "form", + "__style__": Object {}, + "__useMediator": "value", + "addonAfter": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "addonBefore": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "autoFocus": false, + "autoHeight": false, + "behavior": "NORMAL", + "cutString": false, + "fieldId": "textField_k1ow3h20", + "fieldName": "jobTitle", + "hasClear": false, + "hasLimitHint": false, + "htmlType": "input", + "label": Object { + "en_US": "TextField", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "职位", + }, + "labelAlign": "top", + "labelColOffset": 0, + "labelColSpan": 4, + "labelTextAlign": "right", + "labelTipsIcon": "", + "labelTipsText": Object { + "en_US": null, + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "labelTipsTypes": "none", + "placeholder": Object { + "en_US": "please input", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "请输入", + }, + "rows": 4, + "size": "medium", + "state": "", + "tips": Object { + "en_US": "", + "type": "i18n", + "zh_CN": "", + }, + "trim": false, + "validation": Array [], + "value": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "wrapperColOffset": 0, + "wrapperColSpan": 0, + }, + }, + ], + "componentName": "Column", + "condition": true, + "id": "node_k1ow3cbx", + "props": Object { + "__style__": Object {}, + "colSpan": "", + "fieldId": "column_k1p1bnjm", + }, + }, + Object { + "children": Array [ + Object { + "componentName": "TextField", + "condition": true, + "id": "node_k1ow3cc2", + "props": Object { + "__category__": "form", + "__style__": Object {}, + "__useMediator": "value", + "addonAfter": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "addonBefore": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "autoFocus": false, + "autoHeight": false, + "behavior": "NORMAL", + "cutString": false, + "fieldId": "textField_k1ow3h1z", + "fieldName": "nickName", + "hasClear": false, + "hasLimitHint": false, + "htmlType": "input", + "label": Object { + "en_US": "TextField", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "花名", + }, + "labelAlign": "top", + "labelColOffset": 0, + "labelColSpan": 4, + "labelTextAlign": "right", + "labelTipsIcon": "", + "labelTipsText": Object { + "en_US": null, + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "labelTipsTypes": "none", + "placeholder": Object { + "en_US": "please input", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "请输入", + }, + "rows": 4, + "size": "medium", + "state": "", + "tips": Object { + "en_US": "", + "type": "i18n", + "zh_CN": "", + }, + "trim": false, + "validation": Array [], + "value": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "wrapperColOffset": 0, + "wrapperColSpan": 0, + }, + }, + Object { + "componentName": "SelectField", + "condition": true, + "id": "node_k1ow3cc0", + "props": Object { + "__category__": "form", + "__style__": Object {}, + "__useMediator": "value", + "autoWidth": true, + "behavior": "NORMAL", + "dataSource": Array [ + Object { + "__sid__": "serial_k1owc4t1", + "defaultChecked": false, + "sid": "opt_k1owc4t2", + "text": Object { + "__sid__": "param_k1owc4tb", + "en_US": "Option 1", + "type": "i18n", + "zh_CN": "男", + }, + "value": "M", + }, + Object { + "__sid__": "serial_k1owc4t2", + "defaultChecked": false, + "sid": "opt_k1owc4t3", + "text": Object { + "__sid__": "param_k1owc4tf", + "en_US": "Option 2", + "type": "i18n", + "zh_CN": "女", + }, + "value": "F", + }, + ], + "fieldId": "select_k1ow3h1x", + "fieldName": "gender", + "filterLocal": true, + "hasArrow": true, + "hasBorder": true, + "hasClear": false, + "hasSelectAll": false, + "label": Object { + "en_US": "SelectField", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "性别", + }, + "labelAlign": "top", + "labelColOffset": 0, + "labelColSpan": 4, + "labelTextAlign": "right", + "labelTipsIcon": "", + "labelTipsText": Object { + "en_US": null, + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "labelTipsTypes": "none", + "mode": "single", + "notFoundContent": Object { + "type": "i18n", + "use": "zh_CN", + }, + "placeholder": Object { + "en_US": "please select", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "请选择", + }, + "searchDelay": 300, + "showSearch": false, + "size": "medium", + "tips": Object { + "en_US": "", + "type": "i18n", + "zh_CN": "", + }, + "validation": Array [ + Object { + "type": "required", + }, + ], + "value": "", + "wrapperColOffset": 0, + "wrapperColSpan": 0, + }, + }, + ], + "componentName": "Column", + "condition": true, + "id": "node_k1ow3cby", + "props": Object { + "__style__": Object {}, + "colSpan": "", + "fieldId": "column_k1p1bnjn", + }, + }, + ], + "componentName": "ColumnsLayout", + "condition": true, + "id": "node_k1ow3cbw", + "props": Object { + "__style__": Object {}, + "columnGap": "20", + "fieldId": "columns_k1ow3h1v", + "layout": "6:6", + "rowGap": 0, + }, + }, + ], + "componentName": "CardContent", + "condition": true, + "id": "node_k1ow3cbk", + "props": Object {}, + }, + ], + "componentName": "Card", + "condition": true, + "id": "node_k1ow3cbj", + "props": Object { + "__slot__extra": false, + "__slot__subTitle": false, + "__slot__title": false, + "__style__": ":root { + margin-bottom: 12px; +}", + "className": "card_kgaqfbm5", + "contentHeight": "", + "dividerNoInset": false, + "extra": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "fieldId": "card_k1ow3h1l", + "showHeadDivider": true, + "showTitleBullet": true, + "subTitle": Object { + "en_US": "", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "title": Object { + "en_US": "Title", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "基本信息", + }, + }, + }, + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "componentName": "TextField", + "condition": true, + "id": "node_k1ow3cc4", + "props": Object { + "__category__": "form", + "__style__": Object {}, + "__useMediator": "value", + "addonAfter": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "addonBefore": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "autoFocus": false, + "autoHeight": false, + "behavior": "NORMAL", + "cutString": false, + "fieldId": "textField_k1ow3h21", + "fieldName": "department", + "hasClear": false, + "hasLimitHint": false, + "htmlType": "input", + "label": Object { + "en_US": "TextField", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "所属部门", + }, + "labelAlign": "top", + "labelColOffset": 0, + "labelColSpan": 4, + "labelTextAlign": "right", + "labelTipsIcon": "", + "labelTipsText": Object { + "en_US": null, + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "labelTipsTypes": "none", + "placeholder": Object { + "en_US": "please input", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "请输入", + }, + "rows": 4, + "size": "medium", + "state": "", + "tips": Object { + "en_US": "", + "type": "i18n", + "zh_CN": "", + }, + "trim": false, + "validation": Array [], + "value": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "wrapperColOffset": 0, + "wrapperColSpan": 0, + }, + }, + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "componentName": "TextField", + "condition": true, + "id": "node_k1ow3cc8", + "props": Object { + "__category__": "form", + "__style__": Object {}, + "__useMediator": "value", + "addonAfter": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "addonBefore": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "autoFocus": false, + "autoHeight": false, + "behavior": "NORMAL", + "cutString": false, + "fieldId": "textField_k1ow3h23", + "fieldName": "leader", + "hasClear": false, + "hasLimitHint": false, + "htmlType": "input", + "label": Object { + "en_US": "TextField", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "主管", + }, + "labelAlign": "top", + "labelColOffset": 0, + "labelColSpan": 4, + "labelTextAlign": "right", + "labelTipsIcon": "", + "labelTipsText": Object { + "en_US": null, + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "labelTipsTypes": "none", + "placeholder": Object { + "en_US": "please input", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "请输入", + }, + "rows": 4, + "size": "medium", + "state": "", + "tips": Object { + "en_US": "", + "type": "i18n", + "zh_CN": "", + }, + "trim": false, + "validation": Array [], + "value": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "wrapperColOffset": 0, + "wrapperColSpan": 0, + }, + }, + ], + "componentName": "Column", + "condition": true, + "id": "node_k1ow3cc6", + "props": Object { + "__style__": Object {}, + "colSpan": "", + "fieldId": "column_k1p1bnjo", + }, + }, + Object { + "children": Array [ + Object { + "componentName": "TextField", + "condition": true, + "id": "node_k1ow3cc9", + "props": Object { + "__category__": "form", + "__style__": Object {}, + "__useMediator": "value", + "addonAfter": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "addonBefore": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "autoFocus": false, + "autoHeight": false, + "behavior": "NORMAL", + "cutString": false, + "fieldId": "textField_k1ow3h24", + "fieldName": "hrg", + "hasClear": false, + "hasLimitHint": false, + "htmlType": "input", + "label": Object { + "en_US": "TextField", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "HRG", + }, + "labelAlign": "top", + "labelColOffset": 0, + "labelColSpan": 4, + "labelTextAlign": "right", + "labelTipsIcon": "", + "labelTipsText": Object { + "en_US": null, + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "labelTipsTypes": "none", + "placeholder": Object { + "en_US": "please input", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "请输入", + }, + "rows": 4, + "size": "medium", + "state": "", + "tips": Object { + "en_US": "", + "type": "i18n", + "zh_CN": "", + }, + "trim": false, + "validation": Array [], + "value": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "wrapperColOffset": 0, + "wrapperColSpan": 0, + }, + }, + ], + "componentName": "Column", + "condition": true, + "id": "node_k1ow3cc7", + "props": Object { + "__style__": Object {}, + "colSpan": "", + "fieldId": "column_k1p1bnjp", + }, + }, + ], + "componentName": "ColumnsLayout", + "condition": true, + "id": "node_k1ow3cc5", + "props": Object { + "__style__": Object {}, + "columnGap": "20", + "fieldId": "columns_k1ow3h22", + "layout": "6:6", + "rowGap": 0, + }, + }, + ], + "componentName": "CardContent", + "condition": true, + "id": "node_k1ow3cbm", + "props": Object {}, + }, + ], + "componentName": "Card", + "condition": true, + "id": "node_k1ow3cbl", + "props": Object { + "__slot__extra": false, + "__slot__subTitle": false, + "__slot__title": false, + "__style__": ":root { + margin-bottom: 12px; +}", + "className": "card_kgaqfbm6", + "contentHeight": "", + "dividerNoInset": false, + "extra": Object { + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "fieldId": "card_k1ow3h1m", + "showHeadDivider": true, + "showTitleBullet": true, + "subTitle": Object { + "en_US": "", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "", + }, + "title": Object { + "en_US": "Title", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "部门信息", + }, + }, + }, + Object { + "children": Array [ + Object { + "componentName": "Button", + "condition": true, + "id": "node_k1ow3cbn", + "props": Object { + "__style__": ":root { + margin-right: 16px; + width: 80px +}", + "baseIcon": "", + "behavior": "NORMAL", + "className": "button_kgaqfbm7", + "content": Object { + "en_US": "Button", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "提交", + }, + "fieldId": "button_k1ow3h1n", + "loading": false, + "onClick": Object { + "events": Array [ + Object { + "id": "submit", + "name": "submit", + "params": Object {}, + "type": "actionRef", + "uuid": "1570966253282_0", + }, + ], + "rawType": "events", + "type": "JSExpression", + "value": "this.utils.legaoBuiltin.execEventFlow.bind(this, [this.submit])", + }, + "otherIcon": "", + "size": "medium", + "triggerEventsWhenLoading": false, + "type": "primary", + }, + }, + Object { + "componentName": "Button", + "condition": true, + "id": "node_k1ow3cbp", + "props": Object { + "__style__": ":root { + width: 80px; +}", + "baseIcon": "", + "behavior": "NORMAL", + "className": "button_kgaqfbm8", + "content": Object { + "en_US": "Button", + "type": "i18n", + "use": "zh_CN", + "zh_CN": "取消", + }, + "fieldId": "button_k1ow3h1p", + "greeting": Object { + "value": Array [ + Object { + "componentName": "Text", + "props": Object {}, + }, + ], + }, + "loading": false, + "otherIcon": "", + "size": "medium", + "triggerEventsWhenLoading": false, + "type": "normal", + }, + }, + ], + "componentName": "Div", + "condition": true, + "id": "node_k1ow3cbo", + "props": Object { + "__style__": ":root { + display: flex; + align-items: flex-start; + justify-content: center; + background: #fff; + padding: 20px 0; +}", + "behavior": "NORMAL", + "className": "div_kgaqfbm9", + "customClassName": "", + "events": Object {}, + "fieldId": "div_k1ow3h1o", + "useFieldIdAsDomId": false, + }, + }, + ], + "componentName": "Form", + "condition": true, + "extraPropA": "extraPropA", + "id": "form", + "props": Object { + "__style__": Object {}, + "autoUnmount": true, + "autoValidate": true, + "behavior": "NORMAL", + "dataSource": Object { + "type": "variable", + "variable": "state.formData", + }, + "fieldId": "form", + "fieldOptions": Object {}, + "labelAlign": "top", + "obj": Object { + "a": 1, + "b": false, + "c": "string", + }, + "scrollToFirstError": true, + "size": "medium", + "slotA": "", + }, + }, + ], + "componentName": "RootContent", + "condition": true, + "id": "node_k1ow3cbb", + "props": Object { + "contentBgColor": "transparent", + "contentMargin": "20", + "contentPadding": "0", + }, + }, + Object { + "componentName": "RootFooter", + "condition": true, + "id": "node_k1ow3cbc", + "props": Object {}, + }, + ], + "componentName": "Page", + "condition": true, + "css": "body{background-color:#f2f3f5}.card_kgaqfbm5 { + margin-bottom: 12px; +}.card_kgaqfbm6 { + margin-bottom: 12px; +}.button_kgaqfbm7 { + margin-right: 16px; + width: 80px +}.button_kgaqfbm8 { + width: 80px; +}.div_kgaqfbm9 { + display: flex; + align-items: flex-start; + justify-content: center; + background: #fff; + padding: 20px 0; +}", + "dataSource": Object { + "globalConfig": Object { + "fit": Object { + "compiled": "", + "error": Object {}, + "source": "", + "type": "js", + }, + }, + "list": Array [], + "offline": Array [], + "online": Array [], + "sync": true, + }, + "id": "page", + "lifeCycles": Object { + "constructor": Object { + "compiled": "function constructor() { +var module = { exports: {} }; +var _this = this; +this.__initMethods__(module.exports, module); +Object.keys(module.exports).forEach(function(item) { + if(typeof module.exports[item] === 'function'){ + _this[item] = module.exports[item]; + } +}); + +}", + "source": "function constructor() { +var module = { exports: {} }; +var _this = this; +this.__initMethods__(module.exports, module); +Object.keys(module.exports).forEach(function(item) { + if(typeof module.exports[item] === 'function'){ + _this[item] = module.exports[item]; + } +}); + +}", + "type": "js", + }, + }, + "methods": Object { + "__initMethods__": Object { + "compiled": "function (exports, module) { /*set actions code here*/ }", + "source": "function (exports, module) { /*set actions code here*/ }", + "type": "js", + }, + }, + "props": Object { + "className": "page_kgaqfbm4", + "containerStyle": Object {}, + "extensions": Object { + "启用页头": true, + }, + "pageStyle": Object { + "backgroundColor": "#f2f3f5", + }, + "templateVersion": "1.0.0", + }, + "title": "hey, i' a page!", + }, + ], +} +`; + +exports[`document-model 测试 各种方法测试 2`] = `null`; diff --git a/packages/designer/tests/document/document-model/document-model.test.ts b/packages/designer/tests/document/document-model/document-model.test.ts index 94eda1871..1e0e68b99 100644 --- a/packages/designer/tests/document/document-model/document-model.test.ts +++ b/packages/designer/tests/document/document-model/document-model.test.ts @@ -1,16 +1,199 @@ import '../../fixtures/window'; -window.matchMedia('width=600px'); -import { DocumentModel } from '../../../src/document/document-model'; +import { DocumentModel, isDocumentModel, isPageSchema } from '../../../src/document/document-model'; +import { Editor } from '@ali/lowcode-editor-core'; +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 divMeta from '../../fixtures/component-metadata/div'; +import formMeta from '../../fixtures/component-metadata/form'; +import otherMeta from '../../fixtures/component-metadata/other'; +import pageMeta from '../../fixtures/component-metadata/page'; // const { DocumentModel } = require('../../../src/document/document-model'); // const { Node } = require('../__mocks__/node'); -describe.skip('basic utility', () => { - test('delegateMethod - useOriginMethodName', () => { +describe('document-model 测试', () => { + let editor: Editor; + let designer: Designer; + let project: Project; - const node = new DocumentModel({}, { - componentName: 'Component', + beforeEach(() => { + editor = new Editor(); + designer = new Designer({ editor }); + project = designer.project; + }); + + test('empty schema', () => { + const doc = new DocumentModel(project); + expect(doc.rootNode.id).toBe('root'); + expect(doc.currentRoot).toBe(doc.rootNode); + expect(doc.root).toBe(doc.rootNode); + expect(doc.modalNode).toBeUndefined; + expect(doc.isBlank()).toBeTruthy; + expect(doc.schema).toEqual({ + componentName: 'Page', + id: 'root', + fileName: '', + props: {}, }); - console.log(node); - expect(1).toBe(1); + }); + + test('各种方法测试', () => { + const doc = new DocumentModel(project, formSchema); + const mockNode = { id: 1 }; + doc.addWillPurge(mockNode); + expect(doc.willPurgeSpace).toHaveLength(1); + doc.removeWillPurge(mockNode); + expect(doc.willPurgeSpace).toHaveLength(0); + + expect(doc.toData()).toMatchSnapshot(); + + // 测试插入已存在的 id,id 将会被重置 + const formParentNode = doc.getNode('form').parent; + doc.insertNode(formParentNode, { id: 'form', componentName: 'Form' }); + expect(formParentNode.children.get(formParentNode.children.size - 1).id).not.toBe('form'); + + doc.internalRemoveAndPurgeNode({ id: 'mockId' }); + + // internalSetDropLocation + doc.internalSetDropLocation({ a: 1 }); + expect(doc.dropLocation).toEqual({ a: 1 }); + + // wrapWith + // none-selected + doc.wrapWith({ componentName: 'Wrap' }); + doc.selection.select('form'); + doc.wrapWith({ componentName: 'Wrap' }); + expect(doc.getNode('form').parent.componentName).toBe('Wrap'); + expect(doc.wrapWith({ componentName: 'Leaf' })).toBeNull; + + // fileName + expect(doc.fileName).toBeUndefined; + doc.fileName = 'fileName'; + expect(doc.fileName).toBe('fileName'); + + expect(doc.getNodeSchema(doc.getNode('form'))).toMatchSnapshot(); + + // TODO: + // expect(doc.simulatorProps).toMatchSnapshot(); + + const mockSimulator = { + isSimulator: true, + getComponent() { + return 'haha'; + }, + setSuspense() {}, + }; + doc.project.mountSimulator(mockSimulator); + expect(doc.simulator).toEqual(mockSimulator); + expect(doc.getComponent('Div')).toBe('haha'); + + expect(doc.opened).toBeFalsy(); + expect(doc.isModified).toBeTruthy(); + expect(doc.suspensed).toBeTruthy(); + + doc.open(); + expect(doc.opened).toBeTruthy(); + expect(doc.actived).toBeTruthy(); + expect(doc.isModified).toBeTruthy(); + expect(doc.suspensed).toBeFalsy(); + + doc.suspense(); + doc.active(); + doc.close(); + doc.remove(); + + const offReady = doc.onReady(() => {}); + offReady(); + + expect(doc.history).toBe(doc.getHistory()); + }); + + it('registerAddon / getAddonData / exportAddonData', () => { + const doc = new DocumentModel(project); + doc.registerAddon('a', () => 'addon a'); + doc.registerAddon('a', () => 'modified addon a'); + doc.registerAddon('b', () => 'addon b'); + doc.registerAddon('c', () => null); + + ['id', 'layout', 'params'].forEach((name) => { + expect(() => doc.registerAddon(name, () => {})).toThrow(); + }); + + expect(doc.getAddonData('a')).toBe('modified addon a'); + expect(doc.getAddonData('b')).toBe('addon b'); + + expect(doc.exportAddonData()).toEqual({ + a: 'modified addon a', + b: 'addon b', + }); + }); + + it('checkNesting / checkDropTarget / checkNestingUp / checkNestingDown', () => { + designer.createComponentMeta(pageMeta); + designer.createComponentMeta(formMeta); + const doc = new DocumentModel(project, formSchema); + + expect( + doc.checkDropTarget(doc.getNode('page'), { type: 'node', nodes: [doc.getNode('form')] }), + ).toBeTruthy(); + expect( + doc.checkDropTarget(doc.getNode('page'), { + type: 'nodedata', + data: { componentName: 'Form' }, + }), + ).toBeTruthy(); + + expect( + doc.checkNesting(doc.getNode('page'), { type: 'node', nodes: [doc.getNode('form')] }), + ).toBeTruthy(); + expect( + doc.checkNesting(doc.getNode('page'), { + type: 'nodedata', + data: { componentName: 'Form' }, + }), + ).toBeTruthy(); + + expect(doc.checkNestingUp(doc.getNode('page'), null)).toBeTruthy(); + }); + + it('getComponentsMap', () => { + designer.createComponentMeta(divMeta); + designer.createComponentMeta(otherMeta); + const doc = new DocumentModel(project, formSchema); + expect(doc.getComponentsMap(['Other'])).toEqual([ + { componentName: 'Div', package: '@ali/vc-div' }, + { componentName: 'Other', package: '@ali/vc-other' }, + ]); + }); + + it('acceptRootNodeVisitor / getRootNodeVisitor', () => { + designer.createComponentMeta(divMeta); + designer.createComponentMeta(otherMeta); + const doc = new DocumentModel(project, formSchema); + const ret = doc.acceptRootNodeVisitor('getPageId', function(root) { + return 'page'; + }); + expect(ret).toBe('page'); + expect(doc.getRootNodeVisitor('getPageId')).toBe('page'); + + // expect(doc.getComponentsMap(['Other'])).toEqual([ + // { componentName: 'Div', package: '@ali/vc-div' }, + // { componentName: 'Other', package: '@ali/vc-other' }, + // ]); + }); + + it('deprecated methods', () => { + const doc = new DocumentModel(project, formSchema); + doc.refresh(); + doc.onRefresh(); }); }); + +it('isDocumentModel', () => { + expect(isDocumentModel({ rootNode: {} })).toBeTruthy(); +}); + +it('isPageSchema', () => { + expect(isPageSchema({ componentName: 'Page' })).toBeTruthy(); +}); diff --git a/packages/designer/tests/document/document-model/node.test.ts b/packages/designer/tests/document/document-model/node.test.ts deleted file mode 100644 index 29ea34123..000000000 --- a/packages/designer/tests/document/document-model/node.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import '../../fixtures/window'; -import { DocumentModel } from '../../../src/document/document-model'; -import { Node } from '../../../src/document/node/node'; -// import { Node2 } from './__mocks__/node'; - -jest.mock('../../../src/document/document-model', () => { - return { - DocumentModel: jest.fn().mockImplementation(() => { - return { - project: { - designer: { createSettingEntry() {}, transformProps() {} }, - getSchema() {}, - }, - nextId() {}, - }; - }), - }; -}); - -describe.skip('basic utility', () => { - test('delegateMethod - useOriginMethodName', () => { - const dm = new DocumentModel({} as any, {} as any); - console.log(dm.nextId); - const node = new Node(dm, { componentName: 'Leaf' }); - console.log(node); - expect(1).toBe(1); - }); -}); diff --git a/packages/designer/tests/node/node.add.test.ts b/packages/designer/tests/document/node/node.add.test.ts similarity index 96% rename from packages/designer/tests/node/node.add.test.ts rename to packages/designer/tests/document/node/node.add.test.ts index 9da7a3473..dbf05c800 100644 --- a/packages/designer/tests/node/node.add.test.ts +++ b/packages/designer/tests/document/node/node.add.test.ts @@ -1,15 +1,15 @@ 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 '../../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', () => { +jest.mock('../../../src/designer/designer', () => { return { Designer: jest.fn().mockImplementation(() => { return { @@ -58,7 +58,7 @@ describe('schema 生成节点模型测试', () => { expect(nodesMap.get(id).componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName); }); - const pageNode = currentDocument?.getNode('node_k1ow3cb9'); + const pageNode = currentDocument?.getNode('page'); expect(pageNode?.getComponentName()).toBe('Page'); expect(pageNode?.getIcon()).toBeUndefined; @@ -72,7 +72,7 @@ describe('schema 生成节点模型测试', () => { const { currentDocument } = project; const getNode = currentDocument.getNode.bind(currentDocument); - const pageNode = getNode('node_k1ow3cb9'); + const pageNode = getNode('page'); const rootHeaderNode = getNode('node_k1ow3cba'); const rootContentNode = getNode('node_k1ow3cbb'); const rootFooterNode = getNode('node_k1ow3cbc'); @@ -113,7 +113,7 @@ describe('schema 生成节点模型测试', () => { const { currentDocument } = project; const getNode = currentDocument.getNode.bind(currentDocument); - const pageNode = getNode('node_k1ow3cb9'); + const pageNode = getNode('page'); const rootHeaderNode = getNode('node_k1ow3cba'); const rootContentNode = getNode('node_k1ow3cbb'); const rootFooterNode = getNode('node_k1ow3cbc'); @@ -159,9 +159,9 @@ describe('schema 生成节点模型测试', () => { const getNode = currentDocument.getNode.bind(currentDocument); const createNode = currentDocument.createNode.bind(currentDocument); - const pageNode = getNode('node_k1ow3cb9'); + const pageNode = getNode('page'); const nodeCreateHandler = jest.fn(); - currentDocument?.onNodeCreate(nodeCreateHandler); + const offCreate = currentDocument?.onNodeCreate(nodeCreateHandler); const node = createNode({ componentName: 'TextInput', @@ -177,12 +177,15 @@ describe('schema 生成节点模型测试', () => { expect(nodeCreateHandler.mock.calls[0][0].getPropValue('propA')).toBe('haha'); const nodeDestroyHandler = jest.fn(); - currentDocument?.onNodeDestroy(nodeDestroyHandler); + const offDestroy = 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'); + + offCreate(); + offDestroy(); }); it.skip('基本的节点模型初始化,节点插入等方法', () => { @@ -232,7 +235,7 @@ describe('schema 生成节点模型测试', () => { const { currentDocument } = project; const getNode = currentDocument.getNode.bind(currentDocument); - const pageNode = getNode('node_k1ow3cb9'); + const pageNode = getNode('page'); expect(pageNode?.isPage()).toBe(true); expect(pageNode?.isComponent()).toBe(false); expect(pageNode?.isSlot()).toBe(false); diff --git a/packages/designer/tests/node/node.dragdrop.test.ts b/packages/designer/tests/document/node/node.dragdrop.test.ts similarity index 79% rename from packages/designer/tests/node/node.dragdrop.test.ts rename to packages/designer/tests/document/node/node.dragdrop.test.ts index be15bdfa7..3adcc0d4c 100644 --- a/packages/designer/tests/node/node.dragdrop.test.ts +++ b/packages/designer/tests/document/node/node.dragdrop.test.ts @@ -1,14 +1,14 @@ 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 '../../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', () => { +jest.mock('../../../src/designer/designer', () => { return { Designer: jest.fn().mockImplementation(() => { return { diff --git a/packages/designer/tests/node/node.modify.test.ts b/packages/designer/tests/document/node/node.modify.test.ts similarity index 97% rename from packages/designer/tests/node/node.modify.test.ts rename to packages/designer/tests/document/node/node.modify.test.ts index e064d273f..1b4805e4e 100644 --- a/packages/designer/tests/node/node.modify.test.ts +++ b/packages/designer/tests/document/node/node.modify.test.ts @@ -1,14 +1,14 @@ 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 '../../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', () => { +jest.mock('../../../src/designer/designer', () => { return { Designer: jest.fn().mockImplementation(() => { return { diff --git a/packages/designer/tests/node/node.remove.test.ts b/packages/designer/tests/document/node/node.remove.test.ts similarity index 89% rename from packages/designer/tests/node/node.remove.test.ts rename to packages/designer/tests/document/node/node.remove.test.ts index f68d57ca1..78805fc17 100644 --- a/packages/designer/tests/node/node.remove.test.ts +++ b/packages/designer/tests/document/node/node.remove.test.ts @@ -1,14 +1,14 @@ 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 '../../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', () => { +jest.mock('../../../src/designer/designer', () => { return { Designer: jest.fn().mockImplementation(() => { return { diff --git a/packages/designer/tests/document/node/node.test.ts b/packages/designer/tests/document/node/node.test.ts new file mode 100644 index 000000000..89fc00e73 --- /dev/null +++ b/packages/designer/tests/document/node/node.test.ts @@ -0,0 +1,206 @@ +import '../../fixtures/window'; +import { set } from '../../utils'; +import { Editor } from '@ali/lowcode-editor-core'; +import { Project } from '../../../src/project/project'; +import { DocumentModel } from '../../../src/document/document-model'; +import { + isRootNode, + Node, + isNode, + comparePosition, + contains, + insertChild, + insertChildren, +} from '../../../src/document/node/node'; +import { Designer } from '../../../src/designer/designer'; +import formSchema from '../../fixtures/schema/form'; +import divMetadata from '../../fixtures/component-metadata/div'; +import formMetadata from '../../fixtures/component-metadata/form'; +import otherMeta from '../../fixtures/component-metadata/other'; +import pageMetadata from '../../fixtures/component-metadata/page'; +import rootHeaderMetadata from '../../fixtures/component-metadata/root-header'; +import rootContentMetadata from '../../fixtures/component-metadata/root-content'; +import rootFooterMetadata from '../../fixtures/component-metadata/root-footer'; + +describe('Node 方法测试', () => { + let editor: Editor; + let designer: Designer; + let project: Project; + let doc: DocumentModel; + + beforeEach(() => { + editor = new Editor(); + designer = new Designer({ editor }); + project = designer.project; + doc = new DocumentModel(project, formSchema); + }); + + afterEach(() => { + project.unload(); + designer.purge(); + editor = null; + designer = null; + project = null; + }); + + it('condition / loop', () => {}); + + describe('getSuitablePlace', () => { + it('root,子节点中有容器节点', () => { + designer.createComponentMeta(pageMetadata); + designer.createComponentMeta(rootHeaderMetadata); + designer.createComponentMeta(rootContentMetadata); + designer.createComponentMeta(rootFooterMetadata); + + const rootHeaderMeta = designer.getComponentMeta('RootHeader'); + set(rootHeaderMeta, 'prototype.options.canDropIn', true); + + let o = doc.rootNode?.getSuitablePlace(doc.getNode('form'), 1); + expect(o).toEqual({ + container: doc.getNode('node_k1ow3cba'), + ref: 1, + }); + + set(rootHeaderMeta, 'prototype.options.canDropIn', () => true); + o = doc.rootNode?.getSuitablePlace(doc.getNode('form'), 1); + expect(o).toEqual({ + container: doc.getNode('node_k1ow3cba'), + ref: 1, + }); + }); + + it('root,直接子节点中无容器节点,自身支持放入子节点', () => { + designer.createComponentMeta(pageMetadata); + + let o = doc.rootNode?.getSuitablePlace(doc.getNode('form'), 1); + + const pageMeta = designer.getComponentMeta('Page'); + set(pageMeta, 'prototype.options.canDropIn', () => true); + + expect(o).toEqual({ + container: doc.rootNode, + ref: 1, + }); + + set(pageMeta, 'prototype.options.canDropIn', undefined); + o = doc.rootNode?.getSuitablePlace(doc.getNode('form'), 1); + expect(o).toEqual({ + container: doc.rootNode, + ref: 1, + }); + + set(pageMeta, 'prototype.options.canDropIn', true); + o = doc.rootNode?.getSuitablePlace(doc.getNode('form'), 1); + expect(o).toEqual({ + container: doc.rootNode, + ref: 1, + }); + }); + + it('root,子节点中无容器节点,自己也不支持放入子节点', () => { + designer.createComponentMeta(pageMetadata); + + let pageMeta = designer.getComponentMeta('Page'); + + pageMeta = set(pageMeta, 'prototype.options.canDropIn', () => false); + let o = doc.rootNode?.getSuitablePlace(doc.getNode('form'), 1); + expect(o).toBeNull(); + + set(pageMeta, 'prototype.options.canDropIn', false); + o = doc.rootNode?.getSuitablePlace(doc.getNode('form'), 1); + expect(o).toBeNull(); + }); + + it('非 root 节点,不能放入子节点', () => { + designer.createComponentMeta(formMetadata); + designer.createComponentMeta(pageMetadata); + + // form 子节点以及自身都不能放入子节点 + const formMeta = designer.getComponentMeta('Form'); + set(formMeta, 'prototype.options.canDropIn', false); + + const pageMeta = designer.getComponentMeta('Page'); + set(pageMeta, 'prototype.options.canDropIn', () => true); + + const o = doc.getNode('form')!.getSuitablePlace(doc.getNode('node_k1ow3cbj'), 1); + expect(o).toEqual({ + container: doc.rootNode, + ref: 1, + }); + }); + + it('非 root 节点,能放入子节点', () => { + designer.createComponentMeta(formMetadata); + designer.createComponentMeta(pageMetadata); + + // form 子节点以及自身都不能放入子节点 + const formMeta = designer.getComponentMeta('Form'); + set(formMeta, 'prototype.options.canDropIn', true); + + const o = doc.getNode('form')!.getSuitablePlace(doc.getNode('node_k1ow3cbj'), 1); + expect(o).toEqual({ + container: doc.getNode('form'), + ref: 1, + }); + }); + + it('null', () => { + expect( + doc.rootNode?.getSuitablePlace.call({ isContainer: () => false, isRoot: () => false }), + ).toBeNull(); + }); + }); + + it('removeChild / replaceWith / replaceChild / insert / insertBefore / insertAfter / onChildrenChange / mergeChildren', () => {}); + + it('setVisible / getVisible / onVisibleChange', () => {}); + + it('setProps', () => {}); + + it('isValidComponent', () => { + designer.createComponentMeta(divMetadata); + expect(doc.getNode('node_k1ow3cbo')?.isValidComponent()).toBeTruthy(); + expect(doc.getNode('form')?.isValidComponent()).toBeFalsy(); + }); + + it('isEmpty / getIndex', () => { + const firstBtn = doc.getNode('node_k1ow3cbn')!; + expect(firstBtn.isEmpty()).toBeTruthy(); + expect(firstBtn.index).toBe(0); + expect(firstBtn.getIndex()).toBe(0); + }); + + it('schema / toData / export', () => {}); + + it('prevSibling / nextSibling', () => { + const firstBtn = doc.getNode('node_k1ow3cbn'); + const secondBtn = doc.getNode('node_k1ow3cbp'); + expect(firstBtn?.nextSibling).toBe(secondBtn); + expect(secondBtn?.prevSibling).toBe(firstBtn); + expect(secondBtn?.nextSibling).toBeNull(); + }); + + it('toString', () => { + expect(doc.rootNode.toString()).toBe('page'); + }); + + it('isRootNode / isRoot / isNode', () => { + expect(isRootNode(doc.rootNode)).toBeTruthy(); + expect(isNode(doc.rootNode)).toBeTruthy(); + }); + + it('contains / comparePosition', () => {}); + + it('getZLevelTop', () => {}); + + describe.skip('deprecated methods', () => { + it('setStatus / getStatus', () => {}); + + it('getPage', () => { + expect(doc.rootNode?.getPage()).toBe(doc); + }); + it('getDOMNode', () => {}); + it('registerAddon / getAddonData', () => {}); + it('getPrototype / setPrototype', () => {}); + }); +}); diff --git a/packages/designer/tests/document/selection.test.ts b/packages/designer/tests/document/selection.test.ts index 4d81e935e..72fa2942e 100644 --- a/packages/designer/tests/document/selection.test.ts +++ b/packages/designer/tests/document/selection.test.ts @@ -184,7 +184,7 @@ describe('选择区测试', () => { 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.containsNode(currentDocument?.getNode('page'))).toBe(false); expect(selection.getNodes()).toEqual([currentDocument?.getNode('form')]); selectionChangeHandler.mockClear(); @@ -207,11 +207,11 @@ describe('选择区测试', () => { const selectionChangeHandler = jest.fn(); selection.onSelectionChange(selectionChangeHandler); - selection.select('node_k1ow3cb9'); + selection.select('page'); 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(selectionChangeHandler.mock.calls[0][0]).toEqual(['page']); + expect(selection.selected).toEqual(['page']); + expect(selection.has('page')).toBe(true); expect(selection.containsNode(currentDocument?.getNode('form'))).toBe(true); expect(selection.containsNode(currentDocument?.getNode('form'), true)).toBe(false); selectionChangeHandler.mockClear(); @@ -237,9 +237,9 @@ describe('选择区测试', () => { // dispose 后,selected 会被赋值,但是变更事件不会被触发 dispose(); - selection.select('node_k1ow3cb9'); + selection.select('page'); expect(selectionChangeHandler).toHaveBeenCalledTimes(0); - expect(selection.selected).toEqual(['node_k1ow3cb9']); + expect(selection.selected).toEqual(['page']); selectionChangeHandler.mockClear(); }); }); \ No newline at end of file diff --git a/packages/designer/tests/fixtures/component-metadata/div.ts b/packages/designer/tests/fixtures/component-metadata/div.ts index 395cb58bb..ae1738754 100644 --- a/packages/designer/tests/fixtures/component-metadata/div.ts +++ b/packages/designer/tests/fixtures/component-metadata/div.ts @@ -1,5 +1,9 @@ export default { componentName: 'Div', + npm: { + package: '@ali/vc-div', + componentName: 'Div', + }, title: '容器', docUrl: 'http://gitlab.alibaba-inc.com/vision-components/vc-block/blob/master/README.md', devMode: 'procode', diff --git a/packages/designer/tests/fixtures/component-metadata/form.ts b/packages/designer/tests/fixtures/component-metadata/form.ts new file mode 100644 index 000000000..6b98fda32 --- /dev/null +++ b/packages/designer/tests/fixtures/component-metadata/form.ts @@ -0,0 +1,278 @@ +export default { + componentName: 'Form', + npm: { + package: '@ali/vc-form', + }, + 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: { + parentWhitelist: 'Div,Page', + // childWhitelist: 'Div', + }, + }, + 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: [], + }, +}; diff --git a/packages/designer/tests/fixtures/prototype/div-meta.ts b/packages/designer/tests/fixtures/component-metadata/other.ts similarity index 94% rename from packages/designer/tests/fixtures/prototype/div-meta.ts rename to packages/designer/tests/fixtures/component-metadata/other.ts index a2b410494..ea6908353 100644 --- a/packages/designer/tests/fixtures/prototype/div-meta.ts +++ b/packages/designer/tests/fixtures/component-metadata/other.ts @@ -1,5 +1,8 @@ export default { - componentName: 'Div', + componentName: 'Other', + npm: { + package: '@ali/vc-other', + }, title: '容器', docUrl: 'http://gitlab.alibaba-inc.com/vision-components/vc-block/blob/master/README.md', devMode: 'procode', @@ -65,7 +68,7 @@ export default { }, { type: 'group', - name: 'groupkh97h5kc', + name: 'groupkgzzeo41', title: '高级', extraProps: { display: 'accordion', @@ -218,7 +221,10 @@ export default { ], component: { isContainer: true, - nestingRule: {}, + nestingRule: { + parentWhitelist: 'Div', + childWhitelist: 'Div', + }, }, supports: {}, }, @@ -253,7 +259,20 @@ export default { name: 'onMouseLeave', }, ], - filters: [], + filters: [ + { + name: 'events', + }, + { + name: 'onClick', + }, + { + name: 'onMouseEnter', + }, + { + name: 'onMouseLeave', + }, + ], autoruns: [], }, }; diff --git a/packages/designer/tests/fixtures/component-metadata/page.ts b/packages/designer/tests/fixtures/component-metadata/page.ts new file mode 100644 index 000000000..133a00ea1 --- /dev/null +++ b/packages/designer/tests/fixtures/component-metadata/page.ts @@ -0,0 +1,278 @@ +export default { + componentName: 'Page', + npm: { + package: '@ali/vc-page', + }, + 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: { + // parentWhitelist: 'Div', + // childWhitelist: 'Div', + }, + }, + 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: [], + }, +}; diff --git a/packages/designer/tests/fixtures/component-metadata/root-content.ts b/packages/designer/tests/fixtures/component-metadata/root-content.ts new file mode 100644 index 000000000..205528944 --- /dev/null +++ b/packages/designer/tests/fixtures/component-metadata/root-content.ts @@ -0,0 +1,278 @@ +export default { + componentName: 'RootContent', + npm: { + package: '@ali/vc-page', + }, + 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: { + // parentWhitelist: 'Div', + // childWhitelist: 'Div', + }, + }, + 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: [], + }, +}; diff --git a/packages/designer/tests/fixtures/component-metadata/root-footer.ts b/packages/designer/tests/fixtures/component-metadata/root-footer.ts new file mode 100644 index 000000000..8d3127270 --- /dev/null +++ b/packages/designer/tests/fixtures/component-metadata/root-footer.ts @@ -0,0 +1,278 @@ +export default { + componentName: 'RootFooter', + npm: { + package: '@ali/vc-page', + }, + 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: { + // parentWhitelist: 'Div', + // childWhitelist: 'Div', + }, + }, + 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: [], + }, +}; diff --git a/packages/designer/tests/fixtures/component-metadata/root-header.ts b/packages/designer/tests/fixtures/component-metadata/root-header.ts new file mode 100644 index 000000000..2b4a0cbc5 --- /dev/null +++ b/packages/designer/tests/fixtures/component-metadata/root-header.ts @@ -0,0 +1,278 @@ +export default { + componentName: 'RootHeader', + npm: { + package: '@ali/vc-page', + }, + 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: { + // parentWhitelist: 'Div', + // childWhitelist: 'Div', + }, + }, + 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: [], + }, +}; diff --git a/packages/designer/tests/fixtures/schema/form.ts b/packages/designer/tests/fixtures/schema/form.ts index 903b21756..12cf7cbb1 100644 --- a/packages/designer/tests/fixtures/schema/form.ts +++ b/packages/designer/tests/fixtures/schema/form.ts @@ -1,6 +1,6 @@ export default { componentName: 'Page', - id: 'node_k1ow3cb9', + id: 'page', title: 'hey, i\' a page!', props: { extensions: { diff --git a/packages/designer/tests/fixtures/schema/setting.ts b/packages/designer/tests/fixtures/schema/setting.ts index a0d45d0d9..58db3921c 100644 --- a/packages/designer/tests/fixtures/schema/setting.ts +++ b/packages/designer/tests/fixtures/schema/setting.ts @@ -1,6 +1,6 @@ export default { componentName: 'Page', - id: 'node_k1ow3cb9', + id: 'page', title: 'hey, i\' a page!', props: { extensions: { diff --git a/packages/designer/tests/meta/component-meta.test.ts b/packages/designer/tests/main/meta/component-meta.test.ts similarity index 86% rename from packages/designer/tests/meta/component-meta.test.ts rename to packages/designer/tests/main/meta/component-meta.test.ts index f3cdfd2a6..0bcb7b08a 100644 --- a/packages/designer/tests/meta/component-meta.test.ts +++ b/packages/designer/tests/main/meta/component-meta.test.ts @@ -1,13 +1,13 @@ 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, isComponentMeta, removeBuiltinComponentAction, addBuiltinComponentAction } from '../../src/component-meta'; +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, isComponentMeta, removeBuiltinComponentAction, addBuiltinComponentAction } from '../../../src/component-meta'; const mockCreateSettingEntry = jest.fn(); -jest.mock('../../src/designer/designer', () => { +jest.mock('../../../src/designer/designer', () => { return { Designer: jest.fn().mockImplementation(() => { return { diff --git a/packages/designer/tests/main/simulator.test.ts b/packages/designer/tests/main/simulator.test.ts new file mode 100644 index 000000000..13ab97301 --- /dev/null +++ b/packages/designer/tests/main/simulator.test.ts @@ -0,0 +1,7 @@ +import '../fixtures/window'; +import { isSimulatorHost } from '../../src/simulator'; + +it('isSimulatorHost', () => { + expect(isSimulatorHost({ isSimulator: true })).toBeTruthy(); + expect(isSimulatorHost({ a: 1 })).toBeFalsy(); +}); diff --git a/packages/designer/tests/project/project.test.ts b/packages/designer/tests/project/project.test.ts index 31ece4526..35664999c 100644 --- a/packages/designer/tests/project/project.test.ts +++ b/packages/designer/tests/project/project.test.ts @@ -1,5 +1,5 @@ import set from 'lodash/set'; -import cloneDeep from 'lodash/clonedeep'; +import cloneDeep from 'lodash/cloneDeep'; import '../fixtures/window'; import { Project } from '../../src/project/project'; import { Node } from '../../src/document/node/node'; diff --git a/packages/designer/tests/utils/index.ts b/packages/designer/tests/utils/index.ts index 74eb13265..69d9a2359 100644 --- a/packages/designer/tests/utils/index.ts +++ b/packages/designer/tests/utils/index.ts @@ -1,4 +1,5 @@ export { getIdsFromSchema, getNodeFromSchemaById } from '@ali/lowcode-test-mate/es/utils'; -export { getMockDocument, getMockWindow } from './bom'; -export { getMockEvent } from './event'; -export { getMockRenderer } from './renderer'; \ No newline at end of file +export * from './bom'; +export * from './event'; +export * from './renderer'; +export * from './misc'; \ No newline at end of file diff --git a/packages/designer/tests/utils/misc.ts b/packages/designer/tests/utils/misc.ts new file mode 100644 index 000000000..f640416a8 --- /dev/null +++ b/packages/designer/tests/utils/misc.ts @@ -0,0 +1,17 @@ +import lodashSet from 'lodash/set'; + +export function set(obj: any, path: any, val: any) { + if (typeof path === 'string' && path.startsWith('prototype')) { + const segs = path.split('.'); + let acc = obj; + segs.forEach((seg, idx) => { + if (idx !== segs.length - 1) { + acc[seg] = acc[seg] || {}; + acc = acc[seg]; + } else { + acc[seg] = val; + } + }) + } + return lodashSet(obj, path, val); +} \ No newline at end of file