mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-13 01:21:58 +00:00
test: 补充部分单测
This commit is contained in:
parent
5d33a2a9ec
commit
d53ba538b1
@ -6,7 +6,7 @@ module.exports = {
|
||||
// // '^.+\\.(ts|tsx)$': 'ts-jest',
|
||||
// // '^.+\\.(js|jsx)$': 'babel-jest',
|
||||
// },
|
||||
// testMatch: ['**/builtin-hotkey.test.ts'],
|
||||
testMatch: ['**/bugs/*.test.ts'],
|
||||
// testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
|
||||
transformIgnorePatterns: [
|
||||
`/node_modules/(?!${esModules})/`,
|
||||
|
||||
72
packages/designer/tests/bugs/prop-variable-jse.test.ts
Normal file
72
packages/designer/tests/bugs/prop-variable-jse.test.ts
Normal file
@ -0,0 +1,72 @@
|
||||
// @ts-nocheck
|
||||
import { Editor } from '@ali/lowcode-editor-core';
|
||||
import { isJSBlock, TransformStage } from '@ali/lowcode-types';
|
||||
import { isPlainObject, isVariable } from '@ali/lowcode-utils';
|
||||
import '../fixtures/window';
|
||||
import { Designer } from '../../src/designer/designer';
|
||||
import { DocumentModel } from '../../src/document/document-model';
|
||||
import { Project } from '../../src/project/project';
|
||||
import formSchema from '../fixtures/schema/form';
|
||||
|
||||
/**
|
||||
* bug 背景:
|
||||
* Prop 在每次 setValue 时都会调用 dispose 方法用于重新计算子 Prop,我认为在 Node 未完成初始化之前的 dispose 都是
|
||||
* 无意义的,所以增加了判断条件来调用 dispose,结果导致了 variable 结果没有正确转成 JSExpression 结构。
|
||||
*
|
||||
* 因为 propsReducer 的 Init / Upgrade 阶段依然可以更改 props,且此时的 Node 也未完成初始化,不调用 dispose 则导致新的 Prop 结构无法生效
|
||||
*/
|
||||
|
||||
function upgradePropsReducer(props: any): any {
|
||||
if (!props || !isPlainObject(props)) {
|
||||
return props;
|
||||
}
|
||||
|
||||
if (isJSBlock(props)) {
|
||||
if (props.value.componentName === 'Slot') {
|
||||
return {
|
||||
type: 'JSSlot',
|
||||
title: (props.value.props as any)?.slotTitle,
|
||||
name: (props.value.props as any)?.slotName,
|
||||
value: props.value.children,
|
||||
};
|
||||
} else {
|
||||
return props.value;
|
||||
}
|
||||
}
|
||||
if (isVariable(props)) {
|
||||
return {
|
||||
type: 'JSExpression',
|
||||
value: props.variable,
|
||||
mock: props.value,
|
||||
};
|
||||
}
|
||||
const newProps: any = {};
|
||||
Object.keys(props).forEach((key) => {
|
||||
if (/^__slot__/.test(key) && props[key] === true) {
|
||||
return;
|
||||
}
|
||||
newProps[key] = upgradePropsReducer(props[key]);
|
||||
});
|
||||
return newProps;
|
||||
}
|
||||
|
||||
describe('Node 方法测试', () => {
|
||||
let editor: Editor;
|
||||
let designer: Designer;
|
||||
let project: Project;
|
||||
let doc: DocumentModel;
|
||||
|
||||
it('原始 prop 值是 variable 结构,通过一个 propsReducer 转成了 JSExpression 结构', () => {
|
||||
editor = new Editor();
|
||||
designer = new Designer({ editor });
|
||||
designer.addPropsReducer(upgradePropsReducer, TransformStage.Upgrade);
|
||||
project = designer.project;
|
||||
doc = new DocumentModel(project, formSchema);
|
||||
|
||||
const form = doc.getNode('form');
|
||||
expect(form.getPropValue('dataSource')).toEqual({
|
||||
type: 'JSExpression',
|
||||
value: 'state.formData',
|
||||
})
|
||||
});
|
||||
});
|
||||
6
packages/designer/tests/bugs/why.md
Normal file
6
packages/designer/tests/bugs/why.md
Normal file
@ -0,0 +1,6 @@
|
||||
背景:
|
||||
在 UT 的基础上,希望借助一些 Bug 修复来完成场景测试,从而进一步增强稳定性。
|
||||
至少在真正的 E2E 测试来临之前,我们保证不会重复犯两次相同的错误。
|
||||
|
||||
做法:
|
||||
Bugs 文件夹每个文件记录一个 bug 修复的场景测试~
|
||||
@ -1,4 +1,4 @@
|
||||
// @ts-ignore
|
||||
// @ts-nocheck
|
||||
import '../../fixtures/window';
|
||||
import { set, delayObxTick, delay } from '../../utils';
|
||||
import { Editor } from '@ali/lowcode-editor-core';
|
||||
@ -24,7 +24,6 @@ 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;
|
||||
@ -185,12 +184,16 @@ describe('Node 方法测试', () => {
|
||||
|
||||
it('null', () => {
|
||||
expect(
|
||||
doc.rootNode?.getSuitablePlace.call({ contains: () => false, isContainer: () => false, isRoot: () => false }),
|
||||
doc.rootNode?.getSuitablePlace.call({
|
||||
contains: () => false,
|
||||
isContainer: () => false,
|
||||
isRoot: () => false,
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it('removeChild / replaceWith / replaceChild / onChildrenChange / mergeChildren', () => {
|
||||
it('removeChild / replaceWith / replaceChild', () => {
|
||||
const firstBtn = doc.getNode('node_k1ow3cbn')!;
|
||||
|
||||
firstBtn.select();
|
||||
@ -254,7 +257,7 @@ describe('Node 方法测试', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('setVisible / getVisible / onVisibleChange', async () => {
|
||||
it('setVisible / getVisible / onVisibleChange', () => {
|
||||
const mockFn = jest.fn();
|
||||
const firstBtn = doc.getNode('node_k1ow3cbn')!;
|
||||
const off = firstBtn.onVisibleChange(mockFn);
|
||||
@ -265,7 +268,6 @@ describe('Node 方法测试', () => {
|
||||
|
||||
firstBtn.setVisible(false);
|
||||
|
||||
await delayObxTick();
|
||||
expect(firstBtn.getVisible()).toBeFalsy();
|
||||
expect(mockFn).toHaveBeenCalledTimes(2);
|
||||
expect(mockFn).toHaveBeenCalledWith(false);
|
||||
@ -273,7 +275,22 @@ describe('Node 方法测试', () => {
|
||||
off();
|
||||
mockFn.mockClear();
|
||||
firstBtn.setVisible(true);
|
||||
await delayObxTick();
|
||||
expect(mockFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('onPropChange', () => {
|
||||
const mockFn = jest.fn();
|
||||
const firstBtn = doc.getNode('node_k1ow3cbn')!;
|
||||
const off = firstBtn.onPropChange(mockFn);
|
||||
|
||||
firstBtn.setPropValue('x', 1);
|
||||
expect(mockFn).toHaveBeenCalledTimes(1);
|
||||
firstBtn.setPropValue('x', 2);
|
||||
expect(mockFn).toHaveBeenCalledTimes(2);
|
||||
|
||||
off();
|
||||
mockFn.mockClear();
|
||||
firstBtn.setPropValue('x', 3);
|
||||
expect(mockFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -292,7 +309,9 @@ describe('Node 方法测试', () => {
|
||||
|
||||
const pageMeta = designer.getComponentMeta('Page');
|
||||
const autorunMockFn = jest.fn();
|
||||
set(pageMeta, '_transformedMetadata.experimental.autoruns', [{ name: 'a', autorun: autorunMockFn }]);
|
||||
set(pageMeta, '_transformedMetadata.experimental.autoruns', [
|
||||
{ name: 'a', autorun: autorunMockFn },
|
||||
]);
|
||||
const initialChildrenMockFn = jest.fn();
|
||||
set(pageMeta, '_transformedMetadata.experimental.initialChildren', initialChildrenMockFn);
|
||||
doc.createNode({ componentName: 'Page', props: { a: 1 } });
|
||||
|
||||
@ -200,9 +200,11 @@ describe('Prop 类测试', () => {
|
||||
// 更新 slot
|
||||
slotProp.setValue({
|
||||
type: 'JSSlot',
|
||||
value: [{
|
||||
componentName: 'Form',
|
||||
}]
|
||||
value: [
|
||||
{
|
||||
componentName: 'Form',
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(slotNodeImportMockFn).toBeCalled();
|
||||
|
||||
@ -276,19 +278,20 @@ describe('Prop 类测试', () => {
|
||||
expect(prop.get('z.z1')?.getValue()).toBe(1);
|
||||
expect(prop.get('z.z2')?.getValue()).toBe('str');
|
||||
|
||||
const fromStashProp = prop.get('l');
|
||||
const fromStashNestedProp = prop.get('m.m1');
|
||||
fromStashProp.setValue('fromStashProp');
|
||||
fromStashNestedProp?.setValue('fromStashNestedProp');
|
||||
const newlyCreatedProp = prop.get('l', true);
|
||||
const newlyCreatedNestedProp = prop.get('m.m1', true);
|
||||
newlyCreatedProp.setValue('newlyCreatedProp');
|
||||
newlyCreatedNestedProp?.setValue('newlyCreatedNestedProp');
|
||||
|
||||
await delayObxTick();
|
||||
expect(prop.get('l').getValue()).toBe('fromStashProp');
|
||||
expect(prop.get('m.m1').getValue()).toBe('fromStashNestedProp');
|
||||
expect(prop.get('l').getValue()).toBe('newlyCreatedProp');
|
||||
expect(prop.get('m.m1').getValue()).toBe('newlyCreatedNestedProp');
|
||||
|
||||
const newlyCreatedNestedProp2 = prop.get('m.m2', true);
|
||||
// .m2 的值为 undefined,导出时将会被移除
|
||||
expect(prop.get('m').getValue()).toEqual({ m1: 'newlyCreatedNestedProp' });
|
||||
});
|
||||
|
||||
it('export', () => {
|
||||
// TODO: 需要访问一下才能触发构造 _items
|
||||
prop.items;
|
||||
expect(prop.export()).toEqual({
|
||||
a: 1,
|
||||
b: 'str',
|
||||
|
||||
@ -2,32 +2,42 @@
|
||||
import '../../../fixtures/window';
|
||||
import { set, delayObxTick } from '../../../utils';
|
||||
import { Editor } from '@ali/lowcode-editor-core';
|
||||
import { Props, getConvertedExtraKey, getOriginalExtraKey, Prop, isProp, isValidArrayIndex } from '../../../../src/document/node/props/props';
|
||||
import {
|
||||
Props,
|
||||
getConvertedExtraKey,
|
||||
getOriginalExtraKey,
|
||||
Prop,
|
||||
isProp,
|
||||
isValidArrayIndex,
|
||||
} from '../../../../src/document/node/props/props';
|
||||
import { Designer } from '../../../../src/designer/designer';
|
||||
import { Project } from '../../../../src/project/project';
|
||||
import { DocumentModel } from '../../../../src/document/document-model';
|
||||
|
||||
import { TransformStage } from '@ali/lowcode-types';
|
||||
|
||||
|
||||
const mockedOwner = { componentName: 'Page' };
|
||||
|
||||
describe('Props 类测试', () => {
|
||||
let props: Props;
|
||||
beforeEach(() => {
|
||||
props = new Props(mockedOwner, {
|
||||
a: 1,
|
||||
b: 'str',
|
||||
c: true,
|
||||
d: {
|
||||
type: 'JSExpression',
|
||||
value: 'state.a',
|
||||
props = new Props(
|
||||
mockedOwner,
|
||||
{
|
||||
a: 1,
|
||||
b: 'str',
|
||||
c: true,
|
||||
d: {
|
||||
type: 'JSExpression',
|
||||
value: 'state.a',
|
||||
},
|
||||
z: {
|
||||
z1: 1,
|
||||
z2: 'str',
|
||||
},
|
||||
},
|
||||
z: {
|
||||
z1: 1,
|
||||
z2: 'str',
|
||||
},
|
||||
}, { condition: true });
|
||||
{ condition: true },
|
||||
);
|
||||
});
|
||||
afterEach(() => {
|
||||
props.purge();
|
||||
@ -49,7 +59,6 @@ describe('Props 类测试', () => {
|
||||
z2: 'str',
|
||||
});
|
||||
|
||||
|
||||
expect(props.getPropValue('a')).toBe(1);
|
||||
props.setPropValue('a', 2);
|
||||
expect(props.getPropValue('a')).toBe(2);
|
||||
@ -59,14 +68,15 @@ describe('Props 类测试', () => {
|
||||
expect(props.get('z.z1')?.getValue()).toBe(1);
|
||||
expect(props.get('z.z2')?.getValue()).toBe('str');
|
||||
|
||||
const fromStashProp = props.get('l', true);
|
||||
const fromStashNestedProp = props.get('m.m1', true);
|
||||
fromStashProp.setValue('fromStashProp');
|
||||
fromStashNestedProp?.setValue('fromStashNestedProp');
|
||||
const notCreatedProp = props.get('i');
|
||||
expect(notCreatedProp).toBeNull();
|
||||
const newlyCreatedProp = props.get('l', true);
|
||||
const newlyCreatedNestedProp = props.get('m.m1', true);
|
||||
newlyCreatedProp.setValue('newlyCreatedProp');
|
||||
newlyCreatedNestedProp?.setValue('newlyCreatedNestedProp');
|
||||
|
||||
await delayObxTick();
|
||||
expect(props.get('l').getValue()).toBe('fromStashProp');
|
||||
expect(props.get('m.m1').getValue()).toBe('fromStashNestedProp');
|
||||
expect(props.get('l').getValue()).toBe('newlyCreatedProp');
|
||||
expect(props.get('m.m1').getValue()).toBe('newlyCreatedNestedProp');
|
||||
});
|
||||
|
||||
it('export', () => {
|
||||
@ -119,11 +129,66 @@ describe('Props 类测试', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('export - remove undefined items', () => {
|
||||
props.import(
|
||||
{
|
||||
a: 1,
|
||||
},
|
||||
{ loop: false },
|
||||
);
|
||||
props.setPropValue('x', undefined);
|
||||
expect(props.export()).toEqual({
|
||||
props: {
|
||||
a: 1,
|
||||
},
|
||||
extras: {
|
||||
loop: false,
|
||||
},
|
||||
});
|
||||
|
||||
props.setPropValue('x', 2);
|
||||
expect(props.export()).toEqual({
|
||||
props: {
|
||||
a: 1,
|
||||
x: 2,
|
||||
},
|
||||
extras: {
|
||||
loop: false,
|
||||
},
|
||||
});
|
||||
|
||||
props.setPropValue('y.z', undefined);
|
||||
expect(props.export()).toEqual({
|
||||
props: {
|
||||
a: 1,
|
||||
x: 2,
|
||||
},
|
||||
extras: {
|
||||
loop: false,
|
||||
},
|
||||
});
|
||||
|
||||
props.setPropValue('y.z', 2);
|
||||
expect(props.export()).toEqual({
|
||||
props: {
|
||||
a: 1,
|
||||
x: 2,
|
||||
y: { z: 2 },
|
||||
},
|
||||
extras: {
|
||||
loop: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('import', () => {
|
||||
props.import({
|
||||
x: 1,
|
||||
y: true,
|
||||
}, { loop: false });
|
||||
props.import(
|
||||
{
|
||||
x: 1,
|
||||
y: true,
|
||||
},
|
||||
{ loop: false },
|
||||
);
|
||||
expect(props.export()).toEqual({
|
||||
props: {
|
||||
x: 1,
|
||||
@ -173,19 +238,19 @@ describe('Props 类测试', () => {
|
||||
expect(mockedFn).toHaveBeenCalledTimes(6);
|
||||
mockedFn.mockClear();
|
||||
|
||||
props.forEach(item => {
|
||||
props.forEach((item) => {
|
||||
mockedFn();
|
||||
});
|
||||
expect(mockedFn).toHaveBeenCalledTimes(6);
|
||||
mockedFn.mockClear();
|
||||
|
||||
props.map(item => {
|
||||
props.map((item) => {
|
||||
return mockedFn();
|
||||
});
|
||||
expect(mockedFn).toHaveBeenCalledTimes(6);
|
||||
mockedFn.mockClear();
|
||||
|
||||
props.filter(item => {
|
||||
props.filter((item) => {
|
||||
return mockedFn();
|
||||
});
|
||||
expect(mockedFn).toHaveBeenCalledTimes(6);
|
||||
@ -229,7 +294,6 @@ describe('Props 类测试', () => {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('其他函数', () => {
|
||||
it('getConvertedExtraKey', () => {
|
||||
expect(getConvertedExtraKey()).toBe('');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user