mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2025-12-12 03:01:16 +00:00
test: add ut for render-core/utils/data-helper.ts
This commit is contained in:
parent
bf280c6fa1
commit
171b1013b2
@ -1,3 +1,4 @@
|
||||
/* eslint-disable max-len */
|
||||
/* eslint-disable react/prop-types */
|
||||
import classnames from 'classnames';
|
||||
import { create as createDataSourceEngine } from '@alilc/lowcode-datasource-engine/interpret';
|
||||
@ -154,8 +155,7 @@ export default function baseRendererFactory(): IBaseRenderComponent {
|
||||
this.__showPlaceholder = false;
|
||||
return resolve({});
|
||||
}
|
||||
this.__dataHelper
|
||||
.getInitData()
|
||||
this.__dataHelper.getInitData()
|
||||
.then((res: any) => {
|
||||
this.__showPlaceholder = false;
|
||||
if (isEmpty(res)) {
|
||||
@ -286,8 +286,7 @@ export default function baseRendererFactory(): IBaseRenderComponent {
|
||||
// this.__showPlaceholder = false;
|
||||
return resolve({});
|
||||
}
|
||||
this.__dataHelper
|
||||
.getInitData()
|
||||
this.__dataHelper.getInitData()
|
||||
.then((res: any) => {
|
||||
// this.__showPlaceholder = false;
|
||||
if (isEmpty(res)) {
|
||||
|
||||
@ -118,7 +118,7 @@ export function isJSSlot(obj: any): obj is JSSlot {
|
||||
}
|
||||
|
||||
// Compatible with the old protocol JSBlock
|
||||
return ([EXPRESSION_TYPE.JSSLOT, EXPRESSION_TYPE.JSBLOCK].includes(obj.type));
|
||||
return [EXPRESSION_TYPE.JSSLOT, EXPRESSION_TYPE.JSBLOCK].includes(obj.type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable max-len */
|
||||
/* eslint-disable object-curly-newline */
|
||||
import { isJSFunction } from '@alilc/lowcode-types';
|
||||
import { transformArrayToMap, transformStringToFunction, clone } from './common';
|
||||
import { transformArrayToMap, transformStringToFunction } from './common';
|
||||
import { jsonp, request, get, post } from './request';
|
||||
import { DataSource, DataSourceItem } from '../types';
|
||||
import logger from './logger';
|
||||
import { DataSource, DataSourceItem, IRendererAppHelper } from '../types';
|
||||
|
||||
const DS_STATUS = {
|
||||
INIT: 'init',
|
||||
@ -12,22 +14,77 @@ const DS_STATUS = {
|
||||
ERROR: 'error',
|
||||
};
|
||||
|
||||
type DataSourceType = 'fetch' | 'jsonp';
|
||||
|
||||
/**
|
||||
* do request for standard DataSourceType
|
||||
* @param {DataSourceType} type type of DataSourceItem
|
||||
* @param {any} options
|
||||
*/
|
||||
export function doRequest(type: DataSourceType, options: any) {
|
||||
// eslint-disable-next-line prefer-const
|
||||
let { uri, url, method = 'GET', headers, params, ...otherProps } = options;
|
||||
otherProps = otherProps || {};
|
||||
if (type === 'jsonp') {
|
||||
return jsonp(uri, params, otherProps);
|
||||
}
|
||||
|
||||
if (type === 'fetch') {
|
||||
switch (method.toUpperCase()) {
|
||||
case 'GET':
|
||||
return get(uri, params, headers, otherProps);
|
||||
case 'POST':
|
||||
return post(uri, params, headers, otherProps);
|
||||
default:
|
||||
return request(uri, method, params, headers, otherProps);
|
||||
}
|
||||
}
|
||||
|
||||
logger.log(`Engine default dataSource does not support type:[${type}] dataSource request!`, options);
|
||||
}
|
||||
|
||||
// TODO: according to protocol, we should implement errorHandler/shouldFetch/willFetch/requestHandler and isSync controll.
|
||||
export class DataHelper {
|
||||
/**
|
||||
* host object that will be "this" object when excuting dataHandler
|
||||
*
|
||||
* @type {*}
|
||||
* @memberof DataHelper
|
||||
*/
|
||||
host: any;
|
||||
|
||||
/**
|
||||
* data source config
|
||||
*
|
||||
* @type {DataSource}
|
||||
* @memberof DataHelper
|
||||
*/
|
||||
config: DataSource;
|
||||
|
||||
/**
|
||||
* a parser function which will be called to process config data
|
||||
* which eventually will call common/utils.processData() to process data
|
||||
* (originalConfig) => parsedConfig
|
||||
* @type {*}
|
||||
* @memberof DataHelper
|
||||
*/
|
||||
parser: any;
|
||||
|
||||
/**
|
||||
* config.list
|
||||
*
|
||||
* @type {any[]}
|
||||
* @memberof DataHelper
|
||||
*/
|
||||
ajaxList: any[];
|
||||
|
||||
ajaxMap: any;
|
||||
|
||||
dataSourceMap: any;
|
||||
|
||||
appHelper: any;
|
||||
appHelper: IRendererAppHelper;
|
||||
|
||||
constructor(comp: any, config: DataSource, appHelper: any, parser: any) {
|
||||
constructor(comp: any, config: DataSource, appHelper: IRendererAppHelper, parser: any) {
|
||||
this.host = comp;
|
||||
this.config = config || {};
|
||||
this.parser = parser;
|
||||
@ -37,15 +94,6 @@ export class DataHelper {
|
||||
this.appHelper = appHelper;
|
||||
}
|
||||
|
||||
// 重置config,dataSourceMap状态会被重置;
|
||||
resetConfig(config = {}) {
|
||||
this.config = config as DataSource;
|
||||
this.ajaxList = (config as DataSource)?.list || [];
|
||||
this.ajaxMap = transformArrayToMap(this.ajaxList, 'id');
|
||||
this.dataSourceMap = this.generateDataSourceMap();
|
||||
return this.dataSourceMap;
|
||||
}
|
||||
|
||||
// 更新config,只会更新配置,状态保存;
|
||||
updateConfig(config = {}) {
|
||||
this.config = config as DataSource;
|
||||
@ -79,6 +127,7 @@ export class DataHelper {
|
||||
res[item.id] = {
|
||||
status: DS_STATUS.INIT,
|
||||
load: (...args: any) => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
return this.getDataSource(item.id, ...args);
|
||||
},
|
||||
@ -93,41 +142,54 @@ export class DataHelper {
|
||||
this.dataSourceMap[id].status = error ? DS_STATUS.ERROR : DS_STATUS.LOADED;
|
||||
}
|
||||
|
||||
getInitData() {
|
||||
const initSyncData = this.parser(this.ajaxList).filter((item: DataSourceItem) => {
|
||||
if (item.isInit) {
|
||||
/**
|
||||
* get all dataSourceItems which marked as isInit === true
|
||||
* @private
|
||||
* @returns
|
||||
* @memberof DataHelper
|
||||
*/
|
||||
getInitDataSourseConfigs() {
|
||||
const initConfigs = this.parser(this.ajaxList).filter((item: DataSourceItem) => {
|
||||
// according to [spec](https://lowcode-engine.cn/lowcode), isInit should be boolean true to be working
|
||||
if (item.isInit === true) {
|
||||
this.dataSourceMap[item.id].status = DS_STATUS.LOADING;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return initConfigs;
|
||||
}
|
||||
|
||||
/**
|
||||
* process all dataSourceItems which marked as isInit === true, and get dataSource request results.
|
||||
* @public
|
||||
* @returns
|
||||
* @memberof DataHelper
|
||||
*/
|
||||
getInitData() {
|
||||
const initSyncData = this.getInitDataSourseConfigs();
|
||||
// 所有 datasource 的 datahandler
|
||||
return this.asyncDataHandler(initSyncData).then((res) => {
|
||||
let { dataHandler } = this.config;
|
||||
if (isJSFunction(dataHandler)) {
|
||||
dataHandler = transformStringToFunction(dataHandler.value);
|
||||
}
|
||||
if (!dataHandler || typeof dataHandler !== 'function') return res;
|
||||
try {
|
||||
return (dataHandler as any).call(this.host, res);
|
||||
} catch (e) {
|
||||
console.error('请求数据处理函数运行出错', e);
|
||||
}
|
||||
const { dataHandler } = this.config;
|
||||
return this.handleData(null, dataHandler, res, null);
|
||||
});
|
||||
}
|
||||
|
||||
getDataSource(id: string, params: any, otherOptions: any, callback: any) {
|
||||
const req = this.parser(this.ajaxMap[id]);
|
||||
const options = req.options || {};
|
||||
let callbackFn = callback;
|
||||
let otherOptionsObj = otherOptions;
|
||||
if (typeof otherOptions === 'function') {
|
||||
callback = otherOptions;
|
||||
otherOptions = {};
|
||||
callbackFn = otherOptions;
|
||||
otherOptionsObj = {};
|
||||
}
|
||||
const { headers, ...otherProps } = otherOptions || {};
|
||||
const { headers, ...otherProps } = otherOptionsObj || {};
|
||||
if (!req) {
|
||||
console.warn(`getDataSource API named ${id} not exist`);
|
||||
return;
|
||||
}
|
||||
|
||||
return this.asyncDataHandler([
|
||||
{
|
||||
...req,
|
||||
@ -149,170 +211,99 @@ export class DataHelper {
|
||||
},
|
||||
},
|
||||
])
|
||||
.then((res: any) => {
|
||||
try {
|
||||
callback && callback(res && res[id]);
|
||||
} catch (e) {
|
||||
console.error('load请求回调函数报错', e);
|
||||
}
|
||||
|
||||
return res && res[id];
|
||||
})
|
||||
.catch((err) => {
|
||||
try {
|
||||
callback && callback(null, err);
|
||||
} catch (e) {
|
||||
console.error('load请求回调函数报错', e);
|
||||
}
|
||||
|
||||
return err;
|
||||
});
|
||||
.then((res: any) => {
|
||||
try {
|
||||
callbackFn && callbackFn(res && res[id]);
|
||||
} catch (e) {
|
||||
console.error('load请求回调函数报错', e);
|
||||
}
|
||||
return res && res[id];
|
||||
})
|
||||
.catch((err) => {
|
||||
try {
|
||||
callbackFn && callbackFn(null, err);
|
||||
} catch (e) {
|
||||
console.error('load请求回调函数报错', e);
|
||||
}
|
||||
return err;
|
||||
});
|
||||
}
|
||||
|
||||
asyncDataHandler(asyncDataList: any[]) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const allReq = [];
|
||||
const doserReq: Array<{name: string; package: string; params: any }> = [];
|
||||
const doserList: string[] = [];
|
||||
const beforeRequest = this.appHelper && this.appHelper.utils && this.appHelper.utils.beforeRequest;
|
||||
const afterRequest = this.appHelper && this.appHelper.utils && this.appHelper.utils.afterRequest;
|
||||
const csrfInput = document.getElementById('_csrf_token');
|
||||
const _tb_token_ = (csrfInput as any)?.value;
|
||||
const allReq: any[] = [];
|
||||
asyncDataList.forEach((req) => {
|
||||
const { id, type, options } = req;
|
||||
if (!id || !type || type === 'legao') return;
|
||||
if (type === 'doServer') {
|
||||
const { uri, params } = options || {};
|
||||
if (!uri) return;
|
||||
doserList.push(id);
|
||||
doserReq.push({ name: uri, package: 'cms', params });
|
||||
} else {
|
||||
allReq.push(req);
|
||||
const { id, type } = req;
|
||||
// TODO: need refactoring to remove 'legao' related logic
|
||||
if (!id || !type || type === 'legao') {
|
||||
return;
|
||||
}
|
||||
allReq.push(req);
|
||||
});
|
||||
|
||||
if (doserReq.length > 0) {
|
||||
allReq.push({
|
||||
type: 'doServer',
|
||||
options: {
|
||||
uri: '/nrsService.do',
|
||||
cors: true,
|
||||
method: 'POST',
|
||||
params: {
|
||||
data: JSON.stringify(doserReq),
|
||||
_tb_token_,
|
||||
},
|
||||
},
|
||||
});
|
||||
if (allReq.length === 0) {
|
||||
resolve({});
|
||||
}
|
||||
if (allReq.length === 0) resolve({});
|
||||
const res: any = {};
|
||||
// todo:
|
||||
Promise.all(
|
||||
allReq.map((item: any) => {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise((innerResolve) => {
|
||||
const { type, id, dataHandler, options } = item;
|
||||
const doFetch = (type: string, options: any) => {
|
||||
this.fetchOne(type as any, options)
|
||||
?.then((data: any) => {
|
||||
if (afterRequest) {
|
||||
this.appHelper.utils.afterRequest(item, data, undefined, (data: any, error: any) => {
|
||||
fetchHandler(data, error);
|
||||
});
|
||||
} else {
|
||||
fetchHandler(data, undefined);
|
||||
}
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
if (afterRequest) {
|
||||
// 必须要这么调用,否则beforeRequest中的this会丢失
|
||||
this.appHelper.utils.afterRequest(item, undefined, err, (data: any, error: any) => {
|
||||
fetchHandler(data, error);
|
||||
});
|
||||
} else {
|
||||
fetchHandler(undefined, err);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const fetchHandler = (data: any, error: any) => {
|
||||
if (type === 'doServer') {
|
||||
if (!Array.isArray(data)) {
|
||||
data = [data];
|
||||
}
|
||||
doserList.forEach((id, idx) => {
|
||||
const req: any = this.ajaxMap[id];
|
||||
if (req) {
|
||||
res[id] = this.dataHandler(id, req.dataHandler, data && data[idx], error);
|
||||
this.updateDataSourceMap(id, res[id], error);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res[id] = this.dataHandler(id, dataHandler, data, error);
|
||||
this.updateDataSourceMap(id, res[id], error);
|
||||
}
|
||||
resolve({});
|
||||
res[id] = this.handleData(id, dataHandler, data, error);
|
||||
this.updateDataSourceMap(id, res[id], error);
|
||||
innerResolve({});
|
||||
};
|
||||
|
||||
if (type === 'doServer') {
|
||||
doserList.forEach((item) => {
|
||||
this.dataSourceMap[item].status = DS_STATUS.LOADING;
|
||||
});
|
||||
} else {
|
||||
this.dataSourceMap[id].status = DS_STATUS.LOADING;
|
||||
}
|
||||
// 请求切片
|
||||
if (beforeRequest) {
|
||||
// 必须要这么调用,否则beforeRequest中的this会丢失
|
||||
this.appHelper.utils.beforeRequest(item, clone(options), (options: any) => doFetch(type, options));
|
||||
} else {
|
||||
doFetch(type, options);
|
||||
}
|
||||
const doFetch = (innerType: string, innerOptions: any) => {
|
||||
doRequest(innerType as any, innerOptions)
|
||||
?.then((data: any) => {
|
||||
fetchHandler(data, undefined);
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
fetchHandler(undefined, err);
|
||||
});
|
||||
};
|
||||
|
||||
this.dataSourceMap[id].status = DS_STATUS.LOADING;
|
||||
doFetch(type, options);
|
||||
});
|
||||
}),
|
||||
)
|
||||
.then(() => {
|
||||
resolve(res);
|
||||
})
|
||||
.catch((e) => {
|
||||
reject(e);
|
||||
});
|
||||
).then(() => {
|
||||
resolve(res);
|
||||
}).catch((e) => {
|
||||
reject(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// dataHandler todo:
|
||||
dataHandler(id: string, dataHandler: any, data: any, error: any) {
|
||||
/**
|
||||
* process data using dataHandler
|
||||
*
|
||||
* @param {(string | null)} id request id, will be used in error message, can be null
|
||||
* @param {*} dataHandler
|
||||
* @param {*} data
|
||||
* @param {*} error
|
||||
* @returns
|
||||
* @memberof DataHelper
|
||||
*/
|
||||
handleData(id: string | null, dataHandler: any, data: any, error: any) {
|
||||
let dataHandlerFun = dataHandler;
|
||||
if (isJSFunction(dataHandler)) {
|
||||
dataHandler = transformStringToFunction(dataHandler.value);
|
||||
dataHandlerFun = transformStringToFunction(dataHandler.value);
|
||||
}
|
||||
if (!dataHandlerFun || typeof dataHandlerFun !== 'function') {
|
||||
return data;
|
||||
}
|
||||
if (!dataHandler || typeof dataHandler !== 'function') return data;
|
||||
try {
|
||||
return dataHandler.call(this.host, data, error);
|
||||
return dataHandlerFun.call(this.host, data, error);
|
||||
} catch (e) {
|
||||
console.error(`[${ id }]单个请求数据处理函数运行出错`, e);
|
||||
}
|
||||
}
|
||||
|
||||
fetchOne(type: DataSourceType, options: any) {
|
||||
// eslint-disable-next-line prefer-const
|
||||
let { uri, url, method = 'GET', headers, params, ...otherProps } = options;
|
||||
otherProps = otherProps || {};
|
||||
if (type === 'jsonp') {
|
||||
return jsonp(uri, params, otherProps);
|
||||
}
|
||||
|
||||
if (type === 'fetch') {
|
||||
switch (method.toUpperCase()) {
|
||||
case 'GET':
|
||||
return get(uri, params, headers, otherProps);
|
||||
case 'POST':
|
||||
return post(uri, params, headers, otherProps);
|
||||
default:
|
||||
return request(uri, method, params, headers, otherProps);
|
||||
if (id) {
|
||||
console.error(`[${id}]单个请求数据处理函数运行出错`, e);
|
||||
} else {
|
||||
console.error('请求数据处理函数运行出错', e);
|
||||
}
|
||||
}
|
||||
|
||||
logger.log(`Engine default dataSource not support type:[${type}] dataSource request!`, options);
|
||||
}
|
||||
}
|
||||
|
||||
type DataSourceType = 'fetch' | 'jsonp';
|
||||
|
||||
569
packages/renderer-core/tests/utils/data-helper.test.ts
Normal file
569
packages/renderer-core/tests/utils/data-helper.test.ts
Normal file
@ -0,0 +1,569 @@
|
||||
// @ts-nocheck
|
||||
const mockJsonp = jest.fn();
|
||||
const mockRequest = jest.fn();
|
||||
const mockGet = jest.fn();
|
||||
const mockPost = jest.fn();
|
||||
jest.mock('../../src/utils/request', () => {
|
||||
return {
|
||||
jsonp: (uri, params, headers, otherProps) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(mockJsonp(uri, params, headers, otherProps));
|
||||
});
|
||||
},
|
||||
request: (uri, params, headers, otherProps) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(mockRequest(uri, params, headers, otherProps));
|
||||
});
|
||||
},
|
||||
get: (uri, params, headers, otherProps) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(mockGet(uri, params, headers, otherProps));
|
||||
});
|
||||
},
|
||||
post: (uri, params, headers, otherProps) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(mockPost(uri, params, headers, otherProps));
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
import { DataHelper, doRequest } from '../../src/utils/data-helper';
|
||||
import { parseData } from '../../src/utils/common';
|
||||
|
||||
describe('test DataHelper ', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
})
|
||||
it('can be inited', () => {
|
||||
const mockHost = {};
|
||||
let mockDataSourceConfig = {};
|
||||
const mockAppHelper = {};
|
||||
const mockParser = (config: any) => parseData(config);
|
||||
let dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);
|
||||
|
||||
expect(dataHelper).toBeTruthy();
|
||||
expect(dataHelper.host).toBe(mockHost);
|
||||
expect(dataHelper.config).toBe(mockDataSourceConfig);
|
||||
expect(dataHelper.appHelper).toBe(mockAppHelper);
|
||||
expect(dataHelper.parser).toBe(mockParser);
|
||||
|
||||
|
||||
dataHelper = new DataHelper(mockHost, undefined, mockAppHelper, mockParser);
|
||||
expect(dataHelper.config).toStrictEqual({});
|
||||
expect(dataHelper.ajaxList).toStrictEqual([]);
|
||||
|
||||
mockDataSourceConfig = {
|
||||
list: [
|
||||
{
|
||||
id: 'ds1',
|
||||
}, {
|
||||
id: 'ds2',
|
||||
},
|
||||
]
|
||||
};
|
||||
dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);
|
||||
expect(dataHelper.config).toBe(mockDataSourceConfig);
|
||||
expect(dataHelper.ajaxList.length).toBe(2);
|
||||
expect(dataHelper.ajaxMap.ds1).toStrictEqual({
|
||||
id: 'ds1',
|
||||
});
|
||||
});
|
||||
it('should handle generateDataSourceMap properly in constructor', () => {
|
||||
const mockHost = {};
|
||||
let mockDataSourceConfig = {};
|
||||
const mockAppHelper = {};
|
||||
const mockParser = (config: any) => parseData(config);
|
||||
let dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);
|
||||
|
||||
// test generateDataSourceMap logic
|
||||
mockDataSourceConfig = {
|
||||
list: [
|
||||
{
|
||||
id: 'getInfo',
|
||||
isInit: true,
|
||||
type: 'fetch', // fetch/mtop/jsonp/custom
|
||||
options: {
|
||||
uri: 'mock/info.json',
|
||||
method: 'GET',
|
||||
params: { a: 1 },
|
||||
timeout: 5000,
|
||||
},
|
||||
}, {
|
||||
id: 'postInfo',
|
||||
isInit: true,
|
||||
type: 'fetch',
|
||||
options: {
|
||||
uri: 'mock/info.json',
|
||||
method: 'POST',
|
||||
params: { a: 1 },
|
||||
timeout: 5000,
|
||||
},
|
||||
},
|
||||
]
|
||||
};
|
||||
dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);
|
||||
expect(Object.keys(dataHelper.dataSourceMap).length).toBe(2);
|
||||
expect(dataHelper.dataSourceMap.getInfo.status).toBe('init');
|
||||
expect(typeof dataHelper.dataSourceMap.getInfo.load).toBe('function');
|
||||
});
|
||||
|
||||
it('getInitDataSourseConfigs should work', () => {
|
||||
const mockHost = {};
|
||||
let mockDataSourceConfig = {};
|
||||
const mockAppHelper = {};
|
||||
const mockParser = (config: any) => parseData(config);
|
||||
|
||||
// test generateDataSourceMap logic
|
||||
mockDataSourceConfig = {
|
||||
list: [
|
||||
{
|
||||
id: 'getInfo',
|
||||
isInit: true,
|
||||
type: 'fetch', // fetch/mtop/jsonp/custom
|
||||
options: {
|
||||
uri: 'mock/info.json',
|
||||
method: 'GET',
|
||||
params: { a: 1 },
|
||||
timeout: 5000,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'postInfo',
|
||||
isInit: false,
|
||||
type: 'fetch',
|
||||
options: {
|
||||
uri: 'mock/info.json',
|
||||
method: 'POST',
|
||||
params: { a: 1 },
|
||||
timeout: 5000,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'getInfoLater',
|
||||
isInit: false,
|
||||
type: 'fetch',
|
||||
options: {
|
||||
uri: 'mock/info.json',
|
||||
method: 'POST',
|
||||
params: { a: 1 },
|
||||
timeout: 5000,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'getInfoLater2',
|
||||
isInit: 'not a valid boolean',
|
||||
type: 'fetch',
|
||||
options: {
|
||||
uri: 'mock/info.json',
|
||||
method: 'POST',
|
||||
params: { a: 1 },
|
||||
timeout: 5000,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);
|
||||
expect(dataHelper.getInitDataSourseConfigs().length).toBe(1);
|
||||
expect(dataHelper.getInitDataSourseConfigs()[0].id).toBe('getInfo');
|
||||
});
|
||||
it('util function doRequest should work', () => {
|
||||
doRequest('jsonp', {
|
||||
uri: 'https://www.baidu.com',
|
||||
params: { a: 1 },
|
||||
otherStuff1: 'aaa',
|
||||
});
|
||||
expect(mockJsonp).toBeCalled();
|
||||
|
||||
// test GET
|
||||
doRequest('fetch', {
|
||||
uri: 'https://www.baidu.com',
|
||||
method: 'get',
|
||||
params: { a: 1 },
|
||||
otherStuff1: 'aaa',
|
||||
});
|
||||
expect(mockGet).toBeCalled();
|
||||
|
||||
mockGet.mockClear();
|
||||
doRequest('fetch', {
|
||||
uri: 'https://www.baidu.com',
|
||||
method: 'Get',
|
||||
params: { a: 1 },
|
||||
otherStuff1: 'aaa',
|
||||
});
|
||||
expect(mockGet).toBeCalled();
|
||||
|
||||
mockGet.mockClear();
|
||||
doRequest('fetch', {
|
||||
uri: 'https://www.baidu.com',
|
||||
method: 'GET',
|
||||
params: { a: 1 },
|
||||
otherStuff1: 'aaa',
|
||||
});
|
||||
expect(mockGet).toBeCalled();
|
||||
|
||||
mockGet.mockClear();
|
||||
|
||||
// test POST
|
||||
doRequest('fetch', {
|
||||
uri: 'https://www.baidu.com',
|
||||
method: 'post',
|
||||
params: { a: 1 },
|
||||
otherStuff1: 'aaa',
|
||||
});
|
||||
expect(mockPost).toBeCalled();
|
||||
mockPost.mockClear();
|
||||
|
||||
doRequest('fetch', {
|
||||
uri: 'https://www.baidu.com',
|
||||
method: 'POST',
|
||||
params: { a: 1 },
|
||||
otherStuff1: 'aaa',
|
||||
});
|
||||
expect(mockPost).toBeCalled();
|
||||
mockPost.mockClear();
|
||||
doRequest('fetch', {
|
||||
uri: 'https://www.baidu.com',
|
||||
method: 'Post',
|
||||
params: { a: 1 },
|
||||
otherStuff1: 'aaa',
|
||||
});
|
||||
expect(mockPost).toBeCalled();
|
||||
mockPost.mockClear();
|
||||
|
||||
// test default
|
||||
doRequest('fetch', {
|
||||
uri: 'https://www.baidu.com',
|
||||
method: 'whatever',
|
||||
params: { a: 1 },
|
||||
otherStuff1: 'aaa',
|
||||
});
|
||||
expect(mockRequest).toBeCalled();
|
||||
mockRequest.mockClear();
|
||||
mockGet.mockClear();
|
||||
|
||||
// method will be GET when not provided
|
||||
doRequest('fetch', {
|
||||
uri: 'https://www.baidu.com',
|
||||
params: { a: 1 },
|
||||
otherStuff1: 'aaa',
|
||||
});
|
||||
expect(mockRequest).toBeCalledTimes(0);
|
||||
expect(mockGet).toBeCalledTimes(1);
|
||||
|
||||
mockRequest.mockClear();
|
||||
mockGet.mockClear();
|
||||
mockPost.mockClear();
|
||||
mockJsonp.mockClear();
|
||||
|
||||
doRequest('someOtherType', {
|
||||
uri: 'https://www.baidu.com',
|
||||
params: { a: 1 },
|
||||
otherStuff1: 'aaa',
|
||||
});
|
||||
expect(mockRequest).toBeCalledTimes(0);
|
||||
expect(mockGet).toBeCalledTimes(0);
|
||||
expect(mockPost).toBeCalledTimes(0);
|
||||
expect(mockJsonp).toBeCalledTimes(0);
|
||||
});
|
||||
it('updateDataSourceMap should work', () => {
|
||||
const mockHost = {};
|
||||
const mockDataSourceConfig = {
|
||||
list: [
|
||||
{
|
||||
id: 'ds1',
|
||||
}, {
|
||||
id: 'ds2',
|
||||
},
|
||||
]
|
||||
};
|
||||
const mockAppHelper = {};
|
||||
const mockParser = (config: any) => parseData(config);
|
||||
const dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);
|
||||
dataHelper.updateDataSourceMap('ds1', { a: 1 }, null);
|
||||
expect(dataHelper.dataSourceMap['ds1']).toBeTruthy();
|
||||
expect(dataHelper.dataSourceMap['ds1'].data).toStrictEqual({ a: 1 });
|
||||
expect(dataHelper.dataSourceMap['ds1'].error).toBeUndefined();
|
||||
expect(dataHelper.dataSourceMap['ds1'].status).toBe('loaded');
|
||||
dataHelper.updateDataSourceMap('ds2', { b: 2 }, new Error());
|
||||
expect(dataHelper.dataSourceMap['ds2']).toBeTruthy();
|
||||
expect(dataHelper.dataSourceMap['ds2'].data).toStrictEqual({ b: 2 });
|
||||
expect(dataHelper.dataSourceMap['ds2'].status).toBe('error');
|
||||
expect(dataHelper.dataSourceMap['ds2'].error).toBeTruthy();
|
||||
});
|
||||
|
||||
it('handleData should work', () => {
|
||||
const mockHost = { stateA: 'aValue'};
|
||||
const mockDataSourceConfig = {
|
||||
list: [
|
||||
{
|
||||
id: 'fullConfigGet',
|
||||
isInit: true,
|
||||
options: {
|
||||
params: {},
|
||||
method: 'GET',
|
||||
isCors: true,
|
||||
timeout: 5000,
|
||||
headers: {},
|
||||
uri: 'mock/info.json',
|
||||
},
|
||||
shouldFetch: {
|
||||
type: 'JSFunction',
|
||||
value: 'function() { return true; }',
|
||||
},
|
||||
dataHandler: {
|
||||
type: 'JSFunction',
|
||||
value: 'function(res) { return res.data; }',
|
||||
},
|
||||
errorHandler: {
|
||||
type: 'JSFunction',
|
||||
value: 'function(error) {}',
|
||||
},
|
||||
willFetch: {
|
||||
type: 'JSFunction',
|
||||
value: 'function(options) { return options; }',
|
||||
},
|
||||
},
|
||||
]
|
||||
};
|
||||
const mockAppHelper = {};
|
||||
const mockParser = (config: any) => parseData(config);
|
||||
const dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);
|
||||
// test valid case
|
||||
let mockDataHandler = {
|
||||
type: 'JSFunction',
|
||||
value: 'function(res) { return res.data + \'+\' + this.stateA; }',
|
||||
};
|
||||
let result = dataHelper.handleData('fullConfigGet', mockDataHandler, { data: 'mockDataValue' }, null);
|
||||
expect(result).toBe('mockDataValue+aValue');
|
||||
|
||||
// test invalid datahandler
|
||||
mockDataHandler = {
|
||||
type: 'not a JSFunction',
|
||||
value: 'function(res) { return res.data + \'+\' + this.stateA; }',
|
||||
};
|
||||
result = dataHelper.handleData('fullConfigGet', mockDataHandler, { data: 'mockDataValue' }, null);
|
||||
expect(result).toStrictEqual({ data: 'mockDataValue' });
|
||||
|
||||
// test exception
|
||||
const mockError = jest.fn();
|
||||
const orginalConsole = global.console;
|
||||
global.console = { error: mockError };
|
||||
|
||||
// exception with id
|
||||
mockDataHandler = {
|
||||
type: 'JSFunction',
|
||||
value: 'function(res) { return res.data + \'+\' + JSON.parse({a:1}); }',
|
||||
};
|
||||
result = dataHelper.handleData('fullConfigGet', mockDataHandler, { data: 'mockDataValue' }, null);
|
||||
expect(result).toBeUndefined();
|
||||
expect(mockError).toBeCalledWith('[fullConfigGet]单个请求数据处理函数运行出错', expect.anything());
|
||||
|
||||
// exception without id
|
||||
mockDataHandler = {
|
||||
type: 'JSFunction',
|
||||
value: 'function(res) { return res.data + \'+\' + JSON.parse({a:1}); }',
|
||||
};
|
||||
result = dataHelper.handleData(null, mockDataHandler, { data: 'mockDataValue' }, null);
|
||||
expect(result).toBeUndefined();
|
||||
expect(mockError).toBeCalledWith('请求数据处理函数运行出错', expect.anything());
|
||||
|
||||
global.console = orginalConsole;
|
||||
});
|
||||
|
||||
|
||||
it('updateConfig should work', () => {
|
||||
const mockHost = { stateA: 'aValue'};
|
||||
const mockDataSourceConfig = {
|
||||
list: [
|
||||
{
|
||||
id: 'ds1',
|
||||
}, {
|
||||
id: 'ds2',
|
||||
},
|
||||
{
|
||||
id: 'fullConfigGet',
|
||||
isInit: true,
|
||||
options: {
|
||||
params: {},
|
||||
method: 'GET',
|
||||
isCors: true,
|
||||
timeout: 5000,
|
||||
headers: {},
|
||||
uri: 'mock/info.json',
|
||||
},
|
||||
shouldFetch: {
|
||||
type: 'JSFunction',
|
||||
value: 'function() { return true; }',
|
||||
},
|
||||
dataHandler: {
|
||||
type: 'JSFunction',
|
||||
value: 'function(res) { return res.data; }',
|
||||
},
|
||||
errorHandler: {
|
||||
type: 'JSFunction',
|
||||
value: 'function(error) {}',
|
||||
},
|
||||
willFetch: {
|
||||
type: 'JSFunction',
|
||||
value: 'function(options) { return options; }',
|
||||
},
|
||||
},
|
||||
]
|
||||
};
|
||||
const mockAppHelper = {};
|
||||
const mockParser = (config: any) => parseData(config);
|
||||
const dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);
|
||||
|
||||
expect(dataHelper.ajaxList.length).toBe(3);
|
||||
|
||||
let updatedConfig = {
|
||||
list: [
|
||||
{
|
||||
id: 'ds2',
|
||||
},
|
||||
{
|
||||
id: 'fullConfigGet',
|
||||
},
|
||||
]
|
||||
};
|
||||
dataHelper.updateConfig(updatedConfig);
|
||||
|
||||
expect(dataHelper.ajaxList.length).toBe(2);
|
||||
expect(dataHelper.dataSourceMap.ds1).toBeUndefined();
|
||||
|
||||
updatedConfig = {
|
||||
list: [
|
||||
{
|
||||
id: 'ds2',
|
||||
},
|
||||
{
|
||||
id: 'fullConfigGet',
|
||||
},
|
||||
{
|
||||
id: 'ds3',
|
||||
},
|
||||
]
|
||||
};
|
||||
dataHelper.updateConfig(updatedConfig);
|
||||
expect(dataHelper.ajaxList.length).toBe(3);
|
||||
expect(dataHelper.dataSourceMap.ds3).toBeTruthy();
|
||||
});
|
||||
|
||||
it('getInitData should work', () => {
|
||||
const mockHost = { stateA: 'aValue'};
|
||||
const mockDataSourceConfig = {
|
||||
list: [
|
||||
{
|
||||
id: 'ds1',
|
||||
}, {
|
||||
id: 'ds2',
|
||||
},
|
||||
{
|
||||
id: 'fullConfigGet',
|
||||
isInit: true,
|
||||
type: 'fetch',
|
||||
options: {
|
||||
params: {},
|
||||
method: 'GET',
|
||||
isCors: true,
|
||||
timeout: 5000,
|
||||
headers: {
|
||||
headerA: 1,
|
||||
},
|
||||
uri: 'mock/info.json',
|
||||
},
|
||||
shouldFetch: {
|
||||
type: 'JSFunction',
|
||||
value: 'function() { return true; }',
|
||||
},
|
||||
dataHandler: {
|
||||
type: 'JSFunction',
|
||||
value: 'function(res) { return 123; }',
|
||||
},
|
||||
errorHandler: {
|
||||
type: 'JSFunction',
|
||||
value: 'function(error) {}',
|
||||
},
|
||||
willFetch: {
|
||||
type: 'JSFunction',
|
||||
value: 'function(options) { return options; }',
|
||||
},
|
||||
},
|
||||
]
|
||||
};
|
||||
const mockAppHelper = {};
|
||||
const mockParser = (config: any) => parseData(config);
|
||||
const dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);
|
||||
|
||||
expect(dataHelper.ajaxList.length).toBe(3);
|
||||
expect(mockGet).toBeCalledTimes(0);
|
||||
dataHelper.getInitData().then(res => {
|
||||
expect(mockGet).toBeCalledTimes(1);
|
||||
expect(mockGet).toBeCalledWith('mock/info.json', {}, {
|
||||
headerA: 1,
|
||||
}, expect.anything());
|
||||
mockGet.mockClear();
|
||||
});
|
||||
});
|
||||
|
||||
it('getDataSource should work', () => {
|
||||
const mockHost = { stateA: 'aValue'};
|
||||
const mockDataSourceConfig = {
|
||||
list: [
|
||||
{
|
||||
id: 'ds1',
|
||||
}, {
|
||||
id: 'ds2',
|
||||
},
|
||||
{
|
||||
id: 'fullConfigGet',
|
||||
isInit: true,
|
||||
type: 'fetch',
|
||||
options: {
|
||||
params: {},
|
||||
method: 'GET',
|
||||
isCors: true,
|
||||
timeout: 5000,
|
||||
headers: {
|
||||
headerA: 1,
|
||||
},
|
||||
uri: 'mock/info.json',
|
||||
},
|
||||
shouldFetch: {
|
||||
type: 'JSFunction',
|
||||
value: 'function() { return true; }',
|
||||
},
|
||||
dataHandler: {
|
||||
type: 'JSFunction',
|
||||
value: 'function(res) { return 123; }',
|
||||
},
|
||||
errorHandler: {
|
||||
type: 'JSFunction',
|
||||
value: 'function(error) {}',
|
||||
},
|
||||
willFetch: {
|
||||
type: 'JSFunction',
|
||||
value: 'function(options) { return options; }',
|
||||
},
|
||||
},
|
||||
]
|
||||
};
|
||||
const mockAppHelper = {};
|
||||
const mockParser = (config: any) => parseData(config);
|
||||
const dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);
|
||||
|
||||
expect(dataHelper.ajaxList.length).toBe(3);
|
||||
expect(mockGet).toBeCalledTimes(0);
|
||||
const callbackFn = jest.fn();
|
||||
dataHelper.getDataSource('fullConfigGet', { param1: 'value1' }, {}, callbackFn).then(res => {
|
||||
expect(mockGet).toBeCalledTimes(1);
|
||||
expect(mockGet).toBeCalledWith('mock/info.json', { param1: 'value1' }, {
|
||||
headerA: 1,
|
||||
}, expect.anything());
|
||||
mockGet.mockClear();
|
||||
expect(callbackFn).toBeCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user