test: 补充一些 ut

This commit is contained in:
lihao.ylh 2021-11-15 19:57:16 +08:00 committed by lianjie.lj
parent b07436d444
commit cbe5ed7692
10 changed files with 201 additions and 86 deletions

View File

@ -2,7 +2,6 @@ export * from './exclusive-group';
export * from './node';
export * from './node-children';
export * from './props/prop';
export * from './props/prop-stash';
export * from './props/props';
export * from './transform-stage';
export * from './modal-nodes-manager';

View File

@ -142,9 +142,10 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
@computed get title(): string | I18nData | ReactElement {
let t = this.getExtraProp('title');
if (!t && this.componentMeta.descriptor) {
t = this.getProp(this.componentMeta.descriptor, false);
}
// TODO: 暂时走不到这个分支
// if (!t && this.componentMeta.descriptor) {
// t = this.getProp(this.componentMeta.descriptor, false);
// }
if (t) {
const v = t.getAsString();
if (v) {
@ -175,7 +176,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
this._children.internalInitParent();
this.props.merge(
this.upgradeProps(this.initProps(props || {})),
this.upgradeProps(extras || {}),
this.upgradeProps(extras),
);
this.setupAutoruns();
}
@ -719,6 +720,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
const _extras_: { [key: string]: any } = {
...extras,
};
/* istanbul ignore next */
Object.keys(this._addons).forEach((key) => {
const addon = this._addons[key];
if (addon) {
@ -1183,12 +1185,18 @@ export function getZLevelTop(child: Node, zLevel: number): Node | null {
return r;
}
/**
*
* @param node1
* @param node2
* @returns
*/
export function contains(node1: Node, node2: Node): boolean {
if (node1 === node2) {
return true;
}
if (!node1.isParental || !node2.parent) {
if (!node1.isParental() || !node2.parent) {
return false;
}

View File

@ -1,77 +0,0 @@
import { obx, autorun, untracked, computed, makeObservable, action } from '@ali/lowcode-editor-core';
import { Prop, IPropParent, UNSET } from './prop';
import { Props } from './props';
import { Node } from '../node';
export type PendingItem = Prop[];
export class PropStash implements IPropParent {
readonly isPropStash = true;
@obx.shallow private space: Set<Prop> = new Set();
@computed private get maps(): Map<string | number, Prop> {
const maps = new Map();
if (this.space.size > 0) {
this.space.forEach(prop => {
maps.set(prop.key, prop);
});
}
return maps;
}
private willPurge: () => void;
readonly owner: Node;
constructor(readonly props: Props, write: (item: Prop) => void) {
makeObservable(this);
this.owner = props.owner;
this.willPurge = autorun(() => {
if (this.space.size < 1) {
return;
}
const pending: Prop[] = [];
for (const prop of this.space) {
if (!prop.isUnset() && !prop.isVirtual()) {
this.space.delete(prop);
pending.push(prop);
}
}
if (pending.length > 0) {
untracked(() => {
for (const item of pending) {
write(item);
}
});
}
});
}
@action
get(key: string | number): Prop {
let prop = this.maps.get(key);
if (!prop) {
prop = new Prop(this, UNSET, key);
this.space.add(prop);
}
return prop;
}
@action
delete(prop: Prop) {
this.space.delete(prop);
prop.purge();
}
@action
clear() {
this.space.forEach(item => item.purge());
this.space.clear();
}
@action
purge() {
this.willPurge();
this.space.clear();
}
}

View File

@ -228,9 +228,10 @@ export class Props implements IPropParent {
*/
@action
deleteKey(key: string): void {
this.items = this.items.filter(item => {
this.items = this.items.filter((item, i) => {
if (item.key === key) {
item.purge();
this.items.splice(i, 1);
return false;
}
return true;

View File

@ -0,0 +1,63 @@
import '../../fixtures/window';
import { set, delayObxTick, delay } 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,
PositionNO,
} from '../../../src/document/node/node';
import { Designer } from '../../../src/designer/designer';
import { BemToolsManager } from '../../../src/builtin-simulator/bem-tools/manager';
import formSchema from '../../fixtures/schema/form';
describe('Node 方法测试', () => {
let editor: Editor;
let designer: Designer;
// let project: Project;
// let doc: DocumentModel;
let manager: BemToolsManager;
beforeEach(() => {
editor = new Editor();
designer = new Designer({ editor });
// project = designer.project;
// doc = new DocumentModel(project, formSchema);
manager = new BemToolsManager(designer);
});
afterEach(() => {
// project.unload();
designer.purge();
editor = null;
designer = null;
// project = null;
});
it('addBemTools / removeBemTools / getAllBemTools', () => {
manager.addBemTools({
name: 't1',
item: (props: any) => { return <div />; },
});
expect(manager.getAllBemTools().length).toBe(1);
expect(() => {
manager.addBemTools({
name: 't1',
item: (props: any) => { return <div />; },
});
}).toThrow(/already exists/);
manager.removeBemTools('t2');
expect(manager.getAllBemTools().length).toBe(1);
manager.removeBemTools('t1');
expect(manager.getAllBemTools().length).toBe(0);
});
});

View File

@ -17,6 +17,8 @@ import {
import { Designer } from '../../../src/designer/designer';
import formSchema from '../../fixtures/schema/form';
import divMetadata from '../../fixtures/component-metadata/div';
import dialogMetadata from '../../fixtures/component-metadata/dialog';
import btnMetadata from '../../fixtures/component-metadata/button';
import formMetadata from '../../fixtures/component-metadata/form';
import otherMeta from '../../fixtures/component-metadata/other';
import pageMetadata from '../../fixtures/component-metadata/page';
@ -47,6 +49,28 @@ describe('Node 方法测试', () => {
it('condition group', () => {});
it('getExtraProp / setExtraProp', () => {
const firstBtn = doc.getNode('node_k1ow3cbn')!;
expect(firstBtn.getExtraProp('non-existing', false)).toBeNull();
firstBtn.setExtraProp('xxx', '1111');
expect(firstBtn.getExtraProp('xxx', false).getValue()).toBe('1111');
});
it('import(leaf)', () => {
const form = doc.getNode('node_k1ow3cbo');
form.insert({ componentName: 'Leaf', children: '111' });
const leaf = form.getChildren().get(2);
expect(leaf.getPropValue('children')).toBe('111');
leaf.import({ componentName: 'Leaf', children: '222' });
expect(leaf.getPropValue('children')).toBe('222');
leaf.import({ componentName: 'Leaf', children: { type: 'JSExpression', value: 'state.x' } });
expect(leaf.getPropValue('children')).toEqual({ type: 'JSExpression', value: 'state.x' });
});
it('hasCondition', () => {
const firstBtn = doc.getNode('node_k1ow3cbn')!;
firstBtn.getExtraProp('condition')?.setValue(undefined);
@ -149,6 +173,22 @@ describe('Node 方法测试', () => {
expect(o).toBeNull();
});
it('放入模态节点', () => {
designer.createComponentMeta(pageMetadata);
designer.createComponentMeta(dialogMetadata);
const dialog = doc.createNode({ componentName: 'Dialog' });
const o = doc.rootNode?.getSuitablePlace(dialog, 1);
expect(o.container).toBe(doc.rootNode);
expect(o.ref).toBe(1);
});
it('包含 focusNode', () => {
const o = doc.rootNode?.getSuitablePlace(doc.rootNode);
expect(o.container).toBe(doc.rootNode);
});
it.skip('非 root 节点,不能放入子节点', () => {
designer.createComponentMeta(formMetadata);
designer.createComponentMeta(pageMetadata);
@ -195,6 +235,10 @@ describe('Node 方法测试', () => {
it('removeChild / replaceWith / replaceChild', () => {
const firstBtn = doc.getNode('node_k1ow3cbn')!;
const form = doc.getNode('node_k1ow3cbo');
// 不符合条件的节点直接返回
expect(firstBtn.replaceChild(form, { componentName: 'Button', props: { x: 1 } })).toBe(form);
firstBtn.select();
firstBtn.parent?.replaceChild(firstBtn, { componentName: 'Button', props: { x: 1 } });
@ -208,6 +252,15 @@ describe('Node 方法测试', () => {
expect(firstBtn.parent?.getChildren()?.get(1)?.getPropValue('y')).toBe(1);
});
it('schema', () => {
const firstBtn = doc.getNode('node_k1ow3cbn')!;
const schema = firstBtn.schema;
schema.props.size = 'large';
firstBtn.schema = schema;
expect(firstBtn.getPropValue('size')).toBe('large');
});
describe('插入相关方法', () => {
it('insertBefore / onChildrenChange', () => {
const firstBtn = doc.getNode('node_k1ow3cbn')!;
@ -278,6 +331,19 @@ describe('Node 方法测试', () => {
expect(mockFn).not.toHaveBeenCalled();
});
it('RGL / getRGL', () => {
const firstBtn = doc.getNode('node_k1ow3cbn')!;
firstBtn.isRGLContainer = true;
expect(firstBtn.isRGLContainer).toBeTruthy();
const rgl = firstBtn.getRGL();
expect(rgl.isContainerNode).toBeFalsy();
expect(rgl.isEmptyNode).toBeTruthy();
expect(rgl.isRGLContainerNode).toBeTruthy();
expect(rgl.isRGLNode).toBeFalsy();
expect(rgl.isRGL).toBeTruthy();
});
it('onPropChange', () => {
const mockFn = jest.fn();
const firstBtn = doc.getNode('node_k1ow3cbn')!;
@ -330,8 +396,24 @@ describe('Node 方法测试', () => {
expect(doc.getNode('form')?.isValidComponent()).toBeFalsy();
});
it('title', () => {
designer.createComponentMeta(btnMetadata);
const btn = doc.getNode('node_k1ow3cbn');
// 从 componentMeta 中获取到 title 值
expect(btn.title).toEqual({ type: 'i18n', 'zh-CN': '按钮', 'en-US': 'Button' } );
// 从 extraProp 中获取值
btn.setExtraProp('title', 'hello button');
expect(btn.title).toBe('hello button');
// btn.props.deleteKey('___title___');
// 从 componentMeta descriptor 指向的 key 获取 title
// btn.setPropValue('xTitle', 'title from descriptor')
// expect(btn.title).toBe('title from descriptor');
});
it('isEmpty / getIndex / getIcon', () => {
const firstBtn = doc.getNode('node_k1ow3cbn')!;
// expect(firstBtn.children).toBeNull();
expect(firstBtn.isEmpty()).toBeTruthy();
expect(firstBtn.index).toBe(0);
expect(firstBtn.getIndex()).toBe(0);
@ -378,12 +460,39 @@ describe('Node 方法测试', () => {
expect(doc.rootNode.toString()).toBe('page');
});
it('lock', () => {
const form = doc.getNode('node_k1ow3cbo');
expect(form.isLocked).toBeFalsy();
form.lock(true);
expect(form.isLocked).toBeTruthy();
form.lock(false);
expect(form.isLocked).toBeFalsy();
form.lock();
expect(form.isLocked).toBeTruthy();
});
it('didDropIn / didDropOut', () => {
const form = doc.getNode('node_k1ow3cbo');
designer.createComponentMeta(divMetadata);
const callbacks = form.componentMeta.getMetadata().experimental?.callbacks;
const fn1 = callbacks.onNodeAdd = jest.fn();
const fn2 = callbacks.onNodeRemove = jest.fn();
const textField = doc.getNode('node_k1ow3cc9');
form.didDropIn(textField);
expect(fn1).toHaveBeenCalledWith(textField, form);
form.didDropOut(textField);
expect(fn2).toHaveBeenCalledWith(textField, form);
});
it('hover', () => {
const firstBtn = doc.getNode('node_k1ow3cbn')!;
firstBtn.hover(true);
expect(doc.designer.detecting.current).toBe(firstBtn);
firstBtn.hover(false);
expect(doc.designer.detecting.current).toBeNull();
firstBtn.hover();
expect(doc.designer.detecting.current).toBe(firstBtn);
});
it('getRect', () => {
@ -410,13 +519,14 @@ describe('Node 方法测试', () => {
it('contains / comparePosition', () => {
const page = doc.getNode('page')!;
const content = doc.getNode('node_k1ow3cbb')!;
const firstBtn = doc.getNode('node_k1ow3cbn')!;
const secondBtn = doc.getNode('node_k1ow3cbp')!;
const firstCard = doc.getNode('node_k1ow3cbj')!;
expect(contains(firstBtn, firstBtn)).toBeTruthy();
expect(contains(firstBtn, secondBtn)).toBeFalsy();
// TODO: 其实这句测试的代码没懂
expect(contains(firstBtn, page)).toBeFalsy();
expect(contains(firstBtn, content)).toBeFalsy();
expect(contains(firstCard, firstBtn)).toBeFalsy();
expect(comparePosition(firstBtn, secondBtn)).toBe(PositionNO.BeforeOrAfter);

View File

@ -253,6 +253,7 @@ export default {
// parentWhitelist: 'Div',
// childWhitelist: 'Div',
},
descriptor: 'xTitle'
},
supports: {},
},

View File

@ -230,7 +230,10 @@ export default {
supports: {},
},
experimental: {
callbacks: {},
callbacks: {
onNodeAdd: (dragment, self) => { console.log(dragment); },
onNodeRemove: (dragment, self) => { console.log(dragment); }
},
initials: [
{
name: 'behavior',

View File

@ -4,4 +4,5 @@ import { invariant } from '../../src/utils/invariant';
it('invariant', () => {
expect(() => invariant(true)).not.toThrow();
expect(() => invariant(false, 'abc', 'xxx')).toThrow(/Invariant failed:/);
expect(() => invariant(false, 'abc')).toThrow(/Invariant failed:/);
});

View File

@ -21,10 +21,14 @@ const mockNode = {
}]
};
// 没有 slots
const mockNode2 = {};
it('includeSlot', () => {
expect(includeSlot(mockNode, 'haha')).toBeTruthy();
expect(includeSlot(mockNode, 'heihei')).toBeTruthy();
expect(includeSlot(mockNode, 'xixi')).toBeFalsy();
expect(includeSlot(mockNode2, 'xixi')).toBeFalsy();
});
it('removeSlot', () => {
@ -34,4 +38,6 @@ it('removeSlot', () => {
expect(mockNode.slots).toHaveLength(1);
expect(removeSlot(mockNode, 'heihei')).toBeTruthy();
expect(mockNode.slots).toHaveLength(0);
expect(removeSlot(mockNode2, 'xixi')).toBeFalsy();
});