feat: 增强默认参数系列化器
BREAKING CHANGE : axios.get('url',{obj:{v1:1,v2:2}}) -> fetch: 'url?obj={"val":1,"v2":2}' 变为 axios.get('url',{obj:{v1:1,v2:2}}) -> fetch: 'url?obj[v1]=1&obj[v2]=2'pull/41/head
parent
666a9427d3
commit
0cfb3e1ff0
|
@ -15,6 +15,13 @@ export function captureError<T = any>(fn: () => void): T {
|
|||
}
|
||||
}
|
||||
|
||||
export function cleanedStack(error: Error) {
|
||||
if (error.stack) {
|
||||
return error.stack.indexOf('at') === error.stack.indexOf('at /');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function noop() {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -168,13 +168,10 @@ export function getAdapterDefault(): AxiosAdapter | undefined {
|
|||
}
|
||||
|
||||
export function createAdapter(platform: AxiosPlatform): AxiosAdapter {
|
||||
assert(isPlainObject(platform), 'platform 需要是一个 object');
|
||||
assert(isFunction(platform.request), 'platform.request 需要是一个 function');
|
||||
assert(isFunction(platform.upload), 'platform.upload 需要是一个 function');
|
||||
assert(
|
||||
isFunction(platform.download),
|
||||
'platform.download 需要是一个 function',
|
||||
);
|
||||
assert(isPlainObject(platform), 'platform 不是一个 object');
|
||||
assert(isFunction(platform.request), 'platform.request 不是一个 function');
|
||||
assert(isFunction(platform.upload), 'platform.upload 不是一个 function');
|
||||
assert(isFunction(platform.download), 'platform.download 不是一个 function');
|
||||
|
||||
function adapterDefault(
|
||||
config: AxiosAdapterRequestConfig,
|
||||
|
@ -204,17 +201,14 @@ export function createAdapter(platform: AxiosPlatform): AxiosAdapter {
|
|||
upload: AxiosAdapterUpload,
|
||||
baseOptions: AxiosAdapterBaseOptions,
|
||||
): AxiosAdapterTask | void {
|
||||
assert(
|
||||
isPlainObject(baseOptions.data),
|
||||
'上传文件时 data 需要是一个 object',
|
||||
);
|
||||
assert(isPlainObject(baseOptions.data), 'data 不是一个 object');
|
||||
assert(
|
||||
isString(baseOptions.data?.fileName),
|
||||
'上传文件时 data.fileName 需要是一个 string',
|
||||
'data.fileName 不是一个 string',
|
||||
);
|
||||
assert(
|
||||
isString(baseOptions.data?.filePath),
|
||||
'上传文件时 data.filePath 需要是一个 string',
|
||||
'data.filePath 不是一个 string',
|
||||
);
|
||||
|
||||
const { fileName, filePath, fileType, ...formData } =
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { cleanStack } from '../helpers/error';
|
||||
import { AxiosAdapterTask } from '../adapter';
|
||||
import { AxiosRequestConfig, AxiosResponse, AxiosResponseError } from './Axios';
|
||||
|
||||
|
@ -34,5 +35,7 @@ export function createError(
|
|||
request?: AxiosAdapterTask,
|
||||
response?: AxiosErrorResponse,
|
||||
): AxiosError {
|
||||
return new AxiosError(message, config, request, response);
|
||||
const axiosError = new AxiosError(message, config, request, response);
|
||||
cleanStack(axiosError);
|
||||
return axiosError;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { isPlainObject } from '../helpers/isTypes';
|
||||
import { omit } from '../helpers/omit';
|
||||
import { ignore } from '../helpers/ignore';
|
||||
import { AxiosRequestConfig, AxiosRequestHeaders } from './Axios';
|
||||
|
||||
export function flattenHeaders(
|
||||
|
@ -12,7 +12,7 @@ export function flattenHeaders(
|
|||
return {
|
||||
...(config.headers.common ?? {}),
|
||||
...(config.headers[config.method!.toLowerCase()] ?? {}),
|
||||
...omit(
|
||||
...ignore(
|
||||
config.headers,
|
||||
'common',
|
||||
'options',
|
||||
|
|
|
@ -41,7 +41,7 @@ export function request<TData = unknown>(
|
|||
config: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<TData>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
assert(isFunction(config.adapter), 'adapter 需要是一个 function');
|
||||
assert(isFunction(config.adapter), 'adapter 不是一个 function');
|
||||
|
||||
const adapterConfig: AxiosAdapterRequestConfig = {
|
||||
...config,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { buildURL } from '../helpers/buildURL';
|
||||
import { combineURL } from '../helpers/combineURL';
|
||||
import { interpolation, isDynamicURL } from '../helpers/dynamicURL';
|
||||
import { dynamicURL } from '../helpers/dynamicURL';
|
||||
import { isAbsoluteURL } from '../helpers/isAbsoluteURL';
|
||||
import { AxiosRequestConfig } from './Axios';
|
||||
|
||||
|
@ -8,10 +8,7 @@ export function transformURL(config: AxiosRequestConfig): string {
|
|||
let url = config.url ?? '';
|
||||
|
||||
if (!isAbsoluteURL(url)) url = combineURL(config.baseURL ?? '', url);
|
||||
|
||||
if (isDynamicURL(url))
|
||||
url = interpolation(url, Object.assign({}, config.params, config.data));
|
||||
|
||||
url = dynamicURL(url, Object.assign({}, config.params, config.data));
|
||||
url = buildURL(url, config.params, config.paramsSerializer);
|
||||
|
||||
return url;
|
||||
|
|
|
@ -1,65 +1,46 @@
|
|||
import { isDate, isNull, isPlainObject, isUndefined } from './isTypes';
|
||||
import { isArray, isDate, isNull, isPlainObject, isUndefined } from './isTypes';
|
||||
|
||||
export function buildURL(
|
||||
url = '',
|
||||
params?: unknown,
|
||||
paramsSerializer = paramsSerialization,
|
||||
params?: AnyObject,
|
||||
paramsSerializer = defaultSerializer,
|
||||
): string {
|
||||
if (!isPlainObject(params)) {
|
||||
return url;
|
||||
}
|
||||
|
||||
return generateURL(url, paramsSerializer(params));
|
||||
}
|
||||
|
||||
function generateURL(url: string, serializedParams: string): string {
|
||||
const hashIndex = url.indexOf('#');
|
||||
|
||||
if (hashIndex !== -1) {
|
||||
url = url.slice(0, hashIndex);
|
||||
}
|
||||
|
||||
if (serializedParams === '') {
|
||||
return url;
|
||||
const paramsStr = paramsSerializer(params);
|
||||
if (paramsStr) {
|
||||
url = `${url}${url.indexOf('?') === -1 ? '?' : '&'}${paramsStr}`;
|
||||
}
|
||||
|
||||
const prefix = url.indexOf('?') === -1 ? '?' : '&';
|
||||
|
||||
serializedParams = `${prefix}${serializedParams}`;
|
||||
|
||||
return `${url}${serializedParams}`;
|
||||
return url;
|
||||
}
|
||||
|
||||
function paramsSerialization(params?: AnyObject): string {
|
||||
if (!isPlainObject(params)) {
|
||||
return '';
|
||||
}
|
||||
function defaultSerializer(params?: AnyObject): string {
|
||||
if (!isPlainObject(params)) return '';
|
||||
|
||||
const parts: string[] = [];
|
||||
|
||||
Object.keys(params).forEach((key): void => {
|
||||
const value = params[key];
|
||||
function push(key: string, value: string) {
|
||||
parts.push(`${encode(key)}=${encode(value)}`);
|
||||
}
|
||||
|
||||
if (isNull(value) || isUndefined(value) || value !== value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
key += '[]';
|
||||
}
|
||||
|
||||
const values = [].concat(value);
|
||||
|
||||
values.forEach((val: any): void => {
|
||||
for (const [key, val] of Object.entries(params)) {
|
||||
if (!isNull(val) && !isUndefined(val) && val === val) {
|
||||
if (isPlainObject(val)) {
|
||||
val = JSON.stringify(val);
|
||||
for (const [k, v] of Object.entries(val)) push(`${key}[${k}]`, v);
|
||||
} else if (isArray<string>(val)) {
|
||||
const k = `${key}[]`;
|
||||
for (const v of val) push(k, v);
|
||||
} else if (isDate(val)) {
|
||||
val = (val as Date).toISOString();
|
||||
push(key, val.toISOString());
|
||||
} else {
|
||||
push(key, val);
|
||||
}
|
||||
|
||||
parts.push(`${encode(key)}=${encode(val)}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return parts.join('&');
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const combineREG = /(^|[^:])\/{2,}/g;
|
||||
const combineRE = /(^|[^:])\/{2,}/g;
|
||||
export function combineURL(baseURL: string, url: string): string {
|
||||
return url ? `${baseURL}/${url}`.replace(combineREG, '$1/') : baseURL;
|
||||
return url ? `${baseURL}/${url}`.replace(combineRE, '$1/') : baseURL;
|
||||
}
|
||||
|
|
|
@ -3,20 +3,18 @@ import { isPlainObject } from './isTypes';
|
|||
export function deepMerge<T extends AnyObject>(...objs: T[]): T {
|
||||
const result: AnyObject = {};
|
||||
|
||||
objs.forEach((obj: AnyObject) =>
|
||||
Object.keys(obj).forEach((key) => {
|
||||
const val = obj[key];
|
||||
const resultVal = result[key];
|
||||
|
||||
if (isPlainObject(resultVal) && isPlainObject(val)) {
|
||||
result[key] = deepMerge(resultVal, val);
|
||||
} else if (isPlainObject(val)) {
|
||||
result[key] = deepMerge(val);
|
||||
for (const obj of objs) {
|
||||
for (const [key, val] of Object.entries(obj)) {
|
||||
if (isPlainObject(val)) {
|
||||
const rVal = result[key];
|
||||
result[key] = isPlainObject(rVal)
|
||||
? deepMerge(rVal, val)
|
||||
: deepMerge(val);
|
||||
} else {
|
||||
result[key] = val;
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return result as T;
|
||||
}
|
||||
|
|
|
@ -1,18 +1,4 @@
|
|||
import { isPlainObject } from './isTypes';
|
||||
|
||||
const dynamicREG = /\/?(:([a-zA-Z_$][\w-$]*))\/??/g;
|
||||
|
||||
export function interpolation(url: string, sourceData?: unknown): string {
|
||||
if (!isPlainObject(sourceData)) {
|
||||
return url;
|
||||
}
|
||||
|
||||
return url.replace(dynamicREG, ($1, $2, $3) =>
|
||||
$1.replace($2, sourceData[$3]),
|
||||
);
|
||||
}
|
||||
|
||||
export function isDynamicURL(url: string): boolean {
|
||||
dynamicREG.lastIndex = 0;
|
||||
return dynamicREG.test(url);
|
||||
const dynamicRE = /:([^/]+)/g;
|
||||
export function dynamicURL(url: string, data: AnyObject = {}): string {
|
||||
return url.replace(dynamicRE, (_, $2) => data[$2]);
|
||||
}
|
||||
|
|
|
@ -5,5 +5,19 @@ export function assert(condition: boolean, msg: string) {
|
|||
}
|
||||
|
||||
export function throwError(msg: string): void {
|
||||
throw new Error(`[axios-miniprogram]: ${msg}`);
|
||||
const error = new Error(`[axios-miniprogram]: ${msg}`);
|
||||
cleanStack(error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
export function cleanStack(error: Error) {
|
||||
if (error.stack) {
|
||||
const start = error.stack.indexOf('at');
|
||||
const end = error.stack.indexOf('at /');
|
||||
|
||||
if (start !== end) {
|
||||
const removed = error.stack.slice(start, end);
|
||||
error.stack = error.stack.replace(removed, '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
export function ignore<T extends AnyObject, K extends keyof T>(
|
||||
obj: T,
|
||||
...keys: K[]
|
||||
): Omit<T, K> {
|
||||
const result = { ...obj };
|
||||
for (const key of keys) delete result[key];
|
||||
return result;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
const absoluteREG = /^([a-z][a-z\d+\-.]*:)?\/\//i;
|
||||
const absoluteRE = /^([a-z][\w-.]*:)\/\//i;
|
||||
export function isAbsoluteURL(url: string): boolean {
|
||||
return absoluteREG.test(url);
|
||||
return absoluteRE.test(url);
|
||||
}
|
||||
|
|
|
@ -1,38 +1,36 @@
|
|||
const _toString = Object.prototype.toString;
|
||||
|
||||
export function isArray<T = unknown>(value: any): value is T[] {
|
||||
return Array.isArray(value);
|
||||
}
|
||||
|
||||
export function isDate(date: any): date is Date {
|
||||
return _toString.call(date) === '[object Date]';
|
||||
}
|
||||
|
||||
export function isEmptyArray<T = unknown>(value: any): value is [] {
|
||||
return isArray<T>(value) && value.length === 0;
|
||||
}
|
||||
|
||||
export function isEmptyObject(value: any): value is object {
|
||||
return isPlainObject(value) && Object.keys(value).length === 0;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export function isFunction<T extends Function>(value: any): value is T {
|
||||
return typeof value === 'function';
|
||||
}
|
||||
|
||||
export function isNull(value: any): value is null {
|
||||
return value === null;
|
||||
}
|
||||
|
||||
export function isUndefined(value: any): value is undefined {
|
||||
return typeof value === 'undefined';
|
||||
}
|
||||
|
||||
export function isString(value: any): value is string {
|
||||
return (
|
||||
typeof value === 'string' || _toString.call(value) === '[object String]'
|
||||
);
|
||||
}
|
||||
|
||||
export function isPlainObject(value: any): value is object & AnyObject {
|
||||
return _toString.call(value) === '[object Object]';
|
||||
}
|
||||
|
||||
export function isString(value: any): value is string {
|
||||
return typeof value === 'string';
|
||||
export function isArray<T = unknown>(value: any): value is T[] {
|
||||
return Array.isArray(value);
|
||||
}
|
||||
|
||||
export function isUndefined(value: any): value is undefined {
|
||||
return typeof value === 'undefined';
|
||||
export function isEmptyArray<T = unknown>(value: any): value is [] {
|
||||
return isArray<T>(value) && value.length === 0;
|
||||
}
|
||||
|
||||
export function isDate(date: any): date is Date {
|
||||
return _toString.call(date) === '[object Date]';
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export function isFunction<T extends Function>(value: any): value is T {
|
||||
return typeof value === 'function';
|
||||
}
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
export function omit<T extends AnyObject, K extends keyof T>(
|
||||
obj: T,
|
||||
...keys: K[]
|
||||
): Omit<T, K> {
|
||||
const res = { ...obj };
|
||||
keys.forEach((key: K) => delete res[key]);
|
||||
return res;
|
||||
}
|
|
@ -9,7 +9,7 @@ import {
|
|||
import axios from 'src/axios';
|
||||
import { Cancel, isCancel, CancelToken, isCancelToken } from 'src/core/cancel';
|
||||
|
||||
describe('测试 src/helpers/cancel.ts', () => {
|
||||
describe('src/helpers/cancel.ts', () => {
|
||||
test('应该支持空参数', () => {
|
||||
const cancel = new Cancel();
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import { describe, test, expect } from 'vitest';
|
||||
import { cleanedStack } from 'scripts/test.utils';
|
||||
import { createError } from 'src/core/createError';
|
||||
|
||||
describe('src/core/createError.ts', () => {
|
||||
test('应该支持空参数', () => {
|
||||
const config = {};
|
||||
const axiosError = createError('error', config);
|
||||
|
||||
expect(axiosError.isAxiosError).toBeTruthy();
|
||||
expect(axiosError.message).toBe('error');
|
||||
expect(axiosError.config).toBe(config);
|
||||
expect(cleanedStack(axiosError)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('应该支持传入更多参数', () => {
|
||||
const config = {};
|
||||
const request = {};
|
||||
const response = {};
|
||||
const axiosError = createError('error', config, request, response as any);
|
||||
|
||||
expect(axiosError.message).toBe('error');
|
||||
expect(axiosError.config).toBe(config);
|
||||
expect(axiosError.request).toBe(request);
|
||||
expect(axiosError.response).toBe(response);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,63 @@
|
|||
import { describe, test, expect } from 'vitest';
|
||||
import { buildURL } from 'src/helpers/buildURL';
|
||||
|
||||
describe('src/helpers/buildURL.ts', () => {
|
||||
test('应该支持空参数', () => {
|
||||
expect(buildURL('/user')).toBe('/user');
|
||||
});
|
||||
|
||||
test('应该清理哈希值', () => {
|
||||
expect(buildURL('/user#hash')).toBe('/user');
|
||||
});
|
||||
|
||||
test('应该对参数进行系列化', () => {
|
||||
expect(
|
||||
buildURL('/user#hash', {
|
||||
v1: 1,
|
||||
v2: undefined,
|
||||
v3: null,
|
||||
v4: '4',
|
||||
v5: NaN,
|
||||
}),
|
||||
).toBe('/user?v1=1&v4=4');
|
||||
|
||||
expect(
|
||||
buildURL('/user?v1=1', {
|
||||
v2: 2,
|
||||
}),
|
||||
).toBe('/user?v1=1&v2=2');
|
||||
});
|
||||
|
||||
test('应该对数组进行系列化', () => {
|
||||
expect(
|
||||
buildURL('/user', {
|
||||
arr: [1, 2],
|
||||
}),
|
||||
).toBe('/user?arr[]=1&arr[]=2');
|
||||
});
|
||||
|
||||
test('应该对对象进行系列化', () => {
|
||||
expect(
|
||||
buildURL('/user', {
|
||||
obj: {
|
||||
k1: 1,
|
||||
k2: 2,
|
||||
},
|
||||
}),
|
||||
).toBe('/user?obj[k1]=1&obj[k2]=2');
|
||||
});
|
||||
|
||||
test('应该对日期进行系列化', () => {
|
||||
const date = new Date();
|
||||
expect(buildURL('/user', { date })).toBe(
|
||||
`/user?date=${date.toISOString()}`,
|
||||
);
|
||||
});
|
||||
|
||||
test('应该支持自定义序列化器', () => {
|
||||
expect(buildURL('/user', {}, () => 'v1=1&v2=2')).toBe('/user?v1=1&v2=2');
|
||||
expect(buildURL('/user?v1=1', {}, () => 'v2=2&v3=3')).toBe(
|
||||
'/user?v1=1&v2=2&v3=3',
|
||||
);
|
||||
});
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
import { describe, test, expect } from 'vitest';
|
||||
import { combineURL } from 'src/helpers/combineURL';
|
||||
|
||||
describe('测试 src/helpers/combineURL.ts', () => {
|
||||
describe('src/helpers/combineURL.ts', () => {
|
||||
test('应该直接返回第一个参数', () => {
|
||||
expect(combineURL('http://api.com', '')).toBe('http://api.com');
|
||||
expect(combineURL('file://api.com', '')).toBe('file://api.com');
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
import { describe, test, expect } from 'vitest';
|
||||
import { deepMerge } from 'src/helpers/deepMerge';
|
||||
|
||||
describe('src/helpers/deepMerge.ts', () => {
|
||||
test('应该支持空参数', () => {
|
||||
expect(deepMerge()).toEqual({});
|
||||
});
|
||||
|
||||
test('应该直接返回第一个参数', () => {
|
||||
expect(
|
||||
deepMerge({
|
||||
v1: 1,
|
||||
v2: [1],
|
||||
v3: { v: 'v3' },
|
||||
v4: undefined,
|
||||
v5: null,
|
||||
v6: 'v6',
|
||||
}),
|
||||
).toEqual({
|
||||
v1: 1,
|
||||
v2: [1],
|
||||
v3: { v: 'v3' },
|
||||
v4: undefined,
|
||||
v5: null,
|
||||
v6: 'v6',
|
||||
});
|
||||
});
|
||||
|
||||
test('应该进行合并', () => {
|
||||
expect(
|
||||
deepMerge(
|
||||
{
|
||||
v1: 1,
|
||||
v2: 2,
|
||||
v3: 3,
|
||||
},
|
||||
{
|
||||
v2: 22,
|
||||
v3: undefined,
|
||||
v4: 4,
|
||||
},
|
||||
),
|
||||
).toEqual({
|
||||
v1: 1,
|
||||
v2: 22,
|
||||
v3: undefined,
|
||||
v4: 4,
|
||||
});
|
||||
});
|
||||
|
||||
test('应该合并对象里的对象', () => {
|
||||
expect(
|
||||
deepMerge(
|
||||
{
|
||||
v1: { v: 1 },
|
||||
v2: { v: 2 },
|
||||
v3: 3,
|
||||
},
|
||||
{
|
||||
v1: { vv: 11 },
|
||||
v2: 2,
|
||||
v3: { v: 3 },
|
||||
},
|
||||
),
|
||||
).toEqual({
|
||||
v1: { v: 1, vv: 11 },
|
||||
v2: 2,
|
||||
v3: { v: 3 },
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,22 @@
|
|||
import { describe, test, expect } from 'vitest';
|
||||
import { dynamicURL } from 'src/helpers/dynamicURL';
|
||||
|
||||
describe('src/helpers/dynamicURL.ts', () => {
|
||||
test('应该替换关键字', () => {
|
||||
expect(dynamicURL('http://api.com/user/:id', {})).toBe(
|
||||
'http://api.com/user/undefined',
|
||||
);
|
||||
expect(dynamicURL('http://api.com/user/:id', { id: 1 })).toBe(
|
||||
'http://api.com/user/1',
|
||||
);
|
||||
});
|
||||
|
||||
test('应该支持多个关键字', () => {
|
||||
expect(
|
||||
dynamicURL('http://api.com/users/name/:name/age/:age/list', {
|
||||
name: 'my',
|
||||
age: 18,
|
||||
}),
|
||||
).toBe('http://api.com/users/name/my/age/18/list');
|
||||
});
|
||||
});
|
|
@ -1,13 +1,15 @@
|
|||
import { describe, test, expect } from 'vitest';
|
||||
import { assert, throwError } from 'src/helpers/error';
|
||||
import { captureError, cleanedStack } from 'scripts/test.utils';
|
||||
import { assert, throwError, cleanStack } from 'src/helpers/error';
|
||||
|
||||
describe('测试 src/helpers/error.ts', () => {
|
||||
describe('src/helpers/error.ts', () => {
|
||||
test('第一个参数为 true 时应该无事发生', () => {
|
||||
expect(assert(true, '')).toBeUndefined();
|
||||
});
|
||||
|
||||
test('第一个参数为 false 时应该抛出异常', () => {
|
||||
expect(() => assert(false, '')).toThrowError();
|
||||
expect(cleanedStack(captureError(() => assert(false, '')))).toBeTruthy();
|
||||
});
|
||||
|
||||
test('应该抛出异常', () => {
|
||||
|
@ -15,5 +17,17 @@ describe('测试 src/helpers/error.ts', () => {
|
|||
expect(() => throwError('error')).toThrowError(
|
||||
'[axios-miniprogram]: error',
|
||||
);
|
||||
expect(cleanedStack(captureError(() => throwError('error')))).toBeTruthy();
|
||||
});
|
||||
|
||||
test('应该清掉多余的错误栈', () => {
|
||||
const ce = () => new Error();
|
||||
const error = ce();
|
||||
|
||||
expect(cleanedStack(error)).toBeFalsy();
|
||||
|
||||
cleanStack(error);
|
||||
|
||||
expect(cleanedStack(error)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import { describe, test, expect } from 'vitest';
|
||||
import { ignore } from 'src/helpers/ignore';
|
||||
|
||||
describe('src/helpers/ignore.ts', () => {
|
||||
test('不应该改变传入的对象', () => {
|
||||
expect(
|
||||
ignore({
|
||||
v1: 1,
|
||||
}),
|
||||
).toEqual({
|
||||
v1: 1,
|
||||
});
|
||||
});
|
||||
|
||||
test('应该忽略指定键值', () => {
|
||||
expect(
|
||||
ignore(
|
||||
{
|
||||
v1: 1,
|
||||
v2: {},
|
||||
v3: [],
|
||||
v4: undefined,
|
||||
v5: 5,
|
||||
v6: null,
|
||||
},
|
||||
'v1',
|
||||
'v2',
|
||||
'v3',
|
||||
'v4',
|
||||
),
|
||||
).toEqual({ v5: 5, v6: null });
|
||||
});
|
||||
});
|
|
@ -0,0 +1,20 @@
|
|||
import { describe, test, expect } from 'vitest';
|
||||
import { isAbsoluteURL } from 'src/helpers/isAbsoluteURL';
|
||||
|
||||
describe('src/helpers/isAbsoluteURL.ts', () => {
|
||||
test('应该不是绝对路径', () => {
|
||||
expect(isAbsoluteURL('user')).toBeFalsy();
|
||||
expect(isAbsoluteURL('/user')).toBeFalsy();
|
||||
expect(isAbsoluteURL('//user')).toBeFalsy();
|
||||
expect(isAbsoluteURL('://user')).toBeFalsy();
|
||||
});
|
||||
|
||||
test('应该是绝对路径', () => {
|
||||
expect(isAbsoluteURL('http://user')).toBeTruthy();
|
||||
expect(isAbsoluteURL('HTTP://user')).toBeTruthy();
|
||||
expect(isAbsoluteURL('https://user')).toBeTruthy();
|
||||
expect(isAbsoluteURL('custom://user')).toBeTruthy();
|
||||
expect(isAbsoluteURL('custom-v1.0://user')).toBeTruthy();
|
||||
expect(isAbsoluteURL('custom_v1.0://user')).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,63 @@
|
|||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
isArray,
|
||||
isDate,
|
||||
isEmptyArray,
|
||||
isPlainObject,
|
||||
isFunction,
|
||||
isNull,
|
||||
isUndefined,
|
||||
isString,
|
||||
} from 'src/helpers/isTypes';
|
||||
|
||||
describe('src/helpers/isTypes.ts', () => {
|
||||
test('应该能判断是数组', () => {
|
||||
expect(isArray(new Array(1))).toBeTruthy();
|
||||
expect(isArray([])).toBeTruthy();
|
||||
expect(isArray([1])).toBeTruthy();
|
||||
});
|
||||
|
||||
test('应该能判断是空数组', () => {
|
||||
expect(isEmptyArray([1])).toBeFalsy();
|
||||
expect(isArray(new Array(0))).toBeTruthy();
|
||||
expect(isEmptyArray([])).toBeTruthy();
|
||||
});
|
||||
|
||||
test('应该能判断是普通对象', () => {
|
||||
expect(isPlainObject(new String())).toBeFalsy();
|
||||
expect(isPlainObject(new Function())).toBeFalsy();
|
||||
expect(isPlainObject({ v: 1 })).toBeTruthy();
|
||||
expect(isPlainObject(new Object())).toBeTruthy();
|
||||
});
|
||||
|
||||
test('应该能判断是日期', () => {
|
||||
expect(isDate({})).toBeFalsy();
|
||||
expect(isDate(new Date())).toBeTruthy();
|
||||
});
|
||||
|
||||
test('应该能判断是函数', () => {
|
||||
expect(isFunction(() => null)).toBeTruthy();
|
||||
expect(
|
||||
isFunction(function () {
|
||||
return;
|
||||
}),
|
||||
).toBeTruthy();
|
||||
expect(isFunction(new Function())).toBeTruthy();
|
||||
});
|
||||
|
||||
test('应该能判断是 Null', () => {
|
||||
expect(isNull(undefined)).toBeFalsy();
|
||||
expect(isNull(null)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('应该能判断是 Undefined', () => {
|
||||
expect(isUndefined(null)).toBeFalsy();
|
||||
expect(isUndefined(undefined)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('应该能判断是字符串', () => {
|
||||
expect(isString(new String())).toBeTruthy();
|
||||
expect(isString('')).toBeTruthy();
|
||||
expect(isString(``)).toBeTruthy();
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue