fix: renderer not rendering correct components when loading components with loadAsyncLibrary api

This commit is contained in:
liujuping 2022-04-15 22:32:17 +08:00 committed by LeoYuan 袁力皓
parent d5daba8aaf
commit 9b3b4f9b0e
10 changed files with 289 additions and 2 deletions

View File

@ -0,0 +1,6 @@
{
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose": true }]
]
}

View File

@ -0,0 +1,6 @@
{
"plugins": [
"build-plugin-component",
"@alilc/lowcode-test-mate/plugin/index.ts"
]
}

View File

@ -0,0 +1,33 @@
const fs = require('fs');
const { join } = require('path');
const esModules = ['zen-logger'].join('|');
const pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.'));
const jestConfig = {
// transform: {
// '^.+\\.[jt]sx?$': 'babel-jest',
// // '^.+\\.(ts|tsx)$': 'ts-jest',
// // '^.+\\.(js|jsx)$': 'babel-jest',
// },
// testMatch: ['**/document/node/node.test.ts'],
// testMatch: ['**/designer/builtin-hotkey.test.ts'],
// testMatch: ['**/plugin/plugin-manager.test.ts'],
// testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
transformIgnorePatterns: [
`/node_modules/(?!${esModules})/`,
],
setupFiles: ['./test/utils/host.ts'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
collectCoverage: false,
collectCoverageFrom: [
'src/**/*.ts',
'!src/**/*.d.ts',
'!**/node_modules/**',
],
};
// 只对本仓库内的 pkg 做 mapping
jestConfig.moduleNameMapper = {};
jestConfig.moduleNameMapper[`^@alilc/lowcode\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src';
module.exports = jestConfig;

View File

@ -11,6 +11,7 @@
"dist"
],
"scripts": {
"test": "build-scripts test --config build.test.json",
"build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --skip-demo",
"build:umd": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --config build.umd.json"
},

View File

@ -0,0 +1,81 @@
export default {
id: 'node_ockvuu8u911',
css: 'body{background-color:#f2f3f5}',
flows: [],
props: {
className: 'page_kvuu9hym',
pageStyle: {
backgroundColor: '#f2f3f5',
},
containerStyle: {},
templateVersion: '1.0.0',
},
state: {},
title: '',
methods: {
__initMethods__: {
type: 'JSExpression',
value: "function (exports, module) { \"use strict\";\n\nexports.__esModule = true;\nexports.func1 = func1;\nexports.helloPage = helloPage;\n\nfunction func1() {\n console.info('hello, this is a page function');\n}\n\nfunction helloPage() {\n // 你可以这么调用其他函数\n this.func1(); // 你可以这么调用组件的函数\n // this.$('textField_xxx').getValue();\n // 你可以这么使用「数据源面板」定义的「变量」\n // this.state.xxx\n // 你可以这么发送一个在「数据源面板」定义的「远程 API」\n // this.dataSourceMap['xxx'].load(data)\n // API 详见https://go.alibaba-inc.com/help3/API\n} \n}",
},
},
children: [
{
id: 'node_ockvuu8u915',
props: {
fieldId: 'div_kvuu9gl1',
behavior: 'NORMAL',
__style__: {},
customClassName: '',
useFieldIdAsDomId: false,
},
title: '',
children: [
{
id: 'node_ockvuu8u916',
props: {
content: {
use: 'zh_CN',
type: 'JSExpression',
en_US: 'Tips content',
value: '"我是一个简单的测试页面"',
zh_CN: '我是一个简单的测试页面',
extType: 'i18n',
},
fieldId: 'text_kvuu9gl2',
maxLine: 0,
behavior: 'NORMAL',
__style__: {},
showTitle: false,
},
title: '',
condition: true,
componentName: 'Text',
},
],
condition: true,
componentName: 'Div',
},
],
condition: true,
dataSource: {
list: [],
sync: true,
online: [],
offline: [],
globalConfig: {
fit: {
type: 'JSExpression',
value: "function main(){\n 'use strict';\n\nvar __compiledFunc__ = function fit(response) {\n var content = response.content !== undefined ? response.content : response;\n var error = {\n message: response.errorMsg || response.errors && response.errors[0] && response.errors[0].msg || response.content || '远程数据源请求出错success is false'\n };\n var success = true;\n if (response.success !== undefined) {\n success = response.success;\n } else if (response.hasError !== undefined) {\n success = !response.hasError;\n }\n return {\n content: content,\n success: success,\n error: error\n };\n};\n return __compiledFunc__.apply(this, arguments);\n}",
extType: 'function',
},
},
},
lifeCycles: {
constructor: {
type: 'JSExpression',
value: "function constructor() {\nvar module = { exports: {} };\nvar _this = this;\nthis.__initMethods__(module.exports, module);\nObject.keys(module.exports).forEach(function(item) {\n if(typeof module.exports[item] === 'function'){\n _this[item] = module.exports[item];\n }\n});\n\n}",
extType: 'function',
},
},
componentName: 'Page',
};

View File

@ -0,0 +1,41 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Base should be render NotFoundComponent 1`] = `
<div
className="lce-page page_kvuu9hym"
style={Object {}}
>
<div
componentName="Div"
>
<div
componentName="Text"
>
Component Not Found
</div>
</div>
</div>
`;
exports[`Base should be render Text 1`] = `
<div
className="lce-page page_kvuu9hym"
style={Object {}}
>
<div
componentName="Div"
>
<div
__designMode="design"
__style__={Object {}}
behavior="NORMAL"
componentId="node_ockvuu8u916"
fieldId="text_kvuu9gl2"
maxLine={0}
showTitle={false}
>
我是一个简单的测试页面
</div>
</div>
</div>
`;

View File

@ -0,0 +1,31 @@
import renderer from 'react-test-renderer';
import rendererContainer from '../../../src/renderer';
import SimulatorRendererView from '../../../src/renderer-view';
import { Text } from '../../utils/components';
describe('Base', () => {
const component = renderer.create(
<SimulatorRendererView
rendererContainer={rendererContainer}
/>
);
it('should be render NotFoundComponent', () => {
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
it('should be render Text', () => {
// 更新 _componentsMap 值
(rendererContainer as any)._componentsMap.Text = Text;// = host.designer.componentsMap;
// 更新 components 列表
(rendererContainer as any).buildComponents();
expect(!!(rendererContainer.components as any).Text).toBeTruthy();
rendererContainer.rerender();
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
})

View File

@ -0,0 +1,7 @@
export const Text = ({
__tag,
content,
...props
}: any) => (<div {...props}>{content}</div>);
export const Page = (props: any) => (<div>{props.children}</div>);

View File

@ -0,0 +1,75 @@
import { Box, Breadcrumb, Form, Select, Input, Button, Table, Pagination, Dialog } from '@alifd/next';
import defaultSchema from '../schema/basic';
import { Page } from './components';
class Designer {
componentsMap = {
Box,
Breadcrumb,
'Breadcrumb.Item': Breadcrumb.Item,
Form,
'Form.Item': Form.Item,
Select,
Input,
Button,
'Button.Group': Button.Group,
Table,
Pagination,
Dialog,
Page,
}
}
class Host {
designer = new Designer();
connect = () => {}
autorun = (fn: Function) => {
fn();
}
autoRender = true;
componentsConsumer = {
consume() {}
}
schema = defaultSchema;
project = {
documents: [
{
id: '1',
path: '/',
fileName: '',
export: () => {
return this.schema;
},
getNode: () => {},
}
],
get: () => ({}),
}
setInstance() {}
designMode = 'design'
get() {}
injectionConsumer = {
consume() {}
}
/** 下列的函数或者方法是方便测试用 */
mockSchema = (schema: any) => {
this.schema = schema;
};
}
if (!(window as any).LCSimulatorHost) {
(window as any).LCSimulatorHost = new Host();
}
export default (window as any).LCSimulatorHost;

View File

@ -463,8 +463,14 @@ export default function baseRendererFactory(): IBaseRenderComponent {
if (!Comp) {
console.error(`${schema.componentName} component is not found in components list! component list is:`, components || this.props.__container?.components);
Comp = engine.getNotFoundComponent();
otherProps.__componentName = schema.componentName;
return engine.createElement(
engine.getNotFoundComponent(),
{
componentName: schema.componentName,
componentId: schema.id,
},
this.__getSchemaChildrenVirtualDom(schema, scope, Comp),
);
}
// DesignMode 为 design 情况下,需要进入 leaf Hoc进行相关事件注册