test(utils): add ut to package/utils

This commit is contained in:
liujuping 2023-11-13 12:25:50 +08:00 committed by 林熠
parent 938c71fb46
commit 621245393f
74 changed files with 2621 additions and 439 deletions

View File

@ -11,6 +11,7 @@ const jestConfig = {
'!**/node_modules/**',
'!**/vendor/**',
],
setupFilesAfterEnv: ['./jest.setup.js'],
};
// 只对本仓库内的 pkg 做 mapping

View File

@ -0,0 +1 @@
import '@testing-library/jest-dom';

View File

@ -9,7 +9,7 @@
"main": "lib/index.js",
"module": "es/index.js",
"scripts": {
"test": "build-scripts test --config build.test.json",
"test": "build-scripts test --config build.test.json --jest-coverage",
"build": "build-scripts build"
},
"dependencies": {
@ -21,8 +21,11 @@
},
"devDependencies": {
"@alib/build-scripts": "^0.1.18",
"@testing-library/jest-dom": "^6.1.4",
"@testing-library/react": "^11.2.7",
"@types/node": "^13.7.1",
"@types/react": "^16"
"@types/react": "^16",
"react-dom": "^16.14.0"
},
"publishConfig": {
"access": "public",

View File

@ -1,5 +1,6 @@
import { IPublicTypeActionContentObject } from '@alilc/lowcode-types';
import { isObject } from '../is-object';
export function isActionContentObject(obj: any): obj is IPublicTypeActionContentObject {
return obj && typeof obj === 'object';
return isObject(obj);
}

View File

@ -2,7 +2,9 @@ import { isValidElement } from 'react';
import { isReactComponent } from '../is-react';
import { IPublicTypeCustomView } from '@alilc/lowcode-types';
export function isCustomView(obj: any): obj is IPublicTypeCustomView {
return obj && (isValidElement(obj) || isReactComponent(obj));
if (!obj) {
return false;
}
return isValidElement(obj) || isReactComponent(obj);
}

View File

@ -1,5 +1,9 @@
import { IPublicEnumDragObjectType } from '@alilc/lowcode-types';
import { isObject } from '../is-object';
export function isDragAnyObject(obj: any): boolean {
return obj && obj.type !== IPublicEnumDragObjectType.NodeData && obj.type !== IPublicEnumDragObjectType.Node;
if (!isObject(obj)) {
return false;
}
return obj.type !== IPublicEnumDragObjectType.NodeData && obj.type !== IPublicEnumDragObjectType.Node;
}

View File

@ -1,5 +1,9 @@
import { IPublicEnumDragObjectType, IPublicTypeDragNodeDataObject } from '@alilc/lowcode-types';
import { isObject } from '../is-object';
export function isDragNodeDataObject(obj: any): obj is IPublicTypeDragNodeDataObject {
return obj && obj.type === IPublicEnumDragObjectType.NodeData;
if (!isObject(obj)) {
return false;
}
return obj.type === IPublicEnumDragObjectType.NodeData;
}

View File

@ -1,5 +1,9 @@
import { IPublicEnumDragObjectType, IPublicModelNode, IPublicTypeDragNodeObject } from '@alilc/lowcode-types';
import { isObject } from '../is-object';
export function isDragNodeObject<Node = IPublicModelNode>(obj: any): obj is IPublicTypeDragNodeObject<Node> {
return obj && obj.type === IPublicEnumDragObjectType.Node;
if (!isObject(obj)) {
return false;
}
return obj.type === IPublicEnumDragObjectType.Node;
}

View File

@ -1,7 +1,10 @@
import { isFunction } from '../is-function';
import { isReactClass } from '../is-react';
import { IPublicTypeDynamicSetter } from '@alilc/lowcode-types';
export function isDynamicSetter(obj: any): obj is IPublicTypeDynamicSetter {
return obj && typeof obj === 'function' && !isReactClass(obj);
if (!isFunction(obj)) {
return false;
}
return !isReactClass(obj);
}

View File

@ -0,0 +1,3 @@
export function isFunction(obj: any): obj is Function {
return obj && typeof obj === 'function';
}

View File

@ -1,8 +1,9 @@
// type checks
import { IPublicTypeI18nData } from "@alilc/lowcode-types";
import { IPublicTypeI18nData } from '@alilc/lowcode-types';
import { isObject } from '../is-object';
export function isI18nData(obj: any): obj is IPublicTypeI18nData {
return obj && obj.type === 'i18n';
if (!isObject(obj)) {
return false;
}
return obj.type === 'i18n';
}

View File

@ -1,10 +1,26 @@
import { IPublicTypeJSFunction } from '@alilc/lowcode-types';
import { isObject } from '../is-object';
interface InnerJsFunction {
type: 'JSExpression';
source: string;
value: string;
extType: 'function';
}
/**
* { type: 'JSExpression', source: '', value: '', extType: 'function' } JSFunction
*/
export function isInnerJsFunction(data: any) {
return data && data.type === 'JSExpression' && data.extType === 'function';
export function isInnerJsFunction(data: any): data is InnerJsFunction {
if (!isObject(data)) {
return false;
}
return data.type === 'JSExpression' && data.extType === 'function';
}
export function isJSFunction(data: any): boolean {
return typeof data === 'object' && data && data.type === 'JSFunction' || isInnerJsFunction(data);
export function isJSFunction(data: any): data is IPublicTypeJSFunction {
if (!isObject(data)) {
return false;
}
return data.type === 'JSFunction' || isInnerJsFunction(data);
}

View File

@ -1,4 +1,9 @@
import { IPublicTypeJSBlock } from '@alilc/lowcode-types';
import { isObject } from '../is-object';
export function isJSBlock(data: any): boolean {
return data && data.type === 'JSBlock';
export function isJSBlock(data: any): data is IPublicTypeJSBlock {
if (!isObject(data)) {
return false;
}
return data.type === 'JSBlock';
}

View File

@ -1,4 +1,5 @@
import { IPublicTypeJSExpression } from '@alilc/lowcode-types';
import { isObject } from '../is-object';
/**
* { type: 'JSExpression', extType: 'function' }
@ -11,5 +12,8 @@ import { IPublicTypeJSExpression } from '@alilc/lowcode-types';
* @returns
*/
export function isJSExpression(data: any): data is IPublicTypeJSExpression {
return data && data.type === 'JSExpression' && data.extType !== 'function';
if (!isObject(data)) {
return false;
}
return data.type === 'JSExpression' && data.extType !== 'function';
}

View File

@ -1,5 +1,9 @@
import { IPublicTypeJSSlot } from '@alilc/lowcode-types';
import { isObject } from '../is-object';
export function isJSSlot(data: any): data is IPublicTypeJSSlot {
return data && data.type === 'JSSlot';
if (!isObject(data)) {
return false;
}
return data.type === 'JSSlot';
}

View File

@ -1,5 +1,9 @@
import { IPublicTypeLocationChildrenDetail, IPublicTypeLocationDetailType } from '@alilc/lowcode-types';
import { isObject } from '../is-object';
export function isLocationChildrenDetail(obj: any): obj is IPublicTypeLocationChildrenDetail {
return obj && obj.type === IPublicTypeLocationDetailType.Children;
if (!isObject(obj)) {
return false;
}
return obj.type === IPublicTypeLocationDetailType.Children;
}

View File

@ -1,5 +1,9 @@
import { IPublicTypeLocationData } from '@alilc/lowcode-types';
import { isObject } from '../is-object';
export function isLocationData(obj: any): obj is IPublicTypeLocationData {
return obj && obj.target && obj.detail;
if (!isObject(obj)) {
return false;
}
return 'target' in obj && 'detail' in obj;
}

View File

@ -1,6 +1,15 @@
import { IPublicTypeComponentSchema, IPublicTypeProjectSchema } from "@alilc/lowcode-types";
import { isComponentSchema } from "./is-component-schema";
import { IPublicTypeComponentSchema, IPublicTypeProjectSchema } from '@alilc/lowcode-types';
import { isComponentSchema } from './is-component-schema';
import { isObject } from '../is-object';
export function isLowcodeProjectSchema(data: any): data is IPublicTypeProjectSchema<IPublicTypeComponentSchema> {
return data && data.componentsTree && data.componentsTree.length && isComponentSchema(data.componentsTree[0]);
if (!isObject(data)) {
return false;
}
if (!('componentsTree' in data) || data.componentsTree.length === 0) {
return false;
}
return isComponentSchema(data.componentsTree[0]);
}

View File

@ -1,5 +1,9 @@
import { IPublicTypeNodeSchema } from '@alilc/lowcode-types';
import { isObject } from '../is-object';
export function isNodeSchema(data: any): data is IPublicTypeNodeSchema {
return data && data.componentName && !data.isNode;
if (!isObject(data)) {
return false;
}
return 'componentName' in data && !data.isNode;
}

View File

@ -1,5 +1,9 @@
import { IPublicModelNode } from '@alilc/lowcode-types';
import { isObject } from '../is-object';
export function isNode<Node = IPublicModelNode>(node: any): node is Node {
return node && node.isNode;
if (!isObject(node)) {
return false;
}
return node.isNode;
}

View File

@ -0,0 +1,3 @@
export function isObject(obj: any): boolean {
return obj && typeof obj === 'object';
}

View File

@ -1,6 +1,10 @@
import { IPublicTypeComponentMap, IPublicTypeProCodeComponent } from '@alilc/lowcode-types';
import { isObject } from '../is-object';
export function isProCodeComponentType(desc: IPublicTypeComponentMap): desc is IPublicTypeProCodeComponent {
if (!isObject(desc)) {
return false;
}
return 'package' in desc;
}

View File

@ -1,5 +1,9 @@
import { IPublicTypeProjectSchema } from "@alilc/lowcode-types";
import { IPublicTypeProjectSchema } from '@alilc/lowcode-types';
import { isObject } from '../is-object';
export function isProjectSchema(data: any): data is IPublicTypeProjectSchema {
return data && data.componentsTree;
if (!isObject(data)) {
return false;
}
return 'componentsTree' in data;
}

View File

@ -1,7 +1,10 @@
import { IPublicTypeSetterConfig } from '@alilc/lowcode-types';
import { isCustomView } from './is-custom-view';
import { isObject } from '../is-object';
export function isSetterConfig(obj: any): obj is IPublicTypeSetterConfig {
return obj && typeof obj === 'object' && 'componentName' in obj && !isCustomView(obj);
if (!isObject(obj)) {
return false;
}
return 'componentName' in obj && !isCustomView(obj);
}

View File

@ -1,5 +1,10 @@
import { IPublicModelSettingField } from "@alilc/lowcode-types";
import { IPublicModelSettingField } from '@alilc/lowcode-types';
import { isObject } from '../is-object';
export function isSettingField(obj: any): obj is IPublicModelSettingField {
return obj && obj.isSettingField;
if (!isObject(obj)) {
return false;
}
return 'isSettingField' in obj && obj.isSettingField;
}

View File

@ -11,8 +11,8 @@ const excludePropertyNames = [
'arguments',
];
export function cloneEnumerableProperty(target: any, origin: any) {
const compExtraPropertyNames = Object.keys(origin).filter(d => !excludePropertyNames.includes(d));
export function cloneEnumerableProperty(target: any, origin: any, excludes = excludePropertyNames) {
const compExtraPropertyNames = Object.keys(origin).filter(d => !excludes.includes(d));
compExtraPropertyNames.forEach((d: string) => {
(target as any)[d] = origin[d];

View File

@ -1,4 +1,4 @@
export function isObject(value: any): value is Record<string, unknown> {
export function isObject(value: any): value is Record<string, any> {
return value !== null && typeof value === 'object';
}

View File

@ -2,27 +2,49 @@ import { ComponentClass, Component, FunctionComponent, ComponentType, createElem
import { cloneEnumerableProperty } from './clone-enumerable-property';
const hasSymbol = typeof Symbol === 'function' && Symbol.for;
const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
const REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3;
export const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
export const REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3;
export function isReactClass(obj: any): obj is ComponentClass<any> {
return obj && obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component);
if (!obj) {
return false;
}
if (obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component)) {
return true;
}
return false;
}
export function acceptsRef(obj: any): boolean {
return obj?.prototype?.isReactComponent || isForwardOrMemoForward(obj);
if (!obj) {
return false;
}
if (obj?.prototype?.isReactComponent || isForwardOrMemoForward(obj)) {
return true;
}
return false;
}
export function isForwardRefType(obj: any): boolean {
return obj?.$$typeof && obj?.$$typeof === REACT_FORWARD_REF_TYPE;
if (!obj || !obj?.$$typeof) {
return false;
}
return obj?.$$typeof === REACT_FORWARD_REF_TYPE;
}
function isMemoType(obj: any): boolean {
return obj?.$$typeof && obj.$$typeof === REACT_MEMO_TYPE;
export function isMemoType(obj: any): boolean {
if (!obj || !obj?.$$typeof) {
return false;
}
return obj.$$typeof === REACT_MEMO_TYPE;
}
export function isForwardOrMemoForward(obj: any): boolean {
return obj?.$$typeof && (
if (!obj || !obj?.$$typeof) {
return false;
}
return (
// React.forwardRef(..)
isForwardRefType(obj) ||
// React.memo(React.forwardRef(..))

View File

@ -88,7 +88,7 @@ const shouldOutput = (
const output = (logLevel: string, bizName: string) => {
return (...args: any[]) => {
return outputFunction[logLevel].apply(console, getLogArgs(args, bizName, logLevel));
return outputFunction[logLevel]?.apply(console, getLogArgs(args, bizName, logLevel));
};
};
@ -142,7 +142,6 @@ const defaultOptions: Options = {
bizName: '*',
};
class Logger {
bizName: string;
targetBizName: string;
@ -192,7 +191,6 @@ class Logger {
}
}
export { Logger };
export function getLogger(config: { level: Level; bizName: string }): Logger {

View File

@ -2,6 +2,9 @@
import { isI18NObject } from './is-object';
import { get } from 'lodash';
import { IPublicEnumTransformStage, IPublicModelComponentMeta } from '@alilc/lowcode-types';
import { Logger } from './logger';
const logger = new Logger({ level: 'warn', bizName: 'utils' });
interface Variable {
type: 'variable';
@ -10,7 +13,10 @@ interface Variable {
}
export function isVariable(obj: any): obj is Variable {
return obj && obj.type === 'variable';
if (!obj || typeof obj !== 'object') {
return false;
}
return obj.type === 'variable';
}
export function isUseI18NSetter(prototype: any, propName: string) {
@ -103,12 +109,15 @@ export function invariant(check: any, message: string, thing?: any) {
export function deprecate(fail: any, message: string, alterative?: string) {
if (fail) {
console.warn(`Deprecation: ${message}` + (alterative ? `, use ${alterative} instead.` : ''));
logger.warn(`Deprecation: ${message}` + (alterative ? `, use ${alterative} instead.` : ''));
}
}
export function isRegExp(obj: any): obj is RegExp {
return obj && obj.test && obj.exec && obj.compile;
if (!obj || typeof obj !== 'object') {
return false;
}
return 'test' in obj && 'exec' in obj && 'compile' in obj;
}
/**

View File

@ -1,4 +1,5 @@
let nativeSelectionEnabled = true;
export let nativeSelectionEnabled = true;
const preventSelection = (e: Event) => {
if (nativeSelectionEnabled) {
return null;

View File

@ -1,4 +1,7 @@
import { createDefer } from './create-defer';
import { Logger } from './logger';
const logger = new Logger({ level: 'warn', bizName: 'utils' });
export function evaluate(script: string, scriptType?: string) {
const scriptEl = document.createElement('script');
@ -53,7 +56,7 @@ export function newFunction(args: string, code: string) {
// eslint-disable-next-line no-new-func
return new Function(args, code);
} catch (e) {
console.warn('Caught error, Cant init func');
logger.warn('Caught error, Cant init func');
return null;
}
}

View File

@ -1,4 +1,4 @@
import { ReactNode } from 'react';
import React, { ReactNode } from 'react';
const SizePresets: any = {
xsmall: 8,

View File

@ -0,0 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`wrapReactClass should render the FunctionComponent with props 1`] = `
<FunctionComponent
prop1="value1"
prop2="value2"
>
Child Text
</FunctionComponent>
`;

View File

@ -1,342 +0,0 @@
import { buildComponents } from "../../../src/build-components";
function Button() {};
function WrapButton() {};
function ButtonGroup() {};
function WrapButtonGroup() {};
ButtonGroup.Button = Button;
Button.displayName = "Button";
ButtonGroup.displayName = "ButtonGroup";
ButtonGroup.prototype.isReactComponent = true;
Button.prototype.isReactComponent = true;
jest.mock('../../../src/is-react', () => {
const original = jest.requireActual('../../../src/is-react');
return {
...original,
wrapReactClass(view) {
return view;
}
}
})
describe('build-component', () => {
it('basic button', () => {
expect(
buildComponents(
{
'@alilc/button': {
Button,
}
},
{
Button: {
componentName: 'Button',
package: '@alilc/button',
destructuring: true,
exportName: 'Button',
subName: 'Button',
}
},
() => {},
))
.toEqual({
Button,
});
});
it('component is a __esModule', () => {
expect(
buildComponents(
{
'@alilc/button': {
__esModule: true,
default: Button,
}
},
{
Button: {
componentName: 'Button',
package: '@alilc/button',
}
},
() => {},
))
.toEqual({
Button,
});
})
it('basic warp button', () => {
expect(
buildComponents(
{
'@alilc/button': {
WrapButton,
}
},
{
WrapButton: {
componentName: 'WrapButton',
package: '@alilc/button',
destructuring: true,
exportName: 'WrapButton',
subName: 'WrapButton',
}
},
() => {},
))
.toEqual({
WrapButton,
});
});
it('destructuring is false button', () => {
expect(
buildComponents(
{
'@alilc/button': Button
},
{
Button: {
componentName: 'Button',
package: '@alilc/button',
destructuring: false,
}
},
() => {},
))
.toEqual({
Button,
});
});
it('Button and ButtonGroup', () => {
expect(
buildComponents(
{
'@alilc/button': {
Button,
ButtonGroup,
}
},
{
Button: {
componentName: 'Button',
package: '@alilc/button',
destructuring: true,
exportName: 'Button',
subName: 'Button',
},
ButtonGroup: {
componentName: 'ButtonGroup',
package: '@alilc/button',
destructuring: true,
exportName: 'ButtonGroup',
subName: 'ButtonGroup',
}
},
() => {},
))
.toEqual({
Button,
ButtonGroup,
});
});
it('ButtonGroup and ButtonGroup.Button', () => {
expect(
buildComponents(
{
'@alilc/button': {
ButtonGroup,
}
},
{
Button: {
componentName: 'Button',
package: '@alilc/button',
destructuring: true,
exportName: 'ButtonGroup',
subName: 'ButtonGroup.Button',
},
ButtonGroup: {
componentName: 'ButtonGroup',
package: '@alilc/button',
destructuring: true,
exportName: 'ButtonGroup',
subName: 'ButtonGroup',
}
},
() => {},
))
.toEqual({
Button,
ButtonGroup,
});
});
it('ButtonGroup.default and ButtonGroup.Button', () => {
expect(
buildComponents(
{
'@alilc/button': ButtonGroup,
},
{
Button: {
componentName: 'Button',
package: '@alilc/button',
destructuring: true,
exportName: 'Button',
subName: 'Button',
},
ButtonGroup: {
componentName: 'ButtonGroup',
package: '@alilc/button',
destructuring: true,
exportName: 'default',
subName: 'default',
}
},
() => {},
))
.toEqual({
Button,
ButtonGroup,
});
});
it('no npm component', () => {
expect(
buildComponents(
{
'@alilc/button': Button,
},
{
Button: null,
},
() => {},
))
.toEqual({});
});
it('no npm component and global button', () => {
window.Button = Button;
expect(
buildComponents(
{},
{
Button: null,
},
() => {},
))
.toEqual({
Button,
});
window.Button = null;
});
it('componentsMap value is component funtion', () => {
expect(
buildComponents(
{},
{
Button,
},
() => {},
))
.toEqual({
Button,
});
});
it('componentsMap value is component', () => {
expect(
buildComponents(
{},
{
Button: WrapButton,
},
() => {},
))
.toEqual({
Button: WrapButton,
});
});
it('componentsMap value is mix component', () => {
expect(
buildComponents(
{},
{
Button: {
WrapButton,
Button,
ButtonGroup,
},
},
() => {},
))
.toEqual({
Button: {
WrapButton,
Button,
ButtonGroup,
},
});
});
it('componentsMap value is Lowcode Component', () => {
expect(
buildComponents(
{},
{
Button: {
componentName: 'Component',
schema: {},
},
},
(component) => {
return component as any;
},
))
.toEqual({
Button: {
componentsMap: [],
componentsTree: [
{
componentName: 'Component',
schema: {},
}
],
version: "",
},
});
})
});
describe('build div component', () => {
it('build div component', () => {
const components = buildComponents(
{
'@alilc/div': 'div'
},
{
div: {
componentName: 'div',
package: '@alilc/div'
}
},
() => {},
);
expect(components['div']).not.toBeNull();
})
})

View File

@ -0,0 +1,616 @@
import React from 'react';
import {
accessLibrary,
generateHtmlComp,
getSubComponent,
buildComponents,
getProjectUtils,
} from "../../../src/build-components";
function Button() {};
function WrapButton() {};
function ButtonGroup() {};
function WrapButtonGroup() {};
ButtonGroup.Button = Button;
Button.displayName = "Button";
ButtonGroup.displayName = "ButtonGroup";
ButtonGroup.prototype.isReactComponent = true;
Button.prototype.isReactComponent = true;
jest.mock('../../../src/is-react', () => {
const original = jest.requireActual('../../../src/is-react');
return {
...original,
wrapReactClass(view) {
return view;
}
}
});
describe('accessLibrary', () => {
it('should return a library object when given a library object', () => {
const libraryObject = { key: 'value' };
const result = accessLibrary(libraryObject);
expect(result).toEqual(libraryObject);
});
it('should generate an HTML component when given a string library name', () => {
const libraryName = 'div';
const result = accessLibrary(libraryName);
// You can write more specific assertions to validate the generated component
expect(result).toBeDefined();
});
// Add more test cases to cover other scenarios
});
describe('generateHtmlComp', () => {
it('should generate an HTML component for valid HTML tags', () => {
const htmlTags = ['a', 'img', 'div', 'span', 'svg'];
htmlTags.forEach((tag) => {
const result = generateHtmlComp(tag);
// You can write more specific assertions to validate the generated component
expect(result).toBeDefined();
});
});
it('should return undefined for an invalid HTML tag', () => {
const invalidTag = 'invalidtag';
const result = generateHtmlComp(invalidTag);
expect(result).toBeUndefined();
});
// Add more test cases to cover other scenarios
});
describe('getSubComponent', () => {
it('should return the root library if paths are empty', () => {
const library = { component: 'RootComponent' };
const paths = [];
const result = getSubComponent(library, paths);
expect(result).toEqual(library);
});
it('should return the specified sub-component', () => {
const library = {
components: {
Button: 'ButtonComponent',
Text: 'TextComponent',
},
};
const paths = ['components', 'Button'];
const result = getSubComponent(library, paths);
expect(result).toEqual('ButtonComponent');
});
it('should handle missing keys in the path', () => {
const library = {
components: {
Button: 'ButtonComponent',
},
};
const paths = ['components', 'Text'];
const result = getSubComponent(library, paths);
expect(result).toEqual({
Button: 'ButtonComponent',
});
});
it('should handle exceptions and return null', () => {
const library = 'ButtonComponent';
const paths = ['components', 'Button'];
// Simulate an exception by providing a non-object in place of 'ButtonComponent'
const result = getSubComponent(library, paths);
expect(result).toBeNull();
});
it('should handle the "default" key as the first path element', () => {
const library = {
default: 'DefaultComponent',
};
const paths = ['default'];
const result = getSubComponent(library, paths);
expect(result).toEqual('DefaultComponent');
});
});
describe('getProjectUtils', () => {
it('should return an empty object when given empty metadata and library map', () => {
const libraryMap = {};
const utilsMetadata = [];
const result = getProjectUtils(libraryMap, utilsMetadata);
expect(result).toEqual({});
});
it('should return project utilities based on metadata and library map', () => {
const libraryMap = {
'package1': 'library1',
'package2': 'library2',
};
const utilsMetadata = [
{
name: 'util1',
npm: {
package: 'package1',
},
},
{
name: 'util2',
npm: {
package: 'package2',
},
},
];
global['library1'] = { name: 'library1' };
global['library2'] = { name: 'library2' };
const result = getProjectUtils(libraryMap, utilsMetadata);
// Define the expected output based on the mocked accessLibrary
const expectedOutput = {
'util1': { name: 'library1' },
'util2': { name: 'library2' },
};
expect(result).toEqual(expectedOutput);
global['library1'] = null;
global['library1'] = null;
});
it('should handle metadata with destructuring', () => {
const libraryMap = {
'package1': { destructuring: true, util1: 'library1', util2: 'library2' },
};
const utilsMetadata = [
{
name: 'util1',
npm: {
package: 'package1',
destructuring: true,
},
},
];
const result = getProjectUtils(libraryMap, utilsMetadata);
// Define the expected output based on the mocked accessLibrary
const expectedOutput = {
'util1': 'library1',
'util2': 'library2',
};
expect(result).toEqual(expectedOutput);
});
});
describe('buildComponents', () => {
it('should create components from component map with React components', () => {
const libraryMap = {};
const componentsMap = {
Button: () => <button>Button</button>,
Text: () => <p>Text</p>,
};
const createComponent = (schema) => {
// Mock createComponent function
return schema.componentsTree.map((component) => component.component);
};
const result = buildComponents(libraryMap, componentsMap, createComponent);
expect(result.Button).toBeDefined();
expect(result.Text).toBeDefined();
});
it('should create components from component map with component schemas', () => {
const libraryMap = {};
const componentsMap = {
Button: {
componentsTree: [
{
componentName: 'Component'
}
]
},
Text: {
componentsTree: [
{
componentName: 'Component'
}
]
},
};
const createComponent = (schema) => {
// Mock createComponent function
return schema.componentsTree.map((component) => component.component);
};
const result = buildComponents(libraryMap, componentsMap, createComponent);
expect(result.Button).toBeDefined();
expect(result.Text).toBeDefined();
});
it('should create components from component map with React components and schemas', () => {
const libraryMap = {};
const componentsMap = {
Button: () => <button>Button</button>,
Text: {
type: 'ComponentSchema',
// Add component schema properties here
},
};
const createComponent = (schema) => {
// Mock createComponent function
return schema.componentsTree.map((component) => component.component);
};
const result = buildComponents(libraryMap, componentsMap, createComponent);
expect(result.Button).toBeDefined();
expect(result.Text).toBeDefined();
});
it('should create components from component map with library mappings', () => {
const libraryMap = {
'libraryName1': 'library1',
'libraryName2': 'library2',
};
const componentsMap = {
Button: {
package: 'libraryName1',
version: '1.0',
exportName: 'ButtonComponent',
},
Text: {
package: 'libraryName2',
version: '2.0',
exportName: 'TextComponent',
},
};
const createComponent = (schema) => {
// Mock createComponent function
return schema.componentsTree.map((component) => component.component);
};
global['library1'] = () => <button>ButtonComponent</button>;
global['library2'] = () => () => <p>TextComponent</p>;
const result = buildComponents(libraryMap, componentsMap, createComponent);
expect(result.Button).toBeDefined();
expect(result.Text).toBeDefined();
global['library1'] = null;
global['library2'] = null;
});
});
describe('build-component', () => {
it('basic button', () => {
expect(
buildComponents(
{
'@alilc/button': {
Button,
}
},
{
Button: {
componentName: 'Button',
package: '@alilc/button',
destructuring: true,
exportName: 'Button',
subName: 'Button',
}
},
() => {},
))
.toEqual({
Button,
});
});
it('component is a __esModule', () => {
expect(
buildComponents(
{
'@alilc/button': {
__esModule: true,
default: Button,
}
},
{
Button: {
componentName: 'Button',
package: '@alilc/button',
}
},
() => {},
))
.toEqual({
Button,
});
})
it('basic warp button', () => {
expect(
buildComponents(
{
'@alilc/button': {
WrapButton,
}
},
{
WrapButton: {
componentName: 'WrapButton',
package: '@alilc/button',
destructuring: true,
exportName: 'WrapButton',
subName: 'WrapButton',
}
},
() => {},
))
.toEqual({
WrapButton,
});
});
it('destructuring is false button', () => {
expect(
buildComponents(
{
'@alilc/button': Button
},
{
Button: {
componentName: 'Button',
package: '@alilc/button',
destructuring: false,
}
},
() => {},
))
.toEqual({
Button,
});
});
it('Button and ButtonGroup', () => {
expect(
buildComponents(
{
'@alilc/button': {
Button,
ButtonGroup,
}
},
{
Button: {
componentName: 'Button',
package: '@alilc/button',
destructuring: true,
exportName: 'Button',
subName: 'Button',
},
ButtonGroup: {
componentName: 'ButtonGroup',
package: '@alilc/button',
destructuring: true,
exportName: 'ButtonGroup',
subName: 'ButtonGroup',
}
},
() => {},
))
.toEqual({
Button,
ButtonGroup,
});
});
it('ButtonGroup and ButtonGroup.Button', () => {
expect(
buildComponents(
{
'@alilc/button': {
ButtonGroup,
}
},
{
Button: {
componentName: 'Button',
package: '@alilc/button',
destructuring: true,
exportName: 'ButtonGroup',
subName: 'ButtonGroup.Button',
},
ButtonGroup: {
componentName: 'ButtonGroup',
package: '@alilc/button',
destructuring: true,
exportName: 'ButtonGroup',
subName: 'ButtonGroup',
}
},
() => {},
))
.toEqual({
Button,
ButtonGroup,
});
});
it('ButtonGroup.default and ButtonGroup.Button', () => {
expect(
buildComponents(
{
'@alilc/button': ButtonGroup,
},
{
Button: {
componentName: 'Button',
package: '@alilc/button',
destructuring: true,
exportName: 'Button',
subName: 'Button',
},
ButtonGroup: {
componentName: 'ButtonGroup',
package: '@alilc/button',
destructuring: true,
exportName: 'default',
subName: 'default',
}
},
() => {},
))
.toEqual({
Button,
ButtonGroup,
});
});
it('no npm component', () => {
expect(
buildComponents(
{
'@alilc/button': Button,
},
{
Button: null,
},
() => {},
))
.toEqual({});
});
it('no npm component and global button', () => {
window.Button = Button;
expect(
buildComponents(
{},
{
Button: null,
},
() => {},
))
.toEqual({
Button,
});
window.Button = null;
});
it('componentsMap value is component funtion', () => {
expect(
buildComponents(
{},
{
Button,
},
() => {},
))
.toEqual({
Button,
});
});
it('componentsMap value is component', () => {
expect(
buildComponents(
{},
{
Button: WrapButton,
},
() => {},
))
.toEqual({
Button: WrapButton,
});
});
it('componentsMap value is mix component', () => {
expect(
buildComponents(
{},
{
Button: {
WrapButton,
Button,
ButtonGroup,
},
},
() => {},
))
.toEqual({
Button: {
WrapButton,
Button,
ButtonGroup,
},
});
});
it('componentsMap value is Lowcode Component', () => {
expect(
buildComponents(
{},
{
Button: {
componentName: 'Component',
schema: {},
},
},
(component) => {
return component as any;
},
))
.toEqual({
Button: {
componentsMap: [],
componentsTree: [
{
componentName: 'Component',
schema: {},
}
],
version: "",
},
});
})
});
describe('build div component', () => {
it('build div component', () => {
const components = buildComponents(
{
'@alilc/div': 'div'
},
{
div: {
componentName: 'div',
package: '@alilc/div'
}
},
() => {},
);
expect(components['div']).not.toBeNull();
})
})

View File

@ -0,0 +1,20 @@
import { isActionContentObject } from '../../../src/check-types/is-action-content-object';
describe('isActionContentObject', () => {
test('should return true for an object', () => {
const obj = { prop: 'value' };
expect(isActionContentObject(obj)).toBe(true);
});
test('should return false for a non-object', () => {
expect(isActionContentObject('not an object')).toBe(false);
expect(isActionContentObject(123)).toBe(false);
expect(isActionContentObject(null)).toBe(false);
expect(isActionContentObject(undefined)).toBe(false);
});
test('should return false for an empty object', () => {
const obj = {};
expect(isActionContentObject(obj)).toBe(true);
});
});

View File

@ -0,0 +1,26 @@
import React from 'react';
import { isCustomView } from '../../../src/check-types/is-custom-view';
import { IPublicTypeCustomView } from '@alilc/lowcode-types';
describe('isCustomView', () => {
test('should return true when obj is a valid React element', () => {
const obj: IPublicTypeCustomView = <div>Hello, World!</div>;
expect(isCustomView(obj)).toBe(true);
});
test('should return true when obj is a valid React component', () => {
const MyComponent: React.FC = () => <div>Hello, World!</div>;
const obj: IPublicTypeCustomView = MyComponent;
expect(isCustomView(obj)).toBe(true);
});
test('should return false when obj is null or undefined', () => {
expect(isCustomView(null)).toBe(false);
expect(isCustomView(undefined)).toBe(false);
});
test('should return false when obj is not a valid React element or component', () => {
const obj: IPublicTypeCustomView = 'not a valid object';
expect(isCustomView(obj)).toBe(false);
});
});

View File

@ -0,0 +1,13 @@
import { isDOMText } from '../../../src/check-types/is-dom-text';
describe('isDOMText', () => {
it('should return true when the input is a string', () => {
const result = isDOMText('Hello World');
expect(result).toBe(true);
});
it('should return false when the input is not a string', () => {
const result = isDOMText(123);
expect(result).toBe(false);
});
});

View File

@ -0,0 +1,32 @@
import { isDragAnyObject } from '../../../src/check-types/is-drag-any-object';
import { IPublicEnumDragObjectType } from '@alilc/lowcode-types';
describe('isDragAnyObject', () => {
it('should return false if obj is null', () => {
const result = isDragAnyObject(null);
expect(result).toBe(false);
});
it('should return false if obj is number', () => {
const result = isDragAnyObject(2);
expect(result).toBe(false);
});
it('should return false if obj.type is NodeData', () => {
const obj = { type: IPublicEnumDragObjectType.NodeData };
const result = isDragAnyObject(obj);
expect(result).toBe(false);
});
it('should return false if obj.type is Node', () => {
const obj = { type: IPublicEnumDragObjectType.Node };
const result = isDragAnyObject(obj);
expect(result).toBe(false);
});
it('should return true if obj.type is anything else', () => {
const obj = { type: 'SomeOtherType' };
const result = isDragAnyObject(obj);
expect(result).toBe(true);
});
});

View File

@ -0,0 +1,29 @@
import { IPublicEnumDragObjectType, IPublicTypeDragNodeDataObject } from '@alilc/lowcode-types';
import { isDragNodeDataObject } from '../../../src/check-types/is-drag-node-data-object';
describe('isDragNodeDataObject', () => {
test('should return true for valid IPublicTypeDragNodeDataObject', () => {
const obj: IPublicTypeDragNodeDataObject = {
type: IPublicEnumDragObjectType.NodeData,
// 其他属性...
};
expect(isDragNodeDataObject(obj)).toBe(true);
});
test('should return false for invalid IPublicTypeDragNodeDataObject', () => {
const obj: any = {
type: 'InvalidType',
// 其他属性...
};
expect(isDragNodeDataObject(obj)).toBe(false);
});
test('should return false for null or undefined', () => {
expect(isDragNodeDataObject(null)).toBe(false);
expect(isDragNodeDataObject(undefined)).toBe(false);
});
// 可以添加更多测试用例...
});

View File

@ -0,0 +1,36 @@
import { IPublicEnumDragObjectType } from '@alilc/lowcode-types';
import { isDragNodeObject } from '../../../src/check-types/is-drag-node-object';
describe('isDragNodeObject', () => {
it('should return true if the object is of IPublicTypeDragNodeObject type and has type IPublicEnumDragObjectType.Node', () => {
const obj = {
type: IPublicEnumDragObjectType.Node,
//... other properties
};
expect(isDragNodeObject(obj)).toBe(true);
});
it('should return false if the object is not of IPublicTypeDragNodeObject type', () => {
const obj = {
type: IPublicEnumDragObjectType.OtherType,
//... other properties
};
expect(isDragNodeObject(obj)).toBe(false);
});
it('should return false if the object is of IPublicTypeDragNodeObject type but type is not IPublicEnumDragObjectType.Node', () => {
const obj = {
type: IPublicEnumDragObjectType.OtherType,
//... other properties
};
expect(isDragNodeObject(obj)).toBe(false);
});
it('should return false if the object is null or undefined', () => {
expect(isDragNodeObject(null)).toBe(false);
expect(isDragNodeObject(undefined)).toBe(false);
});
});

View File

@ -0,0 +1,28 @@
import { Component } from 'react';
import { isDynamicSetter } from '../../../src/check-types/is-dynamic-setter';
describe('isDynamicSetter', () => {
it('returns true if input is a dynamic setter function', () => {
const dynamicSetter = (value: any) => {
// some implementation
};
expect(isDynamicSetter(dynamicSetter)).toBeTruthy();
});
it('returns false if input is not a dynamic setter function', () => {
expect(isDynamicSetter('not a function')).toBeFalsy();
expect(isDynamicSetter(null)).toBeFalsy();
expect(isDynamicSetter(undefined)).toBeFalsy();
expect(isDynamicSetter(2)).toBeFalsy();
expect(isDynamicSetter(0)).toBeFalsy();
});
it('returns false if input is a React class', () => {
class ReactClass extends Component {
// some implementation
}
expect(isDynamicSetter(ReactClass)).toBeFalsy();
});
});

View File

@ -0,0 +1,27 @@
import { isI18nData } from '../../../src/check-types/is-i18n-data';
import { IPublicTypeI18nData } from "@alilc/lowcode-types";
describe('isI18nData', () => {
it('should return true for valid i18n data', () => {
const i18nData: IPublicTypeI18nData = {
type: 'i18n',
// add any other required properties here
};
expect(isI18nData(i18nData)).toBe(true);
});
it('should return false for invalid i18n data', () => {
const invalidData = {
type: 'some-other-type',
// add any other properties here
};
expect(isI18nData(invalidData)).toBe(false);
});
it('should return false for undefined or null', () => {
expect(isI18nData(undefined)).toBe(false);
expect(isI18nData(null)).toBe(false);
});
});

View File

@ -0,0 +1,61 @@
import { isInnerJsFunction, isJSFunction } from '../../../src/check-types/is-isfunction';
describe('isInnerJsFunction', () => {
test('should return true for valid input', () => {
const data = {
type: 'JSExpression',
source: '',
value: '',
extType: 'function'
};
expect(isInnerJsFunction(data)).toBe(true);
});
test('should return false for invalid input', () => {
const data = {
type: 'JSExpression',
source: '',
value: '',
extType: 'object'
};
expect(isInnerJsFunction(data)).toBe(false);
expect(isInnerJsFunction(null)).toBe(false);
expect(isInnerJsFunction(undefined)).toBe(false);
expect(isInnerJsFunction(1)).toBe(false);
expect(isInnerJsFunction(0)).toBe(false);
expect(isInnerJsFunction('string')).toBe(false);
expect(isInnerJsFunction('')).toBe(false);
});
});
describe('isJSFunction', () => {
test('should return true for valid input', () => {
const data = {
type: 'JSFunction',
};
expect(isJSFunction(data)).toBe(true);
});
test('should return true for inner js function', () => {
const data = {
type: 'JSExpression',
source: '',
value: '',
extType: 'function'
};
expect(isJSFunction(data)).toBe(true);
});
test('should return false for invalid input', () => {
expect(isJSFunction(null)).toBe(false);
expect(isJSFunction(undefined)).toBe(false);
expect(isJSFunction('string')).toBe(false);
expect(isJSFunction('')).toBe(false);
expect(isJSFunction(0)).toBe(false);
expect(isJSFunction(2)).toBe(false);
});
});

View File

@ -0,0 +1,22 @@
import { isJSBlock } from '../../../src/check-types/is-jsblock';
describe('isJSBlock', () => {
it('should return false if data is null or undefined', () => {
expect(isJSBlock(null)).toBe(false);
expect(isJSBlock(undefined)).toBe(false);
});
it('should return false if data is not an object', () => {
expect(isJSBlock('JSBlock')).toBe(false);
expect(isJSBlock(123)).toBe(false);
expect(isJSBlock(true)).toBe(false);
});
it('should return false if data.type is not "JSBlock"', () => {
expect(isJSBlock({ type: 'InvalidType' })).toBe(false);
});
it('should return true if data is an object and data.type is "JSBlock"', () => {
expect(isJSBlock({ type: 'JSBlock' })).toBe(true);
});
});

View File

@ -0,0 +1,39 @@
import { isJSExpression } from '../../../src/check-types/is-jsexpression';
describe('isJSExpression', () => {
it('should return true if the input is a valid JSExpression object', () => {
const validJSExpression = {
type: 'JSExpression',
extType: 'variable',
};
const result = isJSExpression(validJSExpression);
expect(result).toBe(true);
});
it('should return false if the input is not a valid JSExpression object', () => {
const invalidJSExpression = {
type: 'JSExpression',
extType: 'function',
};
const result = isJSExpression(invalidJSExpression);
expect(result).toBe(false);
});
it('should return false if the input is null', () => {
const result = isJSExpression(null);
expect(result).toBe(false);
});
it('should return false if the input is undefined', () => {
const result = isJSExpression(undefined);
expect(result).toBe(false);
});
// 添加其他需要的测试
});

View File

@ -0,0 +1,37 @@
import { isJSSlot } from '../../../src/check-types/is-jsslot';
import { IPublicTypeJSSlot } from '@alilc/lowcode-types';
describe('isJSSlot', () => {
it('should return true when input is of type IPublicTypeJSSlot', () => {
const input: IPublicTypeJSSlot = {
type: 'JSSlot',
// other properties of IPublicTypeJSSlot
};
const result = isJSSlot(input);
expect(result).toBe(true);
});
it('should return false when input is not of type IPublicTypeJSSlot', () => {
const input = {
type: 'OtherType',
// other properties
};
const result = isJSSlot(input);
expect(result).toBe(false);
});
it('should return false when input is null or undefined', () => {
const input1 = null;
const input2 = undefined;
const result1 = isJSSlot(input1);
const result2 = isJSSlot(input2);
expect(result1).toBe(false);
expect(result2).toBe(false);
});
});

View File

@ -0,0 +1,27 @@
import { isLocationChildrenDetail } from '../../../src/check-types/is-location-children-detail';
import { IPublicTypeLocationChildrenDetail, IPublicTypeLocationDetailType } from '@alilc/lowcode-types';
describe('isLocationChildrenDetail', () => {
it('should return true when obj is IPublicTypeLocationChildrenDetail', () => {
const obj: IPublicTypeLocationChildrenDetail = {
type: IPublicTypeLocationDetailType.Children,
// 添加其他必要的属性
};
expect(isLocationChildrenDetail(obj)).toBe(true);
});
it('should return false when obj is not IPublicTypeLocationChildrenDetail', () => {
const obj = {
type: 'other',
// 添加其他必要的属性
};
expect(isLocationChildrenDetail(obj)).toBe(false);
expect(isLocationChildrenDetail(null)).toBe(false);
expect(isLocationChildrenDetail(undefined)).toBe(false);
expect(isLocationChildrenDetail('string')).toBe(false);
expect(isLocationChildrenDetail(0)).toBe(false);
expect(isLocationChildrenDetail(2)).toBe(false);
});
});

View File

@ -0,0 +1,44 @@
import { isLocationData } from '../../../src/check-types/is-location-data';
import { IPublicTypeLocationData } from '@alilc/lowcode-types';
describe('isLocationData', () => {
it('should return true when obj is valid location data', () => {
const obj: IPublicTypeLocationData = {
target: 'some target',
detail: 'some detail',
};
const result = isLocationData(obj);
expect(result).toBe(true);
});
it('should return false when obj is missing target or detail', () => {
const obj1 = {
target: 'some target',
// missing detail
};
const obj2 = {
// missing target
detail: 'some detail',
};
const result1 = isLocationData(obj1);
const result2 = isLocationData(obj2);
expect(result1).toBe(false);
expect(result2).toBe(false);
});
it('should return false when obj is null or undefined', () => {
const obj1 = null;
const obj2 = undefined;
const result1 = isLocationData(obj1);
const result2 = isLocationData(obj2);
expect(result1).toBe(false);
expect(result2).toBe(false);
});
});

View File

@ -0,0 +1,21 @@
import { isLowCodeComponentType } from '../../../src/check-types/is-lowcode-component-type';
import { IPublicTypeLowCodeComponent, IPublicTypeProCodeComponent } from '@alilc/lowcode-types';
describe('isLowCodeComponentType', () => {
test('should return true for a low code component type', () => {
const desc: IPublicTypeLowCodeComponent = {
// create a valid low code component description
};
expect(isLowCodeComponentType(desc)).toBe(true);
});
test('should return false for a pro code component type', () => {
const desc: IPublicTypeProCodeComponent = {
// create a valid pro code component description
package: 'pro-code'
};
expect(isLowCodeComponentType(desc)).toBe(false);
});
});

View File

@ -0,0 +1,42 @@
import { isLowcodeProjectSchema } from "../../../src/check-types/is-lowcode-project-schema";
describe("isLowcodeProjectSchema", () => {
it("should return false when data is null", () => {
const result = isLowcodeProjectSchema(null);
expect(result).toBe(false);
});
it("should return false when data is undefined", () => {
const result = isLowcodeProjectSchema(undefined);
expect(result).toBe(false);
});
it("should return false when data is not an object", () => {
const result = isLowcodeProjectSchema("not an object");
expect(result).toBe(false);
});
it("should return false when componentsTree is missing", () => {
const data = { someKey: "someValue" };
const result = isLowcodeProjectSchema(data);
expect(result).toBe(false);
});
it("should return false when componentsTree is an empty array", () => {
const data = { componentsTree: [] };
const result = isLowcodeProjectSchema(data);
expect(result).toBe(false);
});
it("should return false when the first element of componentsTree is not a component schema", () => {
const data = { componentsTree: [{}] };
const result = isLowcodeProjectSchema(data);
expect(result).toBe(false);
});
it("should return true when all conditions are met", () => {
const data = { componentsTree: [{ prop: "value", componentName: 'Component' }] };
const result = isLowcodeProjectSchema(data);
expect(result).toBe(true);
});
});

View File

@ -0,0 +1,43 @@
import { isNodeSchema } from '../../../src/check-types/is-node-schema';
describe('isNodeSchema', () => {
// 测试正常情况
it('should return true for valid IPublicTypeNodeSchema', () => {
const validData = {
componentName: 'Component',
isNode: false,
};
expect(isNodeSchema(validData)).toBe(true);
});
// 测试 null 或 undefined
it('should return false for null or undefined', () => {
expect(isNodeSchema(null)).toBe(false);
expect(isNodeSchema(undefined)).toBe(false);
});
// 测试没有componentName属性的情况
it('should return false if componentName is missing', () => {
const invalidData = {
isNode: false,
};
expect(isNodeSchema(invalidData)).toBe(false);
});
// 测试isNode为true的情况
it('should return false if isNode is true', () => {
const invalidData = {
componentName: 'Component',
isNode: true,
};
expect(isNodeSchema(invalidData)).toBe(false);
});
// 测试其他数据类型的情况
it('should return false for other data types', () => {
expect(isNodeSchema('string')).toBe(false);
expect(isNodeSchema(123)).toBe(false);
expect(isNodeSchema([])).toBe(false);
expect(isNodeSchema({})).toBe(false);
});
});

View File

@ -0,0 +1,19 @@
import { isNode } from '../../../src/check-types/is-node';
describe('isNode', () => {
it('should return true for a valid node', () => {
const node = { isNode: true };
expect(isNode(node)).toBeTruthy();
});
it('should return false for an invalid node', () => {
const node = { isNode: false };
expect(isNode(node)).toBeFalsy();
});
it('should return false for an undefined node', () => {
expect(isNode(undefined)).toBeFalsy();
});
// Add more test cases if needed
});

View File

@ -0,0 +1,13 @@
import { isProCodeComponentType } from '../../../src/check-types/is-procode-component-type';
describe('isProCodeComponentType', () => {
it('should return true if the given desc object contains "package" property', () => {
const desc = { package: 'packageName' };
expect(isProCodeComponentType(desc)).toBe(true);
});
it('should return false if the given desc object does not contain "package" property', () => {
const desc = { name: 'componentName' };
expect(isProCodeComponentType(desc)).toBe(false);
});
});

View File

@ -0,0 +1,28 @@
import { IPublicTypeProjectSchema } from "@alilc/lowcode-types";
import { isProjectSchema } from "../../../src/check-types/is-project-schema";
describe("isProjectSchema", () => {
it("should return true if data has componentsTree property", () => {
const data: IPublicTypeProjectSchema = {
// ...
componentsTree: {
// ...
},
};
expect(isProjectSchema(data)).toBe(true);
});
it("should return false if data does not have componentsTree property", () => {
const data = {
// ...
};
expect(isProjectSchema(data)).toBe(false);
});
it("should return false if data is null or undefined", () => {
expect(isProjectSchema(null)).toBe(false);
expect(isProjectSchema(undefined)).toBe(false);
});
// 更多的测试用例...
});

View File

@ -0,0 +1,26 @@
import { isSetterConfig } from '../../../src/check-types/is-setter-config';
describe('isSetterConfig', () => {
test('should return true for valid setter config', () => {
const config = {
componentName: 'MyComponent',
// Add other required properties here
};
expect(isSetterConfig(config)).toBe(true);
});
test('should return false for invalid setter config', () => {
const config = {
// Missing componentName property
};
expect(isSetterConfig(config)).toBe(false);
expect(isSetterConfig(null)).toBe(false);
expect(isSetterConfig(undefined)).toBe(false);
expect(isSetterConfig(0)).toBe(false);
expect(isSetterConfig(2)).toBe(false);
});
// Add more test cases for different scenarios you want to cover
});

View File

@ -0,0 +1,18 @@
import { isSettingField } from "../../../src/check-types/is-setting-field";
describe("isSettingField", () => {
it("should return true for an object that has isSettingField property", () => {
const obj = { isSettingField: true };
expect(isSettingField(obj)).toBe(true);
});
it("should return false for an object that does not have isSettingField property", () => {
const obj = { foo: "bar" };
expect(isSettingField(obj)).toBe(false);
});
it("should return false for a falsy value", () => {
const obj = null;
expect(isSettingField(obj)).toBe(false);
});
});

View File

@ -0,0 +1,18 @@
import { isTitleConfig } from '../../../src/check-types/is-title-config';
describe('isTitleConfig', () => {
it('should return true for valid config object', () => {
const config = { title: 'My Title' };
expect(isTitleConfig(config)).toBe(true);
});
it('should return false for invalid config object', () => {
const config = { title: 'My Title', type: 'i18n' , i18nData: {} };
expect(isTitleConfig(config)).toBe(false);
});
it('should return false for non-object input', () => {
const config = 'invalid';
expect(isTitleConfig(config)).toBe(false);
});
});

View File

@ -0,0 +1,30 @@
import { cloneDeep } from '../../src/clone-deep';
describe('cloneDeep', () => {
it('should clone null', () => {
const src = null;
expect(cloneDeep(src)).toBeNull();
});
it('should clone undefined', () => {
const src = undefined;
expect(cloneDeep(src)).toBeUndefined();
});
it('should clone an array', () => {
const src = [1, 2, 3, 4];
expect(cloneDeep(src)).toEqual(src);
});
it('should clone an object', () => {
const src = { name: 'John', age: 25 };
expect(cloneDeep(src)).toEqual(src);
});
it('should deep clone nested objects', () => {
const src = { person: { name: 'John', age: 25 } };
const cloned = cloneDeep(src);
expect(cloned).toEqual(src);
expect(cloned.person).not.toBe(src.person);
});
});

View File

@ -0,0 +1,30 @@
import { cloneEnumerableProperty } from '../../src/clone-enumerable-property';
describe('cloneEnumerableProperty', () => {
test('should clone enumerable properties from origin to target', () => {
// Arrange
const target = {};
const origin = { prop1: 1, prop2: 'hello', prop3: true };
// Act
const result = cloneEnumerableProperty(target, origin);
// Assert
expect(result).toBe(target);
expect(result).toEqual(origin);
});
test('should exclude properties specified in excludePropertyNames', () => {
// Arrange
const target = {};
const origin = { prop1: 1, prop2: 'hello', prop3: true };
const excludePropertyNames = ['prop2'];
// Act
const result = cloneEnumerableProperty(target, origin, excludePropertyNames);
// Assert
expect(result).toBe(target);
expect(result).toEqual({ prop1: 1, prop3: true });
});
});

View File

@ -0,0 +1,38 @@
import React from 'react';
import { createContent } from '../../src/create-content';
const MyComponent = () => {
return <div>MyComponent</div>
}
describe('createContent', () => {
test('should return the same content if it is a valid React element', () => {
const content = <div>Hello</div>;
const result = createContent(content);
expect(result).toEqual(content);
});
test('should clone the element with props if props are provided', () => {
const content = <div></div>;
const props = { className: 'my-class' };
const result = createContent(content, props);
expect(result.props).toEqual(props);
});
test('should create an element with props if the content is a React component', () => {
const content = MyComponent;
const props = { className: 'my-class' };
const result = createContent(content, props);
expect(result.type).toEqual(content);
expect(result.props).toEqual(props);
});
test('should return the content if it is not a React element or a React component', () => {
const content = 'Hello';
const result = createContent(content);
expect(result).toEqual(content);
});
});

View File

@ -0,0 +1,16 @@
import { createDefer } from '../../src/create-defer';
describe('createDefer', () => {
it('should resolve with given value', async () => {
const defer = createDefer<number>();
defer.resolve(42);
const result = await defer.promise();
expect(result).toBe(42);
});
it('should reject with given reason', async () => {
const defer = createDefer<number>();
defer.reject('error');
await expect(defer.promise()).rejects.toEqual('error');
});
});

View File

@ -0,0 +1,45 @@
import { isObject, isI18NObject } from '../../src/is-object';
describe('isObject', () => {
it('should return true for an object', () => {
const obj = { key: 'value' };
const result = isObject(obj);
expect(result).toBe(true);
});
it('should return false for null', () => {
const result = isObject(null);
expect(result).toBe(false);
});
it('should return false for a non-object value', () => {
const value = 42; // Not an object
const result = isObject(value);
expect(result).toBe(false);
});
});
describe('isI18NObject', () => {
it('should return true for an I18N object', () => {
const i18nObject = { type: 'i18n', data: 'some data' };
const result = isI18NObject(i18nObject);
expect(result).toBe(true);
});
it('should return false for a non-I18N object', () => {
const nonI18nObject = { type: 'other', data: 'some data' };
const result = isI18NObject(nonI18nObject);
expect(result).toBe(false);
});
it('should return false for null', () => {
const result = isI18NObject(null);
expect(result).toBe(false);
});
it('should return false for a non-object value', () => {
const value = 42; // Not an object
const result = isI18NObject(value);
expect(result).toBe(false);
});
});

View File

@ -1,38 +0,0 @@
import React from "react";
import { isReactComponent, wrapReactClass } from "../../src/is-react";
class reactDemo extends React.Component {
}
const reactMemo = React.memo(reactDemo);
const reactForwardRef = React.forwardRef((props, ref): any => {
return '';
});
describe('is-react-ut', () => {
it('isReactComponent', () => {
expect(isReactComponent(null)).toBeFalsy();
expect(isReactComponent(() => {})).toBeTruthy();
expect(isReactComponent({
$$typeof: Symbol.for('react.memo')
})).toBeTruthy();
expect(isReactComponent({
$$typeof: Symbol.for('react.forward_ref')
})).toBeTruthy();
expect(isReactComponent(reactDemo)).toBeTruthy();
expect(isReactComponent(reactMemo)).toBeTruthy();
expect(isReactComponent(reactForwardRef)).toBeTruthy();
});
it('wrapReactClass', () => {
const wrap = wrapReactClass(() => {});
expect(isReactComponent(wrap)).toBeTruthy();
const fun = () => {};
fun.displayName = 'mock';
expect(wrapReactClass(fun).displayName).toBe('mock');
})
})

View File

@ -0,0 +1,316 @@
import React, { Component, createElement } from "react";
import {
isReactComponent,
wrapReactClass,
isForwardOrMemoForward,
isMemoType,
isForwardRefType,
acceptsRef,
isReactClass,
REACT_MEMO_TYPE,
REACT_FORWARD_REF_TYPE,
} from "../../src/is-react";
class reactDemo extends React.Component {
}
const reactMemo = React.memo(reactDemo);
const reactForwardRef = React.forwardRef((props, ref): any => {
return '';
});
describe('is-react-ut', () => {
it('isReactComponent', () => {
expect(isReactComponent(null)).toBeFalsy();
expect(isReactComponent(() => {})).toBeTruthy();
expect(isReactComponent({
$$typeof: Symbol.for('react.memo')
})).toBeTruthy();
expect(isReactComponent({
$$typeof: Symbol.for('react.forward_ref')
})).toBeTruthy();
expect(isReactComponent(reactDemo)).toBeTruthy();
expect(isReactComponent(reactMemo)).toBeTruthy();
expect(isReactComponent(reactForwardRef)).toBeTruthy();
});
it('wrapReactClass', () => {
const wrap = wrapReactClass(() => {});
expect(isReactComponent(wrap)).toBeTruthy();
const fun = () => {};
fun.displayName = 'mock';
expect(wrapReactClass(fun).displayName).toBe('mock');
})
})
describe('wrapReactClass', () => {
it('should wrap a FunctionComponent', () => {
// Create a mock FunctionComponent
const MockComponent: React.FunctionComponent = (props) => {
return <div>{props.children}</div>;
};
// Wrap the FunctionComponent using wrapReactClass
const WrappedComponent = wrapReactClass(MockComponent);
const instance = new WrappedComponent();
// Check if the WrappedComponent extends Component
expect(instance instanceof React.Component).toBe(true);
});
it('should render the FunctionComponent with props', () => {
// Create a mock FunctionComponent
const MockComponent: React.FunctionComponent = (props) => {
return <div>{props.children}</div>;
};
MockComponent.displayName = 'FunctionComponent';
// Wrap the FunctionComponent using wrapReactClass
const WrappedComponent = wrapReactClass(MockComponent);
// Create some test props
const testProps = { prop1: 'value1', prop2: 'value2' };
// Render the WrappedComponent with test props
const rendered = createElement(WrappedComponent, testProps, 'Child Text');
// Check if the WrappedComponent renders the FunctionComponent with props
expect(rendered).toMatchSnapshot();
});
});
describe('isReactComponent', () => {
it('should identify a class component as a React component', () => {
class ClassComponent extends React.Component {
render() {
return <div>Class Component</div>;
}
}
expect(isReactComponent(ClassComponent)).toBe(true);
});
it('should identify a functional component as a React component', () => {
const FunctionalComponent = () => {
return <div>Functional Component</div>;
};
expect(isReactComponent(FunctionalComponent)).toBe(true);
});
it('should identify a forward ref component as a React component', () => {
const ForwardRefComponent = React.forwardRef((props, ref) => {
return <div ref={ref}>Forward Ref Component</div>;
});
expect(isReactComponent(ForwardRefComponent)).toBe(true);
});
it('should identify a memo component as a React component', () => {
const MemoComponent = React.memo(() => {
return <div>Memo Component</div>;
});
expect(isReactComponent(MemoComponent)).toBe(true);
});
it('should return false for non-React components', () => {
const plainObject = { prop: 'value' };
const notAComponent = 'Not a component';
expect(isReactComponent(plainObject)).toBe(false);
expect(isReactComponent(notAComponent)).toBe(false);
});
it('should return false for null or undefined', () => {
const nullValue = null;
const undefinedValue = undefined;
expect(isReactComponent(nullValue)).toBe(false);
expect(isReactComponent(undefinedValue)).toBe(false);
});
});
describe('isForwardOrMemoForward', () => {
it('should return true for a forwardRef component', () => {
const forwardRefComponent = React.forwardRef(() => {
return <div>ForwardRef Component</div>;
});
expect(isForwardOrMemoForward(forwardRefComponent)).toBe(true);
});
it('should return true for a memoized forwardRef component', () => {
const forwardRefComponent = React.forwardRef(() => {
return <div>ForwardRef Component</div>;
});
const memoizedComponent = React.memo(forwardRefComponent);
expect(isForwardOrMemoForward(memoizedComponent)).toBe(true);
});
it('should return false for a memoized component that is not a forwardRef', () => {
const memoizedComponent = React.memo(() => {
return <div>Memoized Component</div>;
});
expect(isForwardOrMemoForward(memoizedComponent)).toBe(false);
});
it('should return false for a plain object', () => {
const plainObject = { prop: 'value' };
expect(isForwardOrMemoForward(plainObject)).toBe(false);
});
it('should return false for null or undefined', () => {
const nullValue = null;
const undefinedValue = undefined;
expect(isForwardOrMemoForward(nullValue)).toBe(false);
expect(isForwardOrMemoForward(undefinedValue)).toBe(false);
});
});
describe('isMemoType', () => {
it('should return true for an object with $$typeof matching REACT_MEMO_TYPE', () => {
const memoTypeObject = { $$typeof: REACT_MEMO_TYPE };
expect(isMemoType(memoTypeObject)).toBe(true);
});
it('should return false for an object with $$typeof not matching REACT_MEMO_TYPE', () => {
const otherTypeObject = { $$typeof: Symbol.for('other.type') };
expect(isMemoType(otherTypeObject)).toBe(false);
});
it('should return false for an object with no $$typeof property', () => {
const noTypeObject = { key: 'value' };
expect(isMemoType(noTypeObject)).toBe(false);
});
it('should return false for null or undefined', () => {
const nullValue = null;
const undefinedValue = undefined;
expect(isMemoType(nullValue)).toBe(false);
expect(isMemoType(undefinedValue)).toBe(false);
});
});
describe('isForwardRefType', () => {
it('should return true for an object with $$typeof matching REACT_FORWARD_REF_TYPE', () => {
const forwardRefTypeObject = { $$typeof: REACT_FORWARD_REF_TYPE };
expect(isForwardRefType(forwardRefTypeObject)).toBe(true);
});
it('should return false for an object with $$typeof not matching REACT_FORWARD_REF_TYPE', () => {
const otherTypeObject = { $$typeof: Symbol.for('other.type') };
expect(isForwardRefType(otherTypeObject)).toBe(false);
});
it('should return false for an object with no $$typeof property', () => {
const noTypeObject = { key: 'value' };
expect(isForwardRefType(noTypeObject)).toBe(false);
});
it('should return false for null or undefined', () => {
const nullValue = null;
const undefinedValue = undefined;
expect(isForwardRefType(nullValue)).toBe(false);
expect(isForwardRefType(undefinedValue)).toBe(false);
});
});
describe('acceptsRef', () => {
it('should return true for an object with isReactComponent in its prototype', () => {
const objWithIsReactComponent = {
prototype: {
isReactComponent: true,
},
};
expect(acceptsRef(objWithIsReactComponent)).toBe(true);
});
it('should return true for an object that is forwardRef or memoized forwardRef', () => {
const forwardRefObject = React.forwardRef(() => {
return null;
});
const memoizedForwardRefObject = React.memo(forwardRefObject);
expect(acceptsRef(forwardRefObject)).toBe(true);
expect(acceptsRef(memoizedForwardRefObject)).toBe(true);
});
it('should return false for an object without isReactComponent in its prototype', () => {
const objWithoutIsReactComponent = {
prototype: {
someOtherProperty: true,
},
};
expect(acceptsRef(objWithoutIsReactComponent)).toBe(false);
});
it('should return false for null or undefined', () => {
const nullValue = null;
const undefinedValue = undefined;
expect(acceptsRef(nullValue)).toBe(false);
expect(acceptsRef(undefinedValue)).toBe(false);
});
});
describe('isReactClass', () => {
it('should return true for an object with isReactComponent in its prototype', () => {
class ReactClassComponent extends Component {
render() {
return null;
}
}
expect(isReactClass(ReactClassComponent)).toBe(true);
});
it('should return true for an object with Component in its prototype chain', () => {
class CustomComponent extends Component {
render() {
return null;
}
}
expect(isReactClass(CustomComponent)).toBe(true);
});
it('should return false for an object without isReactComponent in its prototype', () => {
class NonReactComponent {
render() {
return null;
}
}
expect(isReactClass(NonReactComponent)).toBe(false);
});
it('should return false for null or undefined', () => {
const nullValue = null;
const undefinedValue = undefined;
expect(isReactClass(nullValue)).toBe(false);
expect(isReactClass(undefinedValue)).toBe(false);
});
});

View File

@ -0,0 +1,45 @@
import { isShaken } from '../../src/is-shaken';
describe('isShaken', () => {
it('should return true if e1 has shaken property', () => {
const e1: any = { shaken: true };
const e2: MouseEvent | DragEvent = { target: null } as MouseEvent | DragEvent;
expect(isShaken(e1, e2)).toBe(true);
});
it('should return true if e1.target and e2.target are different', () => {
const e1: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent;
const e2: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent;
expect(isShaken(e1, e2)).toBe(true);
});
it('should return false if e1 and e2 targets are the same and distance is less than SHAKE_DISTANCE', () => {
const target = {};
const e1: MouseEvent | DragEvent = { target: target } as MouseEvent | DragEvent;
const e2: MouseEvent | DragEvent = { target: target } as MouseEvent | DragEvent;
// Assuming SHAKE_DISTANCE is 100
e1.clientY = 50;
e2.clientY = 50;
e1.clientX = 60;
e2.clientX = 60;
expect(isShaken(e1, e2)).toBe(false);
});
it('should return true if e1 and e2 targets are the same and distance is greater than SHAKE_DISTANCE', () => {
const e1: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent;
const e2: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent;
// Assuming SHAKE_DISTANCE is 100
e1.clientY = 50;
e1.clientX = 50;
e2.clientY = 200;
e2.clientX = 200;
expect(isShaken(e1, e2)).toBe(true);
});
});

View File

@ -1,4 +1,321 @@
import { shouldUseVariableSetter } from '../../src/misc';
import {
isVariable,
isUseI18NSetter,
convertToI18NObject,
isString,
waitForThing,
arrShallowEquals,
isFromVC,
executePendingFn,
compatStage,
invariant,
isRegExp,
shouldUseVariableSetter,
} from '../../src/misc';
import { IPublicModelComponentMeta } from '@alilc/lowcode-types';
describe('isVariable', () => {
it('should return true for a variable object', () => {
const variable = { type: 'variable', variable: 'foo', value: 'bar' };
const result = isVariable(variable);
expect(result).toBe(true);
});
it('should return false for non-variable objects', () => {
const obj = { type: 'object' };
const result = isVariable(obj);
expect(result).toBe(false);
});
});
describe('isUseI18NSetter', () => {
it('should return true for a property with I18nSetter', () => {
const prototype = { options: { configure: [{ name: 'propName', setter: { type: { displayName: 'I18nSetter' } } }] } };
const propName = 'propName';
const result = isUseI18NSetter(prototype, propName);
expect(result).toBe(true);
});
it('should return false for a property without I18nSetter', () => {
const prototype = { options: { configure: [{ name: 'propName', setter: { type: { displayName: 'OtherSetter' } } }] } };
const propName = 'propName';
const result = isUseI18NSetter(prototype, propName);
expect(result).toBe(false);
});
});
describe('convertToI18NObject', () => {
it('should return the input if it is already an I18N object', () => {
const i18nObject = { type: 'i18n', use: 'en', en: 'Hello' };
const result = convertToI18NObject(i18nObject);
expect(result).toEqual(i18nObject);
});
it('should convert a string to an I18N object', () => {
const inputString = 'Hello';
const result = convertToI18NObject(inputString);
const expectedOutput = { type: 'i18n', use: 'zh-CN', 'zh-CN': inputString };
expect(result).toEqual(expectedOutput);
});
});
describe('isString', () => {
it('should return true for a string', () => {
const stringValue = 'Hello, world!';
const result = isString(stringValue);
expect(result).toBe(true);
});
it('should return true for an empty string', () => {
const emptyString = '';
const result = isString(emptyString);
expect(result).toBe(true);
});
it('should return false for a number', () => {
const numberValue = 42; // Not a string
const result = isString(numberValue);
expect(result).toBe(false);
});
it('should return false for an object', () => {
const objectValue = { key: 'value' }; // Not a string
const result = isString(objectValue);
expect(result).toBe(false);
});
it('should return false for null', () => {
const result = isString(null);
expect(result).toBe(false);
});
it('should return false for undefined', () => {
const undefinedValue = undefined;
const result = isString(undefinedValue);
expect(result).toBe(false);
});
it('should return false for a boolean', () => {
const booleanValue = true; // Not a string
const result = isString(booleanValue);
expect(result).toBe(false);
});
});
describe('waitForThing', () => {
it('should resolve immediately if the thing is available', async () => {
const obj = { prop: 'value' };
const path = 'prop';
const result = await waitForThing(obj, path);
expect(result).toBe('value');
});
it('should resolve after a delay if the thing becomes available', async () => {
const obj = { prop: undefined };
const path = 'prop';
const delay = 100; // Adjust the delay as needed
setTimeout(() => {
obj.prop = 'value';
}, delay);
const result = await waitForThing(obj, path);
expect(result).toBe('value');
});
});
describe('arrShallowEquals', () => {
it('should return true for two empty arrays', () => {
const arr1 = [];
const arr2 = [];
const result = arrShallowEquals(arr1, arr2);
expect(result).toBe(true);
});
it('should return true for two arrays with the same elements in the same order', () => {
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
const result = arrShallowEquals(arr1, arr2);
expect(result).toBe(true);
});
it('should return true for two arrays with the same elements in a different order', () => {
const arr1 = [1, 2, 3];
const arr2 = [3, 2, 1];
const result = arrShallowEquals(arr1, arr2);
expect(result).toBe(true);
});
it('should return false for two arrays with different lengths', () => {
const arr1 = [1, 2, 3];
const arr2 = [1, 2];
const result = arrShallowEquals(arr1, arr2);
expect(result).toBe(false);
});
it('should return false for one array and a non-array', () => {
const arr1 = [1, 2, 3];
const nonArray = 'not an array';
const result = arrShallowEquals(arr1, nonArray);
expect(result).toBe(false);
});
it('should return false for two arrays with different elements', () => {
const arr1 = [1, 2, 3];
const arr2 = [3, 4, 5];
const result = arrShallowEquals(arr1, arr2);
expect(result).toBe(false);
});
it('should return true for arrays with duplicate elements', () => {
const arr1 = [1, 2, 2, 3];
const arr2 = [2, 3, 3, 1];
const result = arrShallowEquals(arr1, arr2);
expect(result).toBe(true);
});
});
describe('isFromVC', () => {
it('should return true when advanced configuration is present', () => {
// Create a mock meta object with advanced configuration
const meta: IPublicModelComponentMeta = {
getMetadata: () => ({ configure: { advanced: true } }),
};
const result = isFromVC(meta);
expect(result).toBe(true);
});
it('should return false when advanced configuration is not present', () => {
// Create a mock meta object without advanced configuration
const meta: IPublicModelComponentMeta = {
getMetadata: () => ({ configure: { advanced: false } }),
};
const result = isFromVC(meta);
expect(result).toBe(false);
});
it('should return false when meta is undefined', () => {
const meta: IPublicModelComponentMeta | undefined = undefined;
const result = isFromVC(meta);
expect(result).toBe(false);
});
it('should return false when meta does not have configure information', () => {
// Create a mock meta object without configure information
const meta: IPublicModelComponentMeta = {
getMetadata: () => ({}),
};
const result = isFromVC(meta);
expect(result).toBe(false);
});
it('should return false when configure.advanced is not present', () => {
// Create a mock meta object with incomplete configure information
const meta: IPublicModelComponentMeta = {
getMetadata: () => ({ configure: {} }),
};
const result = isFromVC(meta);
expect(result).toBe(false);
});
});
describe('executePendingFn', () => {
it('should execute the provided function after the specified timeout', async () => {
// Mock the function to execute
const fn = jest.fn();
// Call executePendingFn with the mocked function and a short timeout
executePendingFn(fn, 100);
// Ensure the function has not been called immediately
expect(fn).not.toHaveBeenCalled();
// Wait for the specified timeout
await new Promise(resolve => setTimeout(resolve, 100));
// Ensure the function has been called after the timeout
expect(fn).toHaveBeenCalled();
});
it('should execute the provided function with a default timeout if not specified', async () => {
// Mock the function to execute
const fn = jest.fn();
// Call executePendingFn with the mocked function without specifying a timeout
executePendingFn(fn);
// Ensure the function has not been called immediately
expect(fn).not.toHaveBeenCalled();
// Wait for the default timeout (2000 milliseconds)
await new Promise(resolve => setTimeout(resolve, 2000));
// Ensure the function has been called after the default timeout
expect(fn).toHaveBeenCalled();
});
});
describe('compatStage', () => {
it('should convert a number to an enum stage', () => {
const result = compatStage(3);
expect(result).toBe('save');
});
it('should warn about the deprecated usage', () => {
const warnSpy = jest.spyOn(console, 'warn');
const result = compatStage(2);
expect(result).toBe('serilize');
expect(warnSpy).toHaveBeenCalledWith(
'stage 直接指定为数字的使用方式已经过时,将在下一版本移除,请直接使用 IPublicEnumTransformStage.Render|Serilize|Save|Clone|Init|Upgrade'
);
warnSpy.mockRestore();
});
it('should return the enum stage if it is already an enum', () => {
const result = compatStage('render');
expect(result).toBe('render');
});
});
describe('invariant', () => {
it('should not throw an error if the check is true', () => {
expect(() => invariant(true, 'Test invariant', 'thing')).not.toThrow();
});
it('should throw an error if the check is false', () => {
expect(() => invariant(false, 'Test invariant', 'thing')).toThrowError(
"Invariant failed: Test invariant in 'thing'"
);
});
});
describe('isRegExp', () => {
it('should return true for a valid RegExp', () => {
const regex = /test/;
const result = isRegExp(regex);
expect(result).toBe(true);
});
it('should return false for a non-RegExp object', () => {
const nonRegExp = { test: /test/ };
const result = isRegExp(nonRegExp);
expect(result).toBe(false);
});
it('should return false for null', () => {
const result = isRegExp(null);
expect(result).toBe(false);
});
});
it('shouldUseVariableSetter', () => {
expect(shouldUseVariableSetter(false, true)).toBeFalsy();

View File

@ -0,0 +1,18 @@
import { setNativeSelection, nativeSelectionEnabled } from '../../src/navtive-selection';
describe('setNativeSelection', () => {
beforeEach(() => {
// 在每个测试运行之前重置nativeSelectionEnabled的值
setNativeSelection(true);
});
test('should enable native selection', () => {
setNativeSelection(true);
expect(nativeSelectionEnabled).toBe(true);
});
test('should disable native selection', () => {
setNativeSelection(false);
expect(nativeSelectionEnabled).toBe(false);
});
});

View File

@ -1,4 +1,132 @@
import { compatibleLegaoSchema } from '../../src/schema';
import {
compatibleLegaoSchema,
getNodeSchemaById,
applyActivities,
} from '../../src/schema';
import { ActivityType } from '@alilc/lowcode-types';
describe('compatibleLegaoSchema', () => {
it('should handle null input', () => {
const result = compatibleLegaoSchema(null);
expect(result).toBeNull();
});
it('should convert Legao schema to JSExpression', () => {
// Create your test input
const legaoSchema = {
type: 'LegaoType',
source: 'LegaoSource',
compiled: 'LegaoCompiled',
};
const result = compatibleLegaoSchema(legaoSchema);
// Define the expected output
const expectedOutput = {
type: 'JSExpression',
value: 'LegaoCompiled',
extType: 'function',
};
// Assert that the result matches the expected output
expect(result).toEqual(expectedOutput);
});
// Add more test cases for other scenarios
});
describe('getNodeSchemaById', () => {
it('should find a node in the schema', () => {
// Create your test schema and node ID
const testSchema = {
id: 'root',
children: [
{
id: 'child1',
children: [
{
id: 'child1.1',
},
],
},
],
};
const nodeId = 'child1.1';
const result = getNodeSchemaById(testSchema, nodeId);
// Define the expected output
const expectedOutput = {
id: 'child1.1',
};
// Assert that the result matches the expected output
expect(result).toEqual(expectedOutput);
});
// Add more test cases for other scenarios
});
describe('applyActivities', () => {
it('should apply ADD activity', () => {
// Create your test schema and activities
const testSchema = {
id: 'root',
children: [
{
id: 'child1',
children: [
{
id: 'child1.1',
},
],
},
],
};
const activities = [
{
type: ActivityType.ADDED,
payload: {
location: {
parent: {
nodeId: 'child1',
index: 0,
},
},
schema: {
id: 'newChild',
},
},
},
];
const result = applyActivities(testSchema, activities);
// Define the expected output
const expectedOutput = {
id: 'root',
children: [
{
id: 'child1',
children: [
{
id: 'newChild',
},
{
id: 'child1.1',
},
],
},
],
};
// Assert that the result matches the expected output
expect(result).toEqual(expectedOutput);
});
// Add more test cases for other activity types and scenarios
});
describe('Schema Ut', () => {
it('props', () => {
const schema = {

View File

@ -0,0 +1,47 @@
import {
evaluate,
evaluateExpression,
newFunction,
} from '../../src/script';
describe('evaluate', () => {
test('should evaluate the given script', () => {
const script = 'console.log("Hello, world!");';
global.console = { log: jest.fn() };
evaluate(script);
expect(global.console.log).toHaveBeenCalledWith('Hello, world!');
});
});
describe('evaluateExpression', () => {
test('should evaluate the given expression', () => {
const expr = 'return 1 + 2';
const result = evaluateExpression(expr);
expect(result).toBe(3);
});
});
describe('newFunction', () => {
test('should create a new function with the given arguments and code', () => {
const args = 'a, b';
const code = 'return a + b';
const result = newFunction(args, code);
expect(result).toBeInstanceOf(Function);
expect(result(1, 2)).toBe(3);
});
test('should return null if an error occurs', () => {
const args = 'a, b';
const code = 'return a +;'; // Invalid code
const result = newFunction(args, code);
expect(result).toBeNull();
});
});

View File

@ -0,0 +1,35 @@
import React from 'react';
import { render } from '@testing-library/react';
import { SVGIcon, IconProps } from '../../src/svg-icon';
describe('SVGIcon', () => {
it('should render SVG element with correct size', () => {
const iconProps: IconProps = {
size: 'small',
viewBox: '0 0 24 24',
};
const { container } = render(<SVGIcon {...iconProps} />);
const svgElement = container.querySelector('svg');
expect(svgElement).toHaveAttribute('width', '12');
expect(svgElement).toHaveAttribute('height', '12');
});
it('should render SVG element with custom size', () => {
const iconProps: IconProps = {
size: 24,
viewBox: '0 0 24 24',
};
const { container } = render(<SVGIcon {...iconProps} />);
const svgElement = container.querySelector('svg');
expect(svgElement).toHaveAttribute('width', '24');
expect(svgElement).toHaveAttribute('height', '24');
});
// Add more tests for other scenarios if needed
});

View File

@ -0,0 +1,58 @@
import { transactionManager } from '../../src/transaction-manager';
import { IPublicEnumTransitionType } from '@alilc/lowcode-types';
const type = IPublicEnumTransitionType.REPAINT;
describe('TransactionManager', () => {
let fn1: jest.Mock;
let fn2: jest.Mock;
beforeEach(() => {
fn1 = jest.fn();
fn2 = jest.fn();
});
afterEach(() => {
jest.clearAllMocks();
});
test('executeTransaction should emit startTransaction and endTransaction events', () => {
const startTransactionSpy = jest.spyOn(transactionManager.emitter, 'emit');
const endTransactionSpy = jest.spyOn(transactionManager.emitter, 'emit');
transactionManager.executeTransaction(() => {
// Perform some action within the transaction
});
expect(startTransactionSpy).toHaveBeenCalledWith(`[${type}]startTransaction`);
expect(endTransactionSpy).toHaveBeenCalledWith(`[${type}]endTransaction`);
});
test('onStartTransaction should register the provided function for startTransaction event', () => {
const offSpy = jest.spyOn(transactionManager.emitter, 'off');
const offFunction = transactionManager.onStartTransaction(fn1);
expect(transactionManager.emitter.listenerCount(`[${type}]startTransaction`)).toBe(1);
expect(offSpy).not.toHaveBeenCalled();
offFunction();
expect(transactionManager.emitter.listenerCount(`[${type}]startTransaction`)).toBe(0);
expect(offSpy).toHaveBeenCalledWith(`[${type}]startTransaction`, fn1);
});
test('onEndTransaction should register the provided function for endTransaction event', () => {
const offSpy = jest.spyOn(transactionManager.emitter, 'off');
const offFunction = transactionManager.onEndTransaction(fn2);
expect(transactionManager.emitter.listenerCount(`[${type}]endTransaction`)).toBe(1);
expect(offSpy).not.toHaveBeenCalled();
offFunction();
expect(transactionManager.emitter.listenerCount(`[${type}]endTransaction`)).toBe(0);
expect(offSpy).toHaveBeenCalledWith(`[${type}]endTransaction`, fn2);
});
});

View File

@ -0,0 +1,11 @@
import { uniqueId } from '../../src/unique-id';
test('uniqueId should return a unique id with prefix', () => {
const id = uniqueId('test');
expect(id.startsWith('test')).toBeTruthy();
});
test('uniqueId should return a unique id without prefix', () => {
const id = uniqueId();
expect(id).not.toBeFalsy();
});