mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-19 14:04:28 +00:00
Merge branch feat/jsFunctionScope into develop
Title: feat: JSFunction 表达式支持 scope 值 Link: https://code.aone.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/codereview/8088102
This commit is contained in:
commit
b5ed75a22d
@ -199,6 +199,8 @@ exports[`React Renderer render basic case 1`] = `
|
|||||||
maxLength={null}
|
maxLength={null}
|
||||||
onBlur={[Function]}
|
onBlur={[Function]}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
|
onCompositionEnd={[Function]}
|
||||||
|
onCompositionStart={[Function]}
|
||||||
onFocus={[Function]}
|
onFocus={[Function]}
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
@ -296,6 +298,8 @@ exports[`React Renderer render basic case 1`] = `
|
|||||||
maxLength={null}
|
maxLength={null}
|
||||||
onBlur={[Function]}
|
onBlur={[Function]}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
|
onCompositionEnd={[Function]}
|
||||||
|
onCompositionStart={[Function]}
|
||||||
onFocus={[Function]}
|
onFocus={[Function]}
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
@ -378,6 +382,8 @@ exports[`React Renderer render basic case 1`] = `
|
|||||||
maxLength={null}
|
maxLength={null}
|
||||||
onBlur={[Function]}
|
onBlur={[Function]}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
|
onCompositionEnd={[Function]}
|
||||||
|
onCompositionStart={[Function]}
|
||||||
onFocus={[Function]}
|
onFocus={[Function]}
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
readOnly={false}
|
readOnly={false}
|
||||||
@ -826,6 +832,8 @@ exports[`React Renderer render basic case 1`] = `
|
|||||||
maxLength={null}
|
maxLength={null}
|
||||||
onBlur={[Function]}
|
onBlur={[Function]}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
|
onCompositionEnd={[Function]}
|
||||||
|
onCompositionStart={[Function]}
|
||||||
onFocus={[Function]}
|
onFocus={[Function]}
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
readOnly={false}
|
readOnly={false}
|
||||||
|
|||||||
6
packages/renderer-core/build.test.json
Normal file
6
packages/renderer-core/build.test.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
"build-plugin-component",
|
||||||
|
"@ali/lowcode-test-mate/plugin/index.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
20
packages/renderer-core/jest.config.js
Normal file
20
packages/renderer-core/jest.config.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
const esModules = ['@recore/obx-react'].join('|');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// transform: {
|
||||||
|
// '^.+\\.[jt]sx?$': 'babel-jest',
|
||||||
|
// // '^.+\\.(ts|tsx)$': 'ts-jest',
|
||||||
|
// // '^.+\\.(js|jsx)$': 'babel-jest',
|
||||||
|
// },
|
||||||
|
// testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
|
||||||
|
transformIgnorePatterns: [
|
||||||
|
`/node_modules/(?!${esModules})/`,
|
||||||
|
],
|
||||||
|
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
|
||||||
|
collectCoverage: true,
|
||||||
|
collectCoverageFrom: [
|
||||||
|
'src/**/*.{ts,tsx}',
|
||||||
|
'!**/node_modules/**',
|
||||||
|
'!**/vendor/**',
|
||||||
|
],
|
||||||
|
};
|
||||||
@ -10,8 +10,13 @@
|
|||||||
"es"
|
"es"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"test": "build-scripts test --config build.test.json",
|
||||||
"build": "build-scripts build --skip-demo"
|
"build": "build-scripts build --skip-demo"
|
||||||
},
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git@gitlab.alibaba-inc.com:ali-lowcode/ali-lowcode-engine.git"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ali/b3-one": "^0.0.17",
|
"@ali/b3-one": "^0.0.17",
|
||||||
"@ali/bzb-request": "^2.6.0-beta.13",
|
"@ali/bzb-request": "^2.6.0-beta.13",
|
||||||
|
|||||||
@ -32,7 +32,7 @@ import { compWrapper } from '../hoc';
|
|||||||
import { IComponentConstruct, IComponentHoc, leafWrapper } from '../hoc/leaf';
|
import { IComponentConstruct, IComponentHoc, leafWrapper } from '../hoc/leaf';
|
||||||
import logger from '../utils/logger';
|
import logger from '../utils/logger';
|
||||||
|
|
||||||
export default function baseRenererFactory() {
|
export default function baseRendererFactory() {
|
||||||
const { BaseRenderer: customBaseRenderer } = adapter.getRenderers();
|
const { BaseRenderer: customBaseRenderer } = adapter.getRenderers();
|
||||||
|
|
||||||
if (customBaseRenderer) {
|
if (customBaseRenderer) {
|
||||||
@ -712,7 +712,7 @@ export default function baseRenererFactory() {
|
|||||||
) {
|
) {
|
||||||
return checkProps(props);
|
return checkProps(props);
|
||||||
}
|
}
|
||||||
if (isJSExpression(props)) {
|
if (isJSExpression(props) || isJSFunction(props)) {
|
||||||
props = parseExpression(props, scope);
|
props = parseExpression(props, scope);
|
||||||
// 只有当变量解析出来为模型结构的时候才会继续解析
|
// 只有当变量解析出来为模型结构的时候才会继续解析
|
||||||
if (!isSchema(props) && !isJSSlot(props)) return checkProps(props);
|
if (!isSchema(props) && !isJSSlot(props)) return checkProps(props);
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import { BuiltinSimulatorHost } from '@ali/lowcode-designer';
|
import { BuiltinSimulatorHost } from '@ali/lowcode-designer';
|
||||||
import { baseRendererFactory } from '../renderer';
|
import { baseRendererFactory } from '../renderer';
|
||||||
import baseRenererFactory from '../renderer/base';
|
|
||||||
|
|
||||||
export type IBaseRenderer = ReturnType<typeof baseRenererFactory>;
|
export type IBaseRenderer = ReturnType<typeof baseRendererFactory>;
|
||||||
export type IBaseRendererInstance = InstanceType<ReturnType<typeof baseRendererFactory>>;
|
export type IBaseRendererInstance = InstanceType<ReturnType<typeof baseRendererFactory>>;
|
||||||
|
|
||||||
export interface IProps {
|
export interface IProps {
|
||||||
@ -28,7 +27,7 @@ export interface IProps {
|
|||||||
|
|
||||||
export interface IState {
|
export interface IState {
|
||||||
engineRenderError?: boolean;
|
engineRenderError?: boolean;
|
||||||
error?: Error
|
error?: Error;
|
||||||
onCompGetRef: (schema: ISchema, ref: any) => void;
|
onCompGetRef: (schema: ISchema, ref: any) => void;
|
||||||
onCompGetCtx: (schema: ISchema, ref: any) => void;
|
onCompGetCtx: (schema: ISchema, ref: any) => void;
|
||||||
customCreateElement: (...args: any) => any;
|
customCreateElement: (...args: any) => any;
|
||||||
@ -57,7 +56,7 @@ export interface ComponentModel {
|
|||||||
export interface ISchema {
|
export interface ISchema {
|
||||||
componentName: string;
|
componentName: string;
|
||||||
props: any;
|
props: any;
|
||||||
children: ComponentModel[]
|
children: ComponentModel[];
|
||||||
dataSource?: any;
|
dataSource?: any;
|
||||||
methods?: any;
|
methods?: any;
|
||||||
lifeCycles?: any;
|
lifeCycles?: any;
|
||||||
@ -68,7 +67,7 @@ export interface IInfo {
|
|||||||
schema: ISchema;
|
schema: ISchema;
|
||||||
Comp: any;
|
Comp: any;
|
||||||
componentInfo?: any;
|
componentInfo?: any;
|
||||||
componentChildren?: any
|
componentChildren?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface JSExpression {
|
export interface JSExpression {
|
||||||
@ -113,9 +112,9 @@ export interface IRendererModules {
|
|||||||
BaseRenderer?: new(...args: any) => IRenderer;
|
BaseRenderer?: new(...args: any) => IRenderer;
|
||||||
PageRenderer: any;
|
PageRenderer: any;
|
||||||
ComponentRenderer: any;
|
ComponentRenderer: any;
|
||||||
BlockRenderer?: any,
|
BlockRenderer?: any;
|
||||||
AddonRenderer?: any,
|
AddonRenderer?: any;
|
||||||
TempRenderer?: any,
|
TempRenderer?: any;
|
||||||
DivRenderer?: any;
|
DivRenderer?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
567
packages/renderer-core/test/fixtures/schema/basic.ts
vendored
Normal file
567
packages/renderer-core/test/fixtures/schema/basic.ts
vendored
Normal file
@ -0,0 +1,567 @@
|
|||||||
|
export default {
|
||||||
|
componentName: 'Page',
|
||||||
|
id: 'node_dockcviv8fo1',
|
||||||
|
props: {
|
||||||
|
ref: 'outterView',
|
||||||
|
autoLoading: true,
|
||||||
|
style: {
|
||||||
|
padding: '0 5px 0 5px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fileName: 'test',
|
||||||
|
dataSource: {
|
||||||
|
list: [],
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
text: 'outter',
|
||||||
|
isShowDialog: false,
|
||||||
|
},
|
||||||
|
css: 'body {font-size: 12px;} .botton{width:100px;color:#ff00ff}',
|
||||||
|
lifeCycles: {
|
||||||
|
componentDidMount: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: "function() {\n console.log('did mount');\n }",
|
||||||
|
},
|
||||||
|
componentWillUnmount: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: "function() {\n console.log('will umount');\n }",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
testFunc: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: "function() {\n console.log('test func');\n }",
|
||||||
|
},
|
||||||
|
onClick: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: 'function() {\n this.setState({\n isShowDialog: true\n })\n }',
|
||||||
|
},
|
||||||
|
closeDialog: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: 'function() {\n this.setState({\n isShowDialog: false\n })\n }',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Box',
|
||||||
|
id: 'node_dockcy8n9xed',
|
||||||
|
props: {
|
||||||
|
style: {
|
||||||
|
backgroundColor: 'rgba(31,56,88,0.1)',
|
||||||
|
padding: '12px 12px 12px 12px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Box',
|
||||||
|
id: 'node_dockcy8n9xee',
|
||||||
|
props: {
|
||||||
|
style: {
|
||||||
|
padding: '12px 12px 12px 12px',
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Breadcrumb',
|
||||||
|
id: 'node_dockcy8n9xef',
|
||||||
|
props: {
|
||||||
|
prefix: 'next-',
|
||||||
|
maxNode: 100,
|
||||||
|
component: 'nav',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Breadcrumb.Item',
|
||||||
|
id: 'node_dockcy8n9xeg',
|
||||||
|
props: {
|
||||||
|
prefix: 'next-',
|
||||||
|
children: '首页',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Breadcrumb.Item',
|
||||||
|
id: 'node_dockcy8n9xei',
|
||||||
|
props: {
|
||||||
|
prefix: 'next-',
|
||||||
|
children: '品质中台',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Breadcrumb.Item',
|
||||||
|
id: 'node_dockcy8n9xek',
|
||||||
|
props: {
|
||||||
|
prefix: 'next-',
|
||||||
|
children: '商家品质页面管理',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Breadcrumb.Item',
|
||||||
|
id: 'node_dockcy8n9xem',
|
||||||
|
props: {
|
||||||
|
prefix: 'next-',
|
||||||
|
children: '质检知识条配置',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Box',
|
||||||
|
id: 'node_dockcy8n9xeo',
|
||||||
|
props: {
|
||||||
|
style: {
|
||||||
|
marginTop: '12px',
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Form',
|
||||||
|
id: 'node_dockcy8n9xep',
|
||||||
|
props: {
|
||||||
|
inline: true,
|
||||||
|
style: {
|
||||||
|
marginTop: '12px',
|
||||||
|
marginRight: '12px',
|
||||||
|
marginLeft: '12px',
|
||||||
|
},
|
||||||
|
__events: [],
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Form.Item',
|
||||||
|
id: 'node_dockcy8n9xeq',
|
||||||
|
props: {
|
||||||
|
style: {
|
||||||
|
marginBottom: '0',
|
||||||
|
},
|
||||||
|
label: '类目名:',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Select',
|
||||||
|
id: 'node_dockcy8n9xer',
|
||||||
|
props: {
|
||||||
|
mode: 'single',
|
||||||
|
hasArrow: true,
|
||||||
|
cacheValue: true,
|
||||||
|
style: {
|
||||||
|
width: '150px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Form.Item',
|
||||||
|
id: 'node_dockcy8n9xes',
|
||||||
|
props: {
|
||||||
|
style: {
|
||||||
|
marginBottom: '0',
|
||||||
|
},
|
||||||
|
label: '项目类型:',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Select',
|
||||||
|
id: 'node_dockcy8n9xet',
|
||||||
|
props: {
|
||||||
|
mode: 'single',
|
||||||
|
hasArrow: true,
|
||||||
|
cacheValue: true,
|
||||||
|
style: {
|
||||||
|
width: '200px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Form.Item',
|
||||||
|
id: 'node_dockcy8n9xeu',
|
||||||
|
props: {
|
||||||
|
style: {
|
||||||
|
marginBottom: '0',
|
||||||
|
},
|
||||||
|
label: '项目 ID:',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Input',
|
||||||
|
id: 'node_dockcy8n9xev',
|
||||||
|
props: {
|
||||||
|
hasBorder: true,
|
||||||
|
size: 'medium',
|
||||||
|
autoComplete: 'off',
|
||||||
|
style: {
|
||||||
|
width: '200px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Button.Group',
|
||||||
|
id: 'node_dockcy8n9xew',
|
||||||
|
props: {},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Button',
|
||||||
|
id: 'node_dockcy8n9xex',
|
||||||
|
props: {
|
||||||
|
type: 'primary',
|
||||||
|
style: {
|
||||||
|
margin: '0 5px 0 5px',
|
||||||
|
},
|
||||||
|
htmlType: 'submit',
|
||||||
|
children: '搜索',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Button',
|
||||||
|
id: 'node_dockcy8n9xe10',
|
||||||
|
props: {
|
||||||
|
type: 'normal',
|
||||||
|
style: {
|
||||||
|
margin: '0 5px 0 5px',
|
||||||
|
},
|
||||||
|
htmlType: 'reset',
|
||||||
|
children: '清空',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Box',
|
||||||
|
id: 'node_dockcy8n9xe1f',
|
||||||
|
props: {
|
||||||
|
style: {
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
paddingBottom: '24px',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Button',
|
||||||
|
id: 'node_dockd5nrh9p4',
|
||||||
|
props: {
|
||||||
|
type: 'primary',
|
||||||
|
size: 'medium',
|
||||||
|
htmlType: 'button',
|
||||||
|
component: 'button',
|
||||||
|
children: '新建配置',
|
||||||
|
style: {},
|
||||||
|
__events: [
|
||||||
|
{
|
||||||
|
type: 'componentEvent',
|
||||||
|
name: 'onClick',
|
||||||
|
relatedEventName: 'onClick',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onClick: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: 'function(){ this.onClick() }',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Box',
|
||||||
|
id: 'node_dockd5nrh9p5',
|
||||||
|
props: {},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Table',
|
||||||
|
id: 'node_dockjielosj1',
|
||||||
|
props: {
|
||||||
|
showMiniPager: true,
|
||||||
|
showActionBar: true,
|
||||||
|
actionBar: [
|
||||||
|
{
|
||||||
|
title: '新增',
|
||||||
|
type: 'primary',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '编辑',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
dataKey: 'name',
|
||||||
|
width: 200,
|
||||||
|
align: 'center',
|
||||||
|
title: '姓名',
|
||||||
|
editType: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataKey: 'age',
|
||||||
|
width: 200,
|
||||||
|
align: 'center',
|
||||||
|
title: '年龄',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataKey: 'email',
|
||||||
|
width: 200,
|
||||||
|
align: 'center',
|
||||||
|
title: '邮箱',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
name: '王小',
|
||||||
|
id: '1',
|
||||||
|
age: 15000,
|
||||||
|
email: 'aaa@abc.com',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '王中',
|
||||||
|
id: '2',
|
||||||
|
age: 25000,
|
||||||
|
email: 'bbb@abc.com',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '王大',
|
||||||
|
id: '3',
|
||||||
|
age: 35000,
|
||||||
|
email: 'ccc@abc.com',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actionTitle: '操作',
|
||||||
|
actionWidth: 180,
|
||||||
|
actionType: 'link',
|
||||||
|
actionFixed: 'right',
|
||||||
|
actionHidden: false,
|
||||||
|
maxWebShownActionCount: 2,
|
||||||
|
actionColumn: [
|
||||||
|
{
|
||||||
|
title: '编辑',
|
||||||
|
callback: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: '(rowData, action, table) => {\n return table.editRow(rowData).then((row) => {\n console.log(row);\n });\n }',
|
||||||
|
},
|
||||||
|
device: [
|
||||||
|
'desktop',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '保存',
|
||||||
|
callback: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: '(rowData, action, table) => { \nreturn table.saveRow(rowData).then((row) => { \nconsole.log(row); \n}); \n}',
|
||||||
|
},
|
||||||
|
mode: 'EDIT',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Box',
|
||||||
|
id: 'node_dockd5nrh9pg',
|
||||||
|
props: {
|
||||||
|
style: {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Pagination',
|
||||||
|
id: 'node_dockd5nrh9pf',
|
||||||
|
props: {
|
||||||
|
prefix: 'next-',
|
||||||
|
type: 'normal',
|
||||||
|
shape: 'normal',
|
||||||
|
size: 'medium',
|
||||||
|
defaultCurrent: 1,
|
||||||
|
total: 100,
|
||||||
|
pageShowCount: 5,
|
||||||
|
pageSize: 10,
|
||||||
|
pageSizePosition: 'start',
|
||||||
|
showJump: true,
|
||||||
|
style: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Dialog',
|
||||||
|
id: 'node_dockcy8n9xe1h',
|
||||||
|
props: {
|
||||||
|
prefix: 'next-',
|
||||||
|
footerAlign: 'right',
|
||||||
|
footerActions: [
|
||||||
|
'ok',
|
||||||
|
'cancel',
|
||||||
|
],
|
||||||
|
closeable: 'esc,close',
|
||||||
|
hasMask: true,
|
||||||
|
align: 'cc cc',
|
||||||
|
minMargin: 40,
|
||||||
|
visible: {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: 'this.state.isShowDialog',
|
||||||
|
},
|
||||||
|
title: '标题',
|
||||||
|
events: [],
|
||||||
|
__events: [
|
||||||
|
{
|
||||||
|
type: 'componentEvent',
|
||||||
|
name: 'onCancel',
|
||||||
|
relatedEventName: 'closeDialog',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'componentEvent',
|
||||||
|
name: 'onClose',
|
||||||
|
relatedEventName: 'closeDialog',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'componentEvent',
|
||||||
|
name: 'onOk',
|
||||||
|
relatedEventName: 'testFunc',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onCancel: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: 'function(){ this.closeDialog() }',
|
||||||
|
},
|
||||||
|
onClose: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: 'function(){ this.closeDialog() }',
|
||||||
|
},
|
||||||
|
onOk: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: 'function(){ this.testFunc() }',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Form',
|
||||||
|
id: 'node_dockd5nrh9pi',
|
||||||
|
props: {
|
||||||
|
inline: false,
|
||||||
|
labelAlign: 'top',
|
||||||
|
labelTextAlign: 'right',
|
||||||
|
size: 'medium',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Form.Item',
|
||||||
|
id: 'node_dockd5nrh9pj',
|
||||||
|
props: {
|
||||||
|
style: {
|
||||||
|
marginBottom: '0',
|
||||||
|
minWidth: '200px',
|
||||||
|
minHeight: '28px',
|
||||||
|
},
|
||||||
|
label: '商品类目',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Select',
|
||||||
|
id: 'node_dockd5nrh9pk',
|
||||||
|
props: {
|
||||||
|
mode: 'single',
|
||||||
|
hasArrow: true,
|
||||||
|
cacheValue: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Form.Item',
|
||||||
|
id: 'node_dockd5nrh9pl',
|
||||||
|
props: {
|
||||||
|
style: {
|
||||||
|
marginBottom: '0',
|
||||||
|
minWidth: '200px',
|
||||||
|
minHeight: '28px',
|
||||||
|
},
|
||||||
|
label: '商品类目',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Select',
|
||||||
|
id: 'node_dockd5nrh9pm',
|
||||||
|
props: {
|
||||||
|
mode: 'single',
|
||||||
|
hasArrow: true,
|
||||||
|
cacheValue: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Form.Item',
|
||||||
|
id: 'node_dockd5nrh9pn',
|
||||||
|
props: {
|
||||||
|
style: {
|
||||||
|
marginBottom: '0',
|
||||||
|
minWidth: '200px',
|
||||||
|
minHeight: '28px',
|
||||||
|
},
|
||||||
|
label: '商品类目',
|
||||||
|
asterisk: true,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Select',
|
||||||
|
id: 'node_dockd5nrh9po',
|
||||||
|
props: {
|
||||||
|
mode: 'single',
|
||||||
|
hasArrow: true,
|
||||||
|
cacheValue: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Form.Item',
|
||||||
|
id: 'node_dockd5nrh9pp',
|
||||||
|
props: {
|
||||||
|
style: {
|
||||||
|
marginBottom: '0',
|
||||||
|
minWidth: '200px',
|
||||||
|
minHeight: '28px',
|
||||||
|
},
|
||||||
|
label: '商品类目',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Input',
|
||||||
|
id: 'node_dockd5nrh9pr',
|
||||||
|
props: {
|
||||||
|
hasBorder: true,
|
||||||
|
size: 'medium',
|
||||||
|
autoComplete: 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'ErrorComponent',
|
||||||
|
id: 'node_dockd5nrh9pr',
|
||||||
|
props: {
|
||||||
|
name: 'error',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
241
packages/renderer-core/test/renderer/renderer.test.tsx
Normal file
241
packages/renderer-core/test/renderer/renderer.test.tsx
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import renderer from 'react-test-renderer';
|
||||||
|
import schema from '../fixtures/schema/basic';
|
||||||
|
import '../utils/mock-react-render';
|
||||||
|
import rendererFactory from '../../src/renderer/renderer';
|
||||||
|
import components from '../utils/components';
|
||||||
|
|
||||||
|
const Renderer = rendererFactory();
|
||||||
|
|
||||||
|
function getComp(schema, comp = null): Promise<{
|
||||||
|
component,
|
||||||
|
inst,
|
||||||
|
}> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const component = renderer.create(
|
||||||
|
// @ts-ignore
|
||||||
|
<Renderer
|
||||||
|
schema={schema}
|
||||||
|
components={components}
|
||||||
|
/>);
|
||||||
|
|
||||||
|
const componentInstance = component.root;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve({
|
||||||
|
inst: comp ? componentInstance.findAllByType(comp) : null,
|
||||||
|
component,
|
||||||
|
});
|
||||||
|
}, 20);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
let componentSnapshot;
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
if (componentSnapshot) {
|
||||||
|
let tree = componentSnapshot.toJSON();
|
||||||
|
expect(tree).toMatchSnapshot();
|
||||||
|
componentSnapshot = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Base Render', () => {
|
||||||
|
it('renderComp', () => {
|
||||||
|
const content = (
|
||||||
|
// @ts-ignore
|
||||||
|
<Renderer
|
||||||
|
schema={schema}
|
||||||
|
components={components}
|
||||||
|
/>);
|
||||||
|
const tree = renderer.create(content).toJSON();
|
||||||
|
expect(tree).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('JSExpression', () => {
|
||||||
|
it('base props', (done) => {
|
||||||
|
const schema = {
|
||||||
|
componentName: 'Page',
|
||||||
|
props: {},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: "Div",
|
||||||
|
props: {
|
||||||
|
className: 'div-ut',
|
||||||
|
text: "123",
|
||||||
|
visible: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
getComp(schema, components.Div).then(({ component, inst }) => {
|
||||||
|
expect(inst[0].props.text).toBe('123');
|
||||||
|
expect(inst[0].props.visible).toBeTruthy();
|
||||||
|
|
||||||
|
componentSnapshot = component;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('JSExpression props', (done) => {
|
||||||
|
const schema = {
|
||||||
|
componentName: 'Page',
|
||||||
|
props: {},
|
||||||
|
state: {
|
||||||
|
isShowDialog: true,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: "Div",
|
||||||
|
props: {
|
||||||
|
className: "div-ut",
|
||||||
|
visible: {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: 'this.state.isShowDialog',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
getComp(schema, components.Div).then(({ component, inst }) => {
|
||||||
|
expect(inst[0].props.visible).toBeTruthy();
|
||||||
|
componentSnapshot = component;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('JSExpression props with loop', (done) => {
|
||||||
|
const schema = {
|
||||||
|
componentName: 'Page',
|
||||||
|
props: {},
|
||||||
|
state: {
|
||||||
|
isShowDialog: true,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: "Div",
|
||||||
|
loop: [
|
||||||
|
{
|
||||||
|
name: '1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '2'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
props: {
|
||||||
|
className: "div-ut",
|
||||||
|
name1: {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: 'this.item.name',
|
||||||
|
},
|
||||||
|
name2: {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: 'item.name',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
getComp(schema, components.Div).then(({ component, inst }) => {
|
||||||
|
// expect(inst[0].props.visible).toBeTruthy();
|
||||||
|
expect(inst.length).toEqual(2);
|
||||||
|
[1, 2].forEach((i) => {
|
||||||
|
expect(inst[0].props[`name${i}`]).toBe('1');
|
||||||
|
expect(inst[1].props[`name${i}`]).toBe('2');
|
||||||
|
})
|
||||||
|
componentSnapshot = component;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('JSFunction props with loop', (done) => {
|
||||||
|
const schema = {
|
||||||
|
componentName: 'Page',
|
||||||
|
props: {},
|
||||||
|
state: {
|
||||||
|
isShowDialog: true,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: "Div",
|
||||||
|
loop: [
|
||||||
|
{
|
||||||
|
name: '1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '2'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
props: {
|
||||||
|
className: "div-ut",
|
||||||
|
onClick1: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: '() => this.item.name',
|
||||||
|
},
|
||||||
|
onClick2: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: 'function(){ return this.item.name }',
|
||||||
|
},
|
||||||
|
onClick3: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: 'function(){ return item.name }',
|
||||||
|
},
|
||||||
|
onClick4: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: '() => item.name',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
getComp(schema, components.Div).then(({ component, inst }) => {
|
||||||
|
// expect(inst[0].props.visible).toBeTruthy();
|
||||||
|
expect(inst.length).toEqual(2);
|
||||||
|
[1, 2, 3, 4].forEach((i) => {
|
||||||
|
expect(inst[0].props[`onClick${i}`]()).toBe('1');
|
||||||
|
expect(inst[1].props[`onClick${i}`]()).toBe('2');
|
||||||
|
})
|
||||||
|
componentSnapshot = component;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('JSFunction props', (done) => {
|
||||||
|
const schema = {
|
||||||
|
componentName: 'Page',
|
||||||
|
props: {},
|
||||||
|
state: {
|
||||||
|
isShowDialog: true,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: "Div",
|
||||||
|
props: {
|
||||||
|
className: "div-ut",
|
||||||
|
onClick: {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: '() => this.state.isShowDialog',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
getComp(schema, components.Div).then(({ component, inst }) => {
|
||||||
|
expect(!!inst[0].props.onClick).toBeTruthy();
|
||||||
|
expect(inst[0].props.onClick()).toBeTruthy();
|
||||||
|
|
||||||
|
componentSnapshot = component;
|
||||||
|
done();
|
||||||
|
});;
|
||||||
|
});
|
||||||
|
})
|
||||||
22
packages/renderer-core/test/utils/components.tsx
Normal file
22
packages/renderer-core/test/utils/components.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { Box, Breadcrumb, Form, Select, Input, Button, Table, Pagination, Dialog } from '@alifd/next';
|
||||||
|
|
||||||
|
const Div = (props) => (<div {...props}>{props.children}</div>);
|
||||||
|
|
||||||
|
const components = {
|
||||||
|
Box,
|
||||||
|
Breadcrumb,
|
||||||
|
'Breadcrumb.Item': Breadcrumb.Item,
|
||||||
|
Form,
|
||||||
|
'Form.Item': Form.Item,
|
||||||
|
Select,
|
||||||
|
Input,
|
||||||
|
Button,
|
||||||
|
'Button.Group': Button.Group,
|
||||||
|
Table,
|
||||||
|
Pagination,
|
||||||
|
Dialog,
|
||||||
|
ErrorComponent: Select,
|
||||||
|
Div,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default components;
|
||||||
66
packages/renderer-core/test/utils/mock-react-render.ts
Normal file
66
packages/renderer-core/test/utils/mock-react-render.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import React, { Component, PureComponent, createElement, createContext, forwardRef, ReactInstance, ContextType } from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import {
|
||||||
|
adapter,
|
||||||
|
pageRendererFactory,
|
||||||
|
componentRendererFactory,
|
||||||
|
blockRendererFactory,
|
||||||
|
addonRendererFactory,
|
||||||
|
tempRendererFactory,
|
||||||
|
rendererFactory,
|
||||||
|
types,
|
||||||
|
} from '../../src';
|
||||||
|
import ConfigProvider from '@alifd/next/lib/config-provider';
|
||||||
|
|
||||||
|
window.React = React;
|
||||||
|
(window as any).ReactDom = ReactDOM;
|
||||||
|
|
||||||
|
adapter.setRuntime({
|
||||||
|
Component,
|
||||||
|
PureComponent,
|
||||||
|
createContext,
|
||||||
|
createElement,
|
||||||
|
forwardRef,
|
||||||
|
findDOMNode: ReactDOM.findDOMNode,
|
||||||
|
});
|
||||||
|
|
||||||
|
adapter.setRenderers({
|
||||||
|
PageRenderer: pageRendererFactory(),
|
||||||
|
ComponentRenderer: componentRendererFactory(),
|
||||||
|
BlockRenderer: blockRendererFactory(),
|
||||||
|
AddonRenderer: addonRendererFactory(),
|
||||||
|
TempRenderer: tempRendererFactory(),
|
||||||
|
DivRenderer: blockRendererFactory(),
|
||||||
|
});
|
||||||
|
|
||||||
|
adapter.setConfigProvider(ConfigProvider);
|
||||||
|
|
||||||
|
function factory() {
|
||||||
|
const Renderer = rendererFactory();
|
||||||
|
return class ReactRenderer extends Renderer implements Component {
|
||||||
|
readonly props: types.IProps;
|
||||||
|
|
||||||
|
context: ContextType<any>;
|
||||||
|
|
||||||
|
setState: (
|
||||||
|
state: types.IState,
|
||||||
|
callback?: () => void,
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
forceUpdate: (callback?: () => void) => void;
|
||||||
|
|
||||||
|
refs: {
|
||||||
|
[key: string]: ReactInstance,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props: types.IProps, context: ContextType<any>) {
|
||||||
|
super(props, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidComponent(obj: any) {
|
||||||
|
return obj?.prototype?.isReactComponent || obj?.prototype instanceof Component;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default factory();
|
||||||
Loading…
x
Reference in New Issue
Block a user