refactor: 重建响应数据类型
parent
ee6a31b4bb
commit
4c75fa3d32
|
@ -34,6 +34,7 @@
|
||||||
"cz": "czg",
|
"cz": "czg",
|
||||||
"build": "esno scripts/build.ts",
|
"build": "esno scripts/build.ts",
|
||||||
"build:asset": "esno scripts/build-asset.ts",
|
"build:asset": "esno scripts/build-asset.ts",
|
||||||
|
"watch": "pnpm build -a -w",
|
||||||
"release": "esno scripts/release.ts",
|
"release": "esno scripts/release.ts",
|
||||||
"publish:ci": "esno scripts/publish.ts",
|
"publish:ci": "esno scripts/publish.ts",
|
||||||
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
|
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
|
||||||
|
|
|
@ -28,7 +28,7 @@ export function noop() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mockResponseBase(
|
export function mockResponse(
|
||||||
status: number,
|
status: number,
|
||||||
statusText: string,
|
statusText: string,
|
||||||
headers: AnyObject,
|
headers: AnyObject,
|
||||||
|
@ -42,17 +42,6 @@ export function mockResponseBase(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mockResponse(headers: AnyObject = {}, data: AnyObject = {}) {
|
|
||||||
return mockResponseBase(200, 'OK', headers, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function mockResponseError(
|
|
||||||
headers: AnyObject = {},
|
|
||||||
data: AnyObject = {},
|
|
||||||
) {
|
|
||||||
return mockResponseBase(400, 'FAIL', headers, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MockAdapterOptions {
|
export interface MockAdapterOptions {
|
||||||
headers?: AnyObject;
|
headers?: AnyObject;
|
||||||
data?: AnyObject;
|
data?: AnyObject;
|
||||||
|
@ -68,21 +57,33 @@ export function mockAdapterBase(
|
||||||
const { headers = {}, data = {}, delay = 0, before, after } = options;
|
const { headers = {}, data = {}, delay = 0, before, after } = options;
|
||||||
|
|
||||||
return (config: AxiosAdapterRequestConfig) => {
|
return (config: AxiosAdapterRequestConfig) => {
|
||||||
|
let canceled = false;
|
||||||
|
|
||||||
before?.(config);
|
before?.(config);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
if (!canceled) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'success':
|
case 'success':
|
||||||
config.success(mockResponse(headers, data));
|
config.success(mockResponse(200, 'OK', headers, data));
|
||||||
break;
|
break;
|
||||||
case 'error':
|
case 'error':
|
||||||
config.success(mockResponseError(headers, data));
|
config.success(mockResponse(500, 'ERROR', headers, data));
|
||||||
break;
|
break;
|
||||||
case 'fail':
|
case 'fail':
|
||||||
config.fail(mockResponseError(headers));
|
config.fail(mockResponse(400, 'FAIL', headers, data));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
after?.();
|
after?.();
|
||||||
|
}
|
||||||
}, delay);
|
}, delay);
|
||||||
|
|
||||||
|
return {
|
||||||
|
abort() {
|
||||||
|
canceled = true;
|
||||||
|
},
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ import {
|
||||||
AxiosProgressCallback,
|
AxiosProgressCallback,
|
||||||
AxiosRequestFormData,
|
AxiosRequestFormData,
|
||||||
AxiosRequestHeaders,
|
AxiosRequestHeaders,
|
||||||
AxiosResponse,
|
|
||||||
} from './core/Axios';
|
} from './core/Axios';
|
||||||
|
|
||||||
export type AxiosAdapterRequestType = 'request' | 'download' | 'upload';
|
export type AxiosAdapterRequestType = 'request' | 'download' | 'upload';
|
||||||
|
@ -24,7 +23,7 @@ export type AxiosAdapterRequestMethod =
|
||||||
| 'TRACE'
|
| 'TRACE'
|
||||||
| 'CONNECT';
|
| 'CONNECT';
|
||||||
|
|
||||||
export interface AxiosAdapterResponse<TData = unknown> extends AnyObject {
|
export interface AxiosAdapterResponse extends AnyObject {
|
||||||
/**
|
/**
|
||||||
* 状态码
|
* 状态码
|
||||||
*/
|
*/
|
||||||
|
@ -40,7 +39,7 @@ export interface AxiosAdapterResponse<TData = unknown> extends AnyObject {
|
||||||
/**
|
/**
|
||||||
* 响应数据
|
* 响应数据
|
||||||
*/
|
*/
|
||||||
data: TData;
|
data: string | ArrayBuffer | AnyObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AxiosAdapterResponseError extends AnyObject {
|
export interface AxiosAdapterResponseError extends AnyObject {
|
||||||
|
@ -107,8 +106,8 @@ export interface AxiosAdapterRequestConfig extends AnyObject {
|
||||||
|
|
||||||
export interface AxiosAdapterBaseOptions extends AxiosAdapterRequestConfig {
|
export interface AxiosAdapterBaseOptions extends AxiosAdapterRequestConfig {
|
||||||
header?: AxiosRequestHeaders;
|
header?: AxiosRequestHeaders;
|
||||||
success(response: unknown): void;
|
success(response: AxiosAdapterResponse): void;
|
||||||
fail(error: unknown): void;
|
fail(error: AxiosAdapterResponseError): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AxiosAdapterUploadOptions
|
export interface AxiosAdapterUploadOptions
|
||||||
|
@ -239,10 +238,10 @@ export function createAdapter(platform: AxiosPlatform): AxiosAdapter {
|
||||||
download: AxiosAdapterDownload,
|
download: AxiosAdapterDownload,
|
||||||
baseOptions: AxiosAdapterBaseOptions,
|
baseOptions: AxiosAdapterBaseOptions,
|
||||||
): AxiosAdapterTask {
|
): AxiosAdapterTask {
|
||||||
const options = {
|
const options: AxiosAdapterDownloadOptions = {
|
||||||
...baseOptions,
|
...baseOptions,
|
||||||
filePath: baseOptions.params?.filePath,
|
filePath: baseOptions.params?.filePath,
|
||||||
success(response: AnyObject): void {
|
success(response): void {
|
||||||
injectDownloadData(response);
|
injectDownloadData(response);
|
||||||
baseOptions.success(response);
|
baseOptions.success(response);
|
||||||
},
|
},
|
||||||
|
@ -275,7 +274,7 @@ export function createAdapter(platform: AxiosPlatform): AxiosAdapter {
|
||||||
return {
|
return {
|
||||||
...config,
|
...config,
|
||||||
header: config.headers,
|
header: config.headers,
|
||||||
success(response: AxiosResponse<unknown>): void {
|
success(response): void {
|
||||||
transformResult(response);
|
transformResult(response);
|
||||||
config.success(response);
|
config.success(response);
|
||||||
},
|
},
|
||||||
|
|
|
@ -61,7 +61,7 @@ function createInstance(defaults: AxiosRequestConfig) {
|
||||||
|
|
||||||
Object.assign(instance, context, {
|
Object.assign(instance, context, {
|
||||||
// instance.fork 内部调用了 context 的私有方法
|
// instance.fork 内部调用了 context 的私有方法
|
||||||
// 所以直接调用 instance.fork 会导致程序会抛出无法访问私有方法的异常
|
// 所以直接调用 instance.fork 会导致程序抛出无法访问私有方法的异常
|
||||||
// instance.fork 调用时 this 重新指向 context,解决此问题
|
// instance.fork 调用时 this 重新指向 context,解决此问题
|
||||||
fork: context.fork.bind(context),
|
fork: context.fork.bind(context),
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
AxiosAdapterResponseError,
|
AxiosAdapterResponseError,
|
||||||
} from '../adapter';
|
} from '../adapter';
|
||||||
import { CancelToken } from './cancel';
|
import { CancelToken } from './cancel';
|
||||||
import dispatchRequest from './dispatchRequest';
|
import { dispatchRequest } from './dispatchRequest';
|
||||||
import InterceptorManager from './InterceptorManager';
|
import InterceptorManager from './InterceptorManager';
|
||||||
import { AxiosTransformer } from './transformData';
|
import { AxiosTransformer } from './transformData';
|
||||||
import AxiosDomain from './AxiosDomain';
|
import AxiosDomain from './AxiosDomain';
|
||||||
|
@ -79,6 +79,13 @@ export interface AxiosRequestFormData extends AnyObject {
|
||||||
|
|
||||||
export type AxiosRequestData = AnyObject | AxiosRequestFormData;
|
export type AxiosRequestData = AnyObject | AxiosRequestFormData;
|
||||||
|
|
||||||
|
export type AxiosResponseData =
|
||||||
|
| undefined
|
||||||
|
| number
|
||||||
|
| string
|
||||||
|
| ArrayBuffer
|
||||||
|
| AnyObject;
|
||||||
|
|
||||||
export interface AxiosProgressEvent {
|
export interface AxiosProgressEvent {
|
||||||
progress: number;
|
progress: number;
|
||||||
totalBytesSent: number;
|
totalBytesSent: number;
|
||||||
|
@ -90,9 +97,8 @@ export interface AxiosProgressCallback {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AxiosRequestConfig
|
export interface AxiosRequestConfig
|
||||||
extends Omit<
|
extends Partial<
|
||||||
Partial<AxiosAdapterRequestConfig>,
|
Omit<AxiosAdapterRequestConfig, 'type' | 'success' | 'fail'>
|
||||||
'type' | 'method' | 'success' | 'fail'
|
|
||||||
> {
|
> {
|
||||||
/**
|
/**
|
||||||
* 请求适配器
|
* 请求适配器
|
||||||
|
@ -102,6 +108,10 @@ export interface AxiosRequestConfig
|
||||||
* 基础路径
|
* 基础路径
|
||||||
*/
|
*/
|
||||||
baseURL?: string;
|
baseURL?: string;
|
||||||
|
/**
|
||||||
|
* 请求的 URL
|
||||||
|
*/
|
||||||
|
url?: string;
|
||||||
/**
|
/**
|
||||||
* 请求参数
|
* 请求参数
|
||||||
*/
|
*/
|
||||||
|
@ -133,11 +143,11 @@ export interface AxiosRequestConfig
|
||||||
/**
|
/**
|
||||||
* 转换请求数据
|
* 转换请求数据
|
||||||
*/
|
*/
|
||||||
transformRequest?: AxiosTransformer | AxiosTransformer[];
|
transformRequest?: AxiosTransformer<AxiosRequestData>;
|
||||||
/**
|
/**
|
||||||
* 转换响应数据
|
* 转换响应数据
|
||||||
*/
|
*/
|
||||||
transformResponse?: AxiosTransformer | AxiosTransformer[];
|
transformResponse?: AxiosTransformer<AxiosResponseData>;
|
||||||
/**
|
/**
|
||||||
* 异常处理
|
* 异常处理
|
||||||
*/
|
*/
|
||||||
|
@ -160,8 +170,9 @@ export interface AxiosRequestConfig
|
||||||
validateStatus?: (status: number) => boolean;
|
validateStatus?: (status: number) => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AxiosResponse<TData = unknown>
|
export interface AxiosResponse<
|
||||||
extends AxiosAdapterResponse<TData> {
|
TData extends AxiosResponseData = AxiosResponseData,
|
||||||
|
> extends Omit<AxiosAdapterResponse, 'data'> {
|
||||||
/**
|
/**
|
||||||
* 请求配置
|
* 请求配置
|
||||||
*/
|
*/
|
||||||
|
@ -170,6 +181,10 @@ export interface AxiosResponse<TData = unknown>
|
||||||
* 请求任务
|
* 请求任务
|
||||||
*/
|
*/
|
||||||
request?: AxiosAdapterTask;
|
request?: AxiosAdapterTask;
|
||||||
|
/**
|
||||||
|
* 响应数据
|
||||||
|
*/
|
||||||
|
data: TData;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AxiosResponseError extends AxiosAdapterResponseError {
|
export interface AxiosResponseError extends AxiosAdapterResponseError {
|
||||||
|
@ -233,22 +248,17 @@ export default class Axios extends AxiosDomain {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#processRequest<TData = unknown>(config: AxiosRequestConfig) {
|
#processRequest(config: AxiosRequestConfig) {
|
||||||
const { request, response } = this.interceptors;
|
const { request, response } = this.interceptors;
|
||||||
|
|
||||||
let promiseRequest = Promise.resolve(config);
|
let promiseRequest = Promise.resolve(config);
|
||||||
request.forEach(({ resolved, rejected }) => {
|
request.forEach(({ resolved, rejected }) => {
|
||||||
promiseRequest = promiseRequest.then(
|
promiseRequest = promiseRequest.then(resolved, rejected);
|
||||||
resolved,
|
|
||||||
rejected,
|
|
||||||
) as Promise<AxiosRequestConfig>;
|
|
||||||
}, true);
|
}, true);
|
||||||
let promiseResponse = promiseRequest.then(dispatchRequest);
|
let promiseResponse = promiseRequest.then(dispatchRequest);
|
||||||
response.forEach(({ resolved, rejected }) => {
|
response.forEach(({ resolved, rejected }) => {
|
||||||
promiseResponse = promiseResponse.then(resolved, rejected) as Promise<
|
promiseResponse = promiseResponse.then(resolved, rejected);
|
||||||
AxiosResponse<unknown>
|
|
||||||
>;
|
|
||||||
});
|
});
|
||||||
return promiseResponse as Promise<AxiosResponse<TData>>;
|
return promiseResponse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,21 @@
|
||||||
import { isString, isUndefined } from '../helpers/isTypes';
|
import { isString, isUndefined } from '../helpers/isTypes';
|
||||||
import { deepMerge } from '../helpers/deepMerge';
|
import { deepMerge } from '../helpers/deepMerge';
|
||||||
import { mergeConfig } from './mergeConfig';
|
import { mergeConfig } from './mergeConfig';
|
||||||
import { AxiosRequestConfig, AxiosRequestData, AxiosResponse } from './Axios';
|
import {
|
||||||
|
AxiosRequestConfig,
|
||||||
|
AxiosRequestData,
|
||||||
|
AxiosResponse,
|
||||||
|
AxiosResponseData,
|
||||||
|
} from './Axios';
|
||||||
|
|
||||||
export interface AxiosDomainRequest {
|
export interface AxiosDomainRequest {
|
||||||
<TData = unknown>(
|
<TData extends AxiosResponseData>(
|
||||||
/**
|
/**
|
||||||
* 请求配置
|
* 请求配置
|
||||||
*/
|
*/
|
||||||
config: AxiosRequestConfig,
|
config: AxiosRequestConfig,
|
||||||
): Promise<AxiosResponse<TData>>;
|
): Promise<AxiosResponse<TData>>;
|
||||||
<TData = unknown>(
|
<TData extends AxiosResponseData>(
|
||||||
/**
|
/**
|
||||||
* 请求地址
|
* 请求地址
|
||||||
*/
|
*/
|
||||||
|
@ -23,7 +28,7 @@ export interface AxiosDomainRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AxiosDomainAsRequest {
|
export interface AxiosDomainAsRequest {
|
||||||
<TData = unknown>(
|
<TData extends AxiosResponseData>(
|
||||||
/**
|
/**
|
||||||
* 请求地址
|
* 请求地址
|
||||||
*/
|
*/
|
||||||
|
@ -36,7 +41,7 @@ export interface AxiosDomainAsRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AxiosDomainAsRequestWithParams {
|
export interface AxiosDomainAsRequestWithParams {
|
||||||
<TData = unknown>(
|
<TData extends AxiosResponseData>(
|
||||||
/**
|
/**
|
||||||
* 请求地址
|
* 请求地址
|
||||||
*/
|
*/
|
||||||
|
@ -53,7 +58,7 @@ export interface AxiosDomainAsRequestWithParams {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AxiosDomainAsRequestWithData {
|
export interface AxiosDomainAsRequestWithData {
|
||||||
<TData = unknown>(
|
<TData extends AxiosResponseData>(
|
||||||
/**
|
/**
|
||||||
* 请求地址
|
* 请求地址
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2,17 +2,17 @@ export interface InterceptorResolved<T = unknown> {
|
||||||
(value: T): T | Promise<T>;
|
(value: T): T | Promise<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InterceptorRejected {
|
export interface InterceptorRejected<T = unknown> {
|
||||||
(error: unknown): unknown | Promise<unknown>;
|
(error: unknown): T | Promise<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Interceptor<T = unknown> {
|
export interface Interceptor<T = unknown> {
|
||||||
resolved: InterceptorResolved<T>;
|
resolved: InterceptorResolved<T>;
|
||||||
rejected?: InterceptorRejected;
|
rejected?: InterceptorRejected<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InterceptorExecutor {
|
export interface InterceptorExecutor<T = unknown> {
|
||||||
(interceptor: Interceptor): void;
|
(interceptor: Interceptor<T>): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class InterceptorManager<T = unknown> {
|
export default class InterceptorManager<T = unknown> {
|
||||||
|
@ -22,7 +22,7 @@ export default class InterceptorManager<T = unknown> {
|
||||||
|
|
||||||
use(
|
use(
|
||||||
resolved: InterceptorResolved<T>,
|
resolved: InterceptorResolved<T>,
|
||||||
rejected?: InterceptorRejected,
|
rejected?: InterceptorRejected<T>,
|
||||||
): number {
|
): number {
|
||||||
this.#interceptors[++this.#id] = {
|
this.#interceptors[++this.#id] = {
|
||||||
resolved,
|
resolved,
|
||||||
|
@ -36,8 +36,8 @@ export default class InterceptorManager<T = unknown> {
|
||||||
delete this.#interceptors[id];
|
delete this.#interceptors[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
forEach(executor: InterceptorExecutor, reverse?: boolean): void {
|
forEach(executor: InterceptorExecutor<T>, reverse?: boolean): void {
|
||||||
let interceptors: Interceptor<any>[] = Object.values(this.#interceptors);
|
let interceptors: Interceptor<T>[] = Object.values(this.#interceptors);
|
||||||
if (reverse) interceptors = interceptors.reverse();
|
if (reverse) interceptors = interceptors.reverse();
|
||||||
interceptors.forEach(executor);
|
interceptors.forEach(executor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ export function createError(
|
||||||
config: AxiosRequestConfig,
|
config: AxiosRequestConfig,
|
||||||
response: AxiosErrorResponse,
|
response: AxiosErrorResponse,
|
||||||
request: AxiosAdapterTask,
|
request: AxiosAdapterTask,
|
||||||
): AxiosError {
|
) {
|
||||||
const axiosError = new AxiosError(message, config, response, request);
|
const axiosError = new AxiosError(message, config, response, request);
|
||||||
cleanStack(axiosError);
|
cleanStack(axiosError);
|
||||||
return axiosError;
|
return axiosError;
|
||||||
|
|
|
@ -14,29 +14,30 @@ function throwIfCancellationRequested(config: AxiosRequestConfig) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function dispatchRequest<TData = unknown>(
|
export function dispatchRequest(config: AxiosRequestConfig) {
|
||||||
config: AxiosRequestConfig,
|
|
||||||
): Promise<AxiosResponse> {
|
|
||||||
throwIfCancellationRequested(config);
|
throwIfCancellationRequested(config);
|
||||||
|
|
||||||
const { transformRequest, transformResponse } = config;
|
const { transformRequest, transformResponse } = config;
|
||||||
|
|
||||||
config.url = transformURL(config);
|
config.url = transformURL(config);
|
||||||
config.method = config.method ?? 'get';
|
config.method = config.method ?? 'get';
|
||||||
config.headers = flattenHeaders(config);
|
config.headers = flattenHeaders(config);
|
||||||
|
|
||||||
transform(config, transformRequest);
|
transformer(config, transformRequest);
|
||||||
|
|
||||||
function onSuccess(response: AxiosResponse<TData>) {
|
function onSuccess(response: AxiosResponse) {
|
||||||
throwIfCancellationRequested(config);
|
throwIfCancellationRequested(config);
|
||||||
transform(response, transformResponse);
|
|
||||||
|
transformer(response, transformResponse);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onError(reason: unknown) {
|
function onError(reason: unknown) {
|
||||||
if (!isCancel(reason)) {
|
if (!isCancel(reason)) {
|
||||||
throwIfCancellationRequested(config);
|
throwIfCancellationRequested(config);
|
||||||
|
|
||||||
if (isAxiosError(reason)) {
|
if (isAxiosError(reason)) {
|
||||||
transform(reason.response as AxiosResponse<TData>, transformResponse);
|
transformer(reason.response as AxiosResponse, transformResponse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,16 +48,16 @@ export default function dispatchRequest<TData = unknown>(
|
||||||
return Promise.reject(reason);
|
return Promise.reject(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
function transform<TData = unknown>(
|
function transformer<TData = unknown>(
|
||||||
target: AxiosRequestConfig | AxiosResponse<TData>,
|
targetObject: { data?: TData; headers?: AnyObject },
|
||||||
transformer?: AxiosTransformer | AxiosTransformer[],
|
transformer?: AxiosTransformer<TData>,
|
||||||
) {
|
) {
|
||||||
target.data = transformData(
|
targetObject.data = transformData(
|
||||||
target.data as AnyObject,
|
targetObject.data,
|
||||||
target.headers,
|
targetObject.headers,
|
||||||
transformer,
|
transformer,
|
||||||
) as TData;
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return request<TData>(config).then(onSuccess).catch(onError);
|
return request(config).then(onSuccess).catch(onError);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,7 @@ import { AxiosRequestConfig } from './Axios';
|
||||||
const postRE = /^POST$/i;
|
const postRE = /^POST$/i;
|
||||||
const getRE = /^GET$/i;
|
const getRE = /^GET$/i;
|
||||||
|
|
||||||
export function generateType(
|
export function generateType(config: AxiosRequestConfig) {
|
||||||
config: AxiosRequestConfig,
|
|
||||||
): AxiosAdapterRequestType {
|
|
||||||
let requestType: AxiosAdapterRequestType = 'request';
|
let requestType: AxiosAdapterRequestType = 'request';
|
||||||
|
|
||||||
if (config.upload && postRE.test(config.method!)) {
|
if (config.upload && postRE.test(config.method!)) {
|
||||||
|
|
|
@ -17,7 +17,7 @@ const deepMergeConfigMap: Record<string, boolean> = {
|
||||||
export function mergeConfig(
|
export function mergeConfig(
|
||||||
config1: AxiosRequestConfig = {},
|
config1: AxiosRequestConfig = {},
|
||||||
config2: AxiosRequestConfig = {},
|
config2: AxiosRequestConfig = {},
|
||||||
): AxiosRequestConfig {
|
) {
|
||||||
const config: AxiosRequestConfig = {};
|
const config: AxiosRequestConfig = {};
|
||||||
|
|
||||||
// 所有已知键名
|
// 所有已知键名
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
AxiosProgressCallback,
|
AxiosProgressCallback,
|
||||||
AxiosRequestConfig,
|
AxiosRequestConfig,
|
||||||
AxiosResponse,
|
AxiosResponse,
|
||||||
|
AxiosResponseData,
|
||||||
AxiosResponseError,
|
AxiosResponseError,
|
||||||
} from './Axios';
|
} from './Axios';
|
||||||
import { isCancelToken } from './cancel';
|
import { isCancelToken } from './cancel';
|
||||||
|
@ -38,16 +39,14 @@ function tryToggleProgressUpdate(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function request<TData = unknown>(
|
export function request(config: AxiosRequestConfig) {
|
||||||
config: AxiosRequestConfig,
|
return new Promise<AxiosResponse>((resolve, reject) => {
|
||||||
): Promise<AxiosResponse<TData>> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
assert(isFunction(config.adapter), 'adapter 不是一个 function');
|
assert(isFunction(config.adapter), 'adapter 不是一个 function');
|
||||||
assert(isString(config.url), 'url 不是一个 string');
|
assert(isString(config.url), 'url 不是一个 string');
|
||||||
|
|
||||||
const adapterConfig: AxiosAdapterRequestConfig = {
|
const adapterConfig: AxiosAdapterRequestConfig = {
|
||||||
...config,
|
...config,
|
||||||
url: config.url,
|
url: config.url!,
|
||||||
type: generateType(config),
|
type: generateType(config),
|
||||||
method: config.method!.toUpperCase() as AxiosAdapterRequestMethod,
|
method: config.method!.toUpperCase() as AxiosAdapterRequestMethod,
|
||||||
success,
|
success,
|
||||||
|
@ -56,10 +55,11 @@ export function request<TData = unknown>(
|
||||||
|
|
||||||
const adapterTask = config.adapter!(adapterConfig);
|
const adapterTask = config.adapter!(adapterConfig);
|
||||||
|
|
||||||
function success(_: AxiosAdapterResponse<TData>): void {
|
function success(_: AxiosAdapterResponse): void {
|
||||||
const response = _ as AxiosResponse<TData>;
|
const response = _ as AxiosResponse;
|
||||||
response.config = config;
|
response.config = config;
|
||||||
response.request = adapterTask;
|
response.request = adapterTask;
|
||||||
|
|
||||||
if (config.validateStatus?.(response.status) ?? true) {
|
if (config.validateStatus?.(response.status) ?? true) {
|
||||||
resolve(response);
|
resolve(response);
|
||||||
} else {
|
} else {
|
||||||
|
@ -72,7 +72,7 @@ export function request<TData = unknown>(
|
||||||
responseError.isFail = true;
|
responseError.isFail = true;
|
||||||
responseError.config = config;
|
responseError.config = config;
|
||||||
responseError.request = adapterTask;
|
responseError.request = adapterTask;
|
||||||
catchError(responseError.statusText, responseError);
|
catchError('request fail', responseError);
|
||||||
}
|
}
|
||||||
|
|
||||||
function catchError(
|
function catchError(
|
||||||
|
|
|
@ -1,35 +1,38 @@
|
||||||
import { isArray, isUndefined } from '../helpers/isTypes';
|
import { isArray, isFunction } from '../helpers/isTypes';
|
||||||
import { AxiosRequestData } from './Axios';
|
|
||||||
|
|
||||||
export interface AxiosTransformer {
|
export interface AxiosTransformCallback<TData = unknown> {
|
||||||
(
|
(
|
||||||
/**
|
/**
|
||||||
* 数据
|
* 数据
|
||||||
*/
|
*/
|
||||||
data?: AxiosRequestData,
|
data?: TData,
|
||||||
/**
|
/**
|
||||||
* 头信息
|
* 头信息
|
||||||
*/
|
*/
|
||||||
headers?: AnyObject,
|
headers?: AnyObject,
|
||||||
): AxiosRequestData;
|
): TData | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function transformData(
|
export type AxiosTransformer<TData = unknown> =
|
||||||
data?: AxiosRequestData,
|
| AxiosTransformCallback<TData>
|
||||||
|
| AxiosTransformCallback<TData>[];
|
||||||
|
|
||||||
|
export function transformData<TData = unknown>(
|
||||||
|
data?: TData,
|
||||||
headers?: AnyObject,
|
headers?: AnyObject,
|
||||||
transforms?: AxiosTransformer | AxiosTransformer[],
|
transforms?: AxiosTransformer<TData>,
|
||||||
): AxiosRequestData | undefined {
|
) {
|
||||||
if (isUndefined(transforms)) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isArray(transforms)) {
|
if (!isArray(transforms)) {
|
||||||
|
if (isFunction(transforms)) {
|
||||||
transforms = [transforms];
|
transforms = [transforms];
|
||||||
|
} else {
|
||||||
|
transforms = [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
transforms.forEach((transform: AxiosTransformer) => {
|
transforms.forEach((transform) => {
|
||||||
data = transform(data, headers);
|
data = transform(data, headers);
|
||||||
});
|
});
|
||||||
|
|
||||||
return data;
|
return data as TData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { dynamicURL } from '../helpers/dynamicURL';
|
||||||
import { isAbsoluteURL } from '../helpers/isAbsoluteURL';
|
import { isAbsoluteURL } from '../helpers/isAbsoluteURL';
|
||||||
import { AxiosRequestConfig } from './Axios';
|
import { AxiosRequestConfig } from './Axios';
|
||||||
|
|
||||||
export function transformURL(config: AxiosRequestConfig): string {
|
export function transformURL(config: AxiosRequestConfig) {
|
||||||
let url = config.url ?? '';
|
let url = config.url ?? '';
|
||||||
|
|
||||||
if (!isAbsoluteURL(url)) url = combineURL(config.baseURL ?? '', url);
|
if (!isAbsoluteURL(url)) url = combineURL(config.baseURL ?? '', url);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { describe, test, expect, beforeEach, afterEach, vi } from 'vitest';
|
import { describe, test, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||||
import { getAdapterDefault } from 'src/adapter';
|
import { getAdapterDefault } from '@/adapter';
|
||||||
|
|
||||||
const platforms = [
|
const platforms = [
|
||||||
'uni',
|
'uni',
|
||||||
|
|
|
@ -1,24 +1,29 @@
|
||||||
import { describe, test, expect, vi } from 'vitest';
|
import { describe, test, expect, vi } from 'vitest';
|
||||||
import { createAdapter } from 'src/adapter';
|
|
||||||
import { noop } from 'scripts/test.utils';
|
import { noop } from 'scripts/test.utils';
|
||||||
|
import { AxiosPlatform, createAdapter } from '@/adapter';
|
||||||
|
|
||||||
describe('src/adapter.ts', () => {
|
describe('src/adapter.ts', () => {
|
||||||
test('应该抛出异常', () => {
|
test('应该抛出异常', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
createAdapter(undefined as any),
|
createAdapter(undefined as unknown as AxiosPlatform),
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
'"[axios-miniprogram]: platform 不是一个 object"',
|
'"[axios-miniprogram]: platform 不是一个 object"',
|
||||||
);
|
);
|
||||||
expect(() => createAdapter({} as any)).toThrowErrorMatchingInlineSnapshot(
|
expect(() =>
|
||||||
|
createAdapter({} as unknown as AxiosPlatform),
|
||||||
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
'"[axios-miniprogram]: request 不是一个 function"',
|
'"[axios-miniprogram]: request 不是一个 function"',
|
||||||
);
|
);
|
||||||
expect(() =>
|
expect(() =>
|
||||||
createAdapter({ request: vi.fn() } as any),
|
createAdapter({ request: vi.fn() } as unknown as AxiosPlatform),
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
'"[axios-miniprogram]: upload 不是一个 function"',
|
'"[axios-miniprogram]: upload 不是一个 function"',
|
||||||
);
|
);
|
||||||
expect(() =>
|
expect(() =>
|
||||||
createAdapter({ request: vi.fn(), upload: vi.fn() } as any),
|
createAdapter({
|
||||||
|
request: vi.fn(),
|
||||||
|
upload: vi.fn(),
|
||||||
|
} as unknown as AxiosPlatform),
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
'"[axios-miniprogram]: download 不是一个 function"',
|
'"[axios-miniprogram]: download 不是一个 function"',
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,136 +1,17 @@
|
||||||
import { describe, test, expect, beforeAll, afterAll } from 'vitest';
|
import { describe, test, expect } from 'vitest';
|
||||||
import { mockAdapter } from 'scripts/test.utils';
|
import Axios from '@/core/Axios';
|
||||||
import Axios from '../src/core/Axios';
|
import { CancelToken, isCancel } from '@/core/cancel';
|
||||||
import { CancelToken, isCancel } from '../src/core/cancel';
|
import { isAxiosError } from '@/core/createError';
|
||||||
import { isAxiosError } from '../src/core/createError';
|
import { createAdapter } from '@/adapter';
|
||||||
import { createAdapter } from '../src/adapter';
|
import axios from '@/axios';
|
||||||
import defaults from '../src/defaults';
|
|
||||||
import axios from '../src/axios';
|
|
||||||
|
|
||||||
describe('src/axios.ts', () => {
|
describe('src/axios.ts', () => {
|
||||||
const data = {
|
|
||||||
result: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeAll(() => {
|
|
||||||
axios.defaults.baseURL = 'http://api.com';
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
axios.defaults.baseURL = undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
test('应该有这些静态属性', () => {
|
test('应该有这些静态属性', () => {
|
||||||
expect(axios.defaults).toBe(defaults);
|
|
||||||
expect(axios.Axios).toBe(Axios);
|
expect(axios.Axios).toBe(Axios);
|
||||||
expect(axios.CancelToken).toBe(CancelToken);
|
expect(axios.CancelToken).toBe(CancelToken);
|
||||||
|
expect(axios.create).toBeTypeOf('function');
|
||||||
expect(axios.createAdapter).toBe(createAdapter);
|
expect(axios.createAdapter).toBe(createAdapter);
|
||||||
expect(axios.isCancel).toBe(isCancel);
|
expect(axios.isCancel).toBe(isCancel);
|
||||||
expect(axios.isAxiosError).toBe(isAxiosError);
|
expect(axios.isAxiosError).toBe(isAxiosError);
|
||||||
|
|
||||||
expect(axios.interceptors).toBeTypeOf('object');
|
|
||||||
expect(axios.create).toBeTypeOf('function');
|
|
||||||
expect(axios.request).toBeTypeOf('function');
|
|
||||||
|
|
||||||
expect(axios.getUri).toBeTypeOf('function');
|
|
||||||
expect(axios.fork).toBeTypeOf('function');
|
|
||||||
|
|
||||||
[...Axios.as, ...Axios.asp, ...Axios.asd].forEach((k) => {
|
|
||||||
expect(axios[k]).toBeTypeOf('function');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('应该可以发送普通别名请求', () => {
|
|
||||||
const c = {
|
|
||||||
adapter: mockAdapter({
|
|
||||||
before: (config) => {
|
|
||||||
expect(config.url).toBe('http://api.com/test');
|
|
||||||
},
|
|
||||||
data,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
Axios.as.forEach((a) => {
|
|
||||||
axios[a]('test', c).then((res) => {
|
|
||||||
expect(res.data).toEqual(data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('应该可以发送带参数的别名请求', () => {
|
|
||||||
const p = { id: 1 };
|
|
||||||
const c1 = {
|
|
||||||
adapter: mockAdapter({
|
|
||||||
before: (config) => {
|
|
||||||
expect(config.url).toBe('http://api.com/test?id=1');
|
|
||||||
expect(config.params).toEqual(p);
|
|
||||||
},
|
|
||||||
data,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
const c2 = {
|
|
||||||
adapter: mockAdapter({
|
|
||||||
before: (config) => {
|
|
||||||
expect(config.url).toBe('http://api.com/test/1?id=1');
|
|
||||||
expect(config.params).toEqual(p);
|
|
||||||
},
|
|
||||||
data,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
Axios.asp.forEach((a) => {
|
|
||||||
axios[a]('test', p, c1).then((res) => {
|
|
||||||
expect(res.data).toEqual(data);
|
|
||||||
});
|
|
||||||
axios[a]('test/:id', p, c2).then((res) => {
|
|
||||||
expect(res.data).toEqual(data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('应该可以发送带数据的别名请求', () => {
|
|
||||||
const d = { id: 1 };
|
|
||||||
const c1 = {
|
|
||||||
adapter: mockAdapter({
|
|
||||||
before: (config) => {
|
|
||||||
expect(config.url).toBe('http://api.com/test');
|
|
||||||
expect(config.data).toEqual(d);
|
|
||||||
},
|
|
||||||
data,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
const c2 = {
|
|
||||||
adapter: mockAdapter({
|
|
||||||
before: (config) => {
|
|
||||||
expect(config.url).toBe('http://api.com/test/1');
|
|
||||||
expect(config.data).toEqual(d);
|
|
||||||
},
|
|
||||||
data,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
Axios.asd.forEach((a) => {
|
|
||||||
axios[a]('test', d, c1).then((res) => {
|
|
||||||
expect(res.data).toEqual(data);
|
|
||||||
});
|
|
||||||
axios[a]('test/:id', d, c2).then((res) => {
|
|
||||||
expect(res.data).toEqual(data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('应该可以获取 URI', () => {
|
|
||||||
expect(
|
|
||||||
axios.getUri({
|
|
||||||
url: 'test',
|
|
||||||
}),
|
|
||||||
).toBe('test');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('应该可以派生领域', () => {
|
|
||||||
const a = axios.fork({
|
|
||||||
baseURL: 'test',
|
|
||||||
});
|
|
||||||
expect(a.defaults.baseURL).toBe('http://api.com/test');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
import { describe, test, expect, beforeAll, afterAll } from 'vitest';
|
||||||
|
import { mockAdapter } from 'scripts/test.utils';
|
||||||
|
import Axios from '@/core/Axios';
|
||||||
|
import defaults from '@/defaults';
|
||||||
|
import axios from '@/axios';
|
||||||
|
|
||||||
|
describe('src/axios.ts', () => {
|
||||||
|
const data = {
|
||||||
|
result: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
axios.defaults.baseURL = 'http://api.com';
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
axios.defaults.baseURL = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该有这些实例属性及方法', () => {
|
||||||
|
expect(axios.defaults).toBe(defaults);
|
||||||
|
expect(axios.interceptors).toBeTypeOf('object');
|
||||||
|
expect(axios.getUri).toBeTypeOf('function');
|
||||||
|
expect(axios.fork).toBeTypeOf('function');
|
||||||
|
expect(axios.request).toBeTypeOf('function');
|
||||||
|
|
||||||
|
[...Axios.as, ...Axios.asp, ...Axios.asd].forEach((k) => {
|
||||||
|
expect(axios[k]).toBeTypeOf('function');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该可以发送普通别名请求', () => {
|
||||||
|
const c = {
|
||||||
|
adapter: mockAdapter({
|
||||||
|
before: (config) => {
|
||||||
|
expect(config.url).toBe('http://api.com/test');
|
||||||
|
},
|
||||||
|
data,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
Axios.as.forEach((a) => {
|
||||||
|
axios[a]('test', c).then((res) => {
|
||||||
|
expect(res.data).toEqual(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该可以发送带参数的别名请求', () => {
|
||||||
|
const p = { id: 1 };
|
||||||
|
const c1 = {
|
||||||
|
adapter: mockAdapter({
|
||||||
|
before: (config) => {
|
||||||
|
expect(config.url).toBe('http://api.com/test?id=1');
|
||||||
|
expect(config.params).toEqual(p);
|
||||||
|
},
|
||||||
|
data,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
const c2 = {
|
||||||
|
adapter: mockAdapter({
|
||||||
|
before: (config) => {
|
||||||
|
expect(config.url).toBe('http://api.com/test/1?id=1');
|
||||||
|
expect(config.params).toEqual(p);
|
||||||
|
},
|
||||||
|
data,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
Axios.asp.forEach((a) => {
|
||||||
|
axios[a]('test', p, c1).then((res) => {
|
||||||
|
expect(res.data).toEqual(data);
|
||||||
|
});
|
||||||
|
axios[a]('test/:id', p, c2).then((res) => {
|
||||||
|
expect(res.data).toEqual(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该可以发送带数据的别名请求', () => {
|
||||||
|
const d = { id: 1 };
|
||||||
|
const c1 = {
|
||||||
|
adapter: mockAdapter({
|
||||||
|
before: (config) => {
|
||||||
|
expect(config.url).toBe('http://api.com/test');
|
||||||
|
expect(config.data).toEqual(d);
|
||||||
|
},
|
||||||
|
data,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
const c2 = {
|
||||||
|
adapter: mockAdapter({
|
||||||
|
before: (config) => {
|
||||||
|
expect(config.url).toBe('http://api.com/test/1');
|
||||||
|
expect(config.data).toEqual(d);
|
||||||
|
},
|
||||||
|
data,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
Axios.asd.forEach((a) => {
|
||||||
|
axios[a]('test', d, c1).then((res) => {
|
||||||
|
expect(res.data).toEqual(data);
|
||||||
|
});
|
||||||
|
axios[a]('test/:id', d, c2).then((res) => {
|
||||||
|
expect(res.data).toEqual(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该可以获取 URI', () => {
|
||||||
|
expect(
|
||||||
|
axios.getUri({
|
||||||
|
url: 'test',
|
||||||
|
}),
|
||||||
|
).toBe('test');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该可以派生领域', () => {
|
||||||
|
const a = axios.fork({
|
||||||
|
baseURL: 'test',
|
||||||
|
});
|
||||||
|
expect(a.defaults.baseURL).toBe('http://api.com/test');
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,6 +1,6 @@
|
||||||
import { describe, test, expect } from 'vitest';
|
import { describe, test, expect } from 'vitest';
|
||||||
import axios from 'src/axios';
|
|
||||||
import { mockAdapter, mockAdapterError } from 'scripts/test.utils';
|
import { mockAdapter, mockAdapterError } from 'scripts/test.utils';
|
||||||
|
import axios from '@/axios';
|
||||||
|
|
||||||
describe('src/axios.ts', () => {
|
describe('src/axios.ts', () => {
|
||||||
test('应该处理成功和失败', () => {
|
test('应该处理成功和失败', () => {
|
||||||
|
|
|
@ -1,27 +1,133 @@
|
||||||
import { describe, test, expect } from 'vitest';
|
import { describe, test, expect } from 'vitest';
|
||||||
import Axios from 'src/core/Axios';
|
import { mockAdapter } from 'scripts/test.utils';
|
||||||
|
import Axios from '@/core/Axios';
|
||||||
|
import AxiosDomain from '@/core/AxiosDomain';
|
||||||
|
|
||||||
describe('src/core/Axios.ts', () => {
|
describe('src/core/Axios.ts', () => {
|
||||||
|
const data = {
|
||||||
|
result: null,
|
||||||
|
};
|
||||||
|
const axios = new Axios({
|
||||||
|
baseURL: 'http://api.com',
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该继承自 AxiosDomain', () => {
|
||||||
|
expect(new Axios() instanceof AxiosDomain).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
test('应该有这些静态属性', () => {
|
test('应该有这些静态属性', () => {
|
||||||
expect(Axios.as).toEqual(['options', 'trace', 'connect']);
|
expect(Axios.as).toEqual(['options', 'trace', 'connect']);
|
||||||
expect(Axios.asp).toEqual(['head', 'get', 'delete']);
|
expect(Axios.asp).toEqual(['head', 'get', 'delete']);
|
||||||
expect(Axios.asd).toEqual(['post', 'put']);
|
expect(Axios.asd).toEqual(['post', 'put']);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('应该有这些实例属性', () => {
|
test('应该有这些实例属性及方法', () => {
|
||||||
const c = {
|
const c = {
|
||||||
baseURL: 'http://api.com',
|
baseURL: 'http://api.com',
|
||||||
};
|
};
|
||||||
const a = new Axios(c);
|
|
||||||
|
|
||||||
expect(a.defaults).toEqual(c);
|
expect(axios.defaults).toEqual(c);
|
||||||
expect(a.interceptors).toBeTypeOf('object');
|
expect(axios.interceptors).toBeTypeOf('object');
|
||||||
expect(a.request).toBeTypeOf('function');
|
expect(axios.request).toBeTypeOf('function');
|
||||||
expect(a.getUri).toBeTypeOf('function');
|
expect(axios.getUri).toBeTypeOf('function');
|
||||||
expect(a.fork).toBeTypeOf('function');
|
expect(axios.fork).toBeTypeOf('function');
|
||||||
|
|
||||||
[...Axios.as, ...Axios.asp, ...Axios.asd].forEach((k) => {
|
[...Axios.as, ...Axios.asp, ...Axios.asd].forEach((k) => {
|
||||||
expect(a[k]).toBeTypeOf('function');
|
expect(axios[k]).toBeTypeOf('function');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('应该可以发送普通别名请求', () => {
|
||||||
|
const c = {
|
||||||
|
adapter: mockAdapter({
|
||||||
|
before: (config) => {
|
||||||
|
expect(config.url).toBe('http://api.com/test');
|
||||||
|
},
|
||||||
|
data,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
Axios.as.forEach((a) => {
|
||||||
|
axios[a]('test', c).then((res) => {
|
||||||
|
expect(res.data).toEqual(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该可以发送带参数的别名请求', () => {
|
||||||
|
const p = { id: 1 };
|
||||||
|
const c1 = {
|
||||||
|
adapter: mockAdapter({
|
||||||
|
before: (config) => {
|
||||||
|
expect(config.url).toBe('http://api.com/test?id=1');
|
||||||
|
expect(config.params).toEqual(p);
|
||||||
|
},
|
||||||
|
data,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
const c2 = {
|
||||||
|
adapter: mockAdapter({
|
||||||
|
before: (config) => {
|
||||||
|
expect(config.url).toBe('http://api.com/test/1?id=1');
|
||||||
|
expect(config.params).toEqual(p);
|
||||||
|
},
|
||||||
|
data,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
Axios.asp.forEach((a) => {
|
||||||
|
axios[a]('test', p, c1).then((res) => {
|
||||||
|
expect(res.data).toEqual(data);
|
||||||
|
});
|
||||||
|
axios[a]('test/:id', p, c2).then((res) => {
|
||||||
|
expect(res.data).toEqual(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该可以发送带数据的别名请求', () => {
|
||||||
|
const d = { id: 1 };
|
||||||
|
const c1 = {
|
||||||
|
adapter: mockAdapter({
|
||||||
|
before: (config) => {
|
||||||
|
expect(config.url).toBe('http://api.com/test');
|
||||||
|
expect(config.data).toEqual(d);
|
||||||
|
},
|
||||||
|
data,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
const c2 = {
|
||||||
|
adapter: mockAdapter({
|
||||||
|
before: (config) => {
|
||||||
|
expect(config.url).toBe('http://api.com/test/1');
|
||||||
|
expect(config.data).toEqual(d);
|
||||||
|
},
|
||||||
|
data,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
Axios.asd.forEach((a) => {
|
||||||
|
axios[a]('test', d, c1).then((res) => {
|
||||||
|
expect(res.data).toEqual(data);
|
||||||
|
});
|
||||||
|
axios[a]('test/:id', d, c2).then((res) => {
|
||||||
|
expect(res.data).toEqual(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该可以获取 URI', () => {
|
||||||
|
expect(
|
||||||
|
axios.getUri({
|
||||||
|
url: 'test',
|
||||||
|
}),
|
||||||
|
).toBe('test');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该可以派生领域', () => {
|
||||||
|
const a = axios.fork({
|
||||||
|
baseURL: 'test',
|
||||||
|
});
|
||||||
|
expect(a.defaults.baseURL).toBe('http://api.com/test');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { describe, test, expect, vi } from 'vitest';
|
import { describe, test, expect, vi } from 'vitest';
|
||||||
import AxiosDomain, { AxiosDomainRequest } from 'src/core/AxiosDomain';
|
import { ignore } from '@/helpers/ignore';
|
||||||
import { ignore } from 'src/helpers/ignore';
|
import AxiosDomain from '@/core/AxiosDomain';
|
||||||
|
import { AxiosResponse } from '@/core/Axios';
|
||||||
|
|
||||||
describe('src/core/AxiosDomain.ts', () => {
|
describe('src/core/AxiosDomain.ts', () => {
|
||||||
test('应该有这些静态属性', () => {
|
test('应该有这些静态属性', () => {
|
||||||
|
@ -48,6 +49,45 @@ describe('src/core/AxiosDomain.ts', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('应该可以调用这些方法', () => {
|
test('应该可以调用这些方法', () => {
|
||||||
|
const cb = vi.fn();
|
||||||
|
const d = {
|
||||||
|
baseURL: 'http://api.com',
|
||||||
|
};
|
||||||
|
const u = 'test';
|
||||||
|
const c = {
|
||||||
|
params: {
|
||||||
|
id: 1,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
id: 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const a = new AxiosDomain(d, async (config) => {
|
||||||
|
cb();
|
||||||
|
|
||||||
|
expect(config.baseURL).toBe(d.baseURL);
|
||||||
|
expect(config.url).toBe(u);
|
||||||
|
expect(config.params).toEqual(c.params);
|
||||||
|
expect(config.data).toEqual(c.data);
|
||||||
|
|
||||||
|
return {} as AxiosResponse;
|
||||||
|
});
|
||||||
|
|
||||||
|
a.request(u, c);
|
||||||
|
|
||||||
|
AxiosDomain.as.forEach((k) => a[k](u, c));
|
||||||
|
AxiosDomain.asp.forEach((k) => a[k](u, c.params, ignore(c, 'params')));
|
||||||
|
AxiosDomain.asd.forEach((k) => a[k](u, c.data, ignore(c, 'data')));
|
||||||
|
|
||||||
|
const l =
|
||||||
|
AxiosDomain.as.length +
|
||||||
|
AxiosDomain.asp.length +
|
||||||
|
AxiosDomain.asd.length +
|
||||||
|
1;
|
||||||
|
expect(cb.mock.calls.length).toBe(l);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该可以直接传入 config 调用这些方法', () => {
|
||||||
const cb = vi.fn();
|
const cb = vi.fn();
|
||||||
const d = {
|
const d = {
|
||||||
baseURL: 'http://api.com',
|
baseURL: 'http://api.com',
|
||||||
|
@ -61,14 +101,16 @@ describe('src/core/AxiosDomain.ts', () => {
|
||||||
id: 1,
|
id: 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const a = new AxiosDomain(d, ((config) => {
|
const a = new AxiosDomain(d, async (config) => {
|
||||||
cb();
|
cb();
|
||||||
|
|
||||||
expect(config.baseURL).toBe(d.baseURL);
|
expect(config.baseURL).toBe(d.baseURL);
|
||||||
expect(config.url).toBe(c.url);
|
expect(config.url).toBe(c.url);
|
||||||
expect(config.params).toEqual(c.params);
|
expect(config.params).toEqual(c.params);
|
||||||
expect(config.data).toEqual(c.data);
|
expect(config.data).toEqual(c.data);
|
||||||
}) as AxiosDomainRequest);
|
|
||||||
|
return {} as AxiosResponse;
|
||||||
|
});
|
||||||
|
|
||||||
a.request(c);
|
a.request(c);
|
||||||
|
|
||||||
|
@ -107,7 +149,7 @@ describe('src/core/AxiosDomain.ts', () => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const a = new AxiosDomain(d, ((config) => {
|
const a = new AxiosDomain(d, async (config) => {
|
||||||
expect(config.params).toEqual({
|
expect(config.params).toEqual({
|
||||||
v1: 1,
|
v1: 1,
|
||||||
v2: {
|
v2: {
|
||||||
|
@ -116,7 +158,9 @@ describe('src/core/AxiosDomain.ts', () => {
|
||||||
},
|
},
|
||||||
v3: 3,
|
v3: 3,
|
||||||
});
|
});
|
||||||
}) as AxiosDomainRequest);
|
|
||||||
|
return {} as AxiosResponse;
|
||||||
|
});
|
||||||
|
|
||||||
AxiosDomain.asp.forEach((k) => a[k]('test', p, c));
|
AxiosDomain.asp.forEach((k) => a[k]('test', p, c));
|
||||||
});
|
});
|
||||||
|
@ -140,7 +184,7 @@ describe('src/core/AxiosDomain.ts', () => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const a = new AxiosDomain(ds, ((config) => {
|
const a = new AxiosDomain(ds, async (config) => {
|
||||||
expect(config.data).toEqual({
|
expect(config.data).toEqual({
|
||||||
v1: 1,
|
v1: 1,
|
||||||
v2: {
|
v2: {
|
||||||
|
@ -149,7 +193,9 @@ describe('src/core/AxiosDomain.ts', () => {
|
||||||
},
|
},
|
||||||
v3: 3,
|
v3: 3,
|
||||||
});
|
});
|
||||||
}) as AxiosDomainRequest);
|
|
||||||
|
return {} as AxiosResponse;
|
||||||
|
});
|
||||||
|
|
||||||
AxiosDomain.asd.forEach((k) => a[k]('test', d, c));
|
AxiosDomain.asd.forEach((k) => a[k]('test', d, c));
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { describe, test, expect, vi } from 'vitest';
|
import { describe, test, expect, vi } from 'vitest';
|
||||||
import InterceptorManager from 'src/core/InterceptorManager';
|
import InterceptorManager from '@/core/InterceptorManager';
|
||||||
|
|
||||||
describe('src/core/InterceptorManager.ts', () => {
|
describe('src/core/InterceptorManager.ts', () => {
|
||||||
test('应该有这些实例属性', () => {
|
test('应该有这些实例属性', () => {
|
||||||
|
|
|
@ -7,12 +7,7 @@ import {
|
||||||
asyncTimeout,
|
asyncTimeout,
|
||||||
} from 'scripts/test.utils';
|
} from 'scripts/test.utils';
|
||||||
import axios from 'src/axios';
|
import axios from 'src/axios';
|
||||||
import {
|
import { Cancel, isCancel, CancelToken, isCancelToken } from '@/core/cancel';
|
||||||
Cancel,
|
|
||||||
isCancel,
|
|
||||||
CancelToken,
|
|
||||||
isCancelToken,
|
|
||||||
} from '../../src/core/cancel';
|
|
||||||
|
|
||||||
describe('src/helpers/cancel.ts', () => {
|
describe('src/helpers/cancel.ts', () => {
|
||||||
test('应该支持空参数', () => {
|
test('应该支持空参数', () => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { describe, test, expect } from 'vitest';
|
import { describe, test, expect } from 'vitest';
|
||||||
import { checkStack } from 'scripts/test.utils';
|
import { checkStack } from 'scripts/test.utils';
|
||||||
import { createError, isAxiosError } from 'src/core/createError';
|
import { createError, isAxiosError } from '@/core/createError';
|
||||||
|
|
||||||
describe('src/core/createError.ts', () => {
|
describe('src/core/createError.ts', () => {
|
||||||
test('应该支持空参数', () => {
|
test('应该支持空参数', () => {
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { describe, test, expect } from 'vitest';
|
||||||
|
import { dispatchRequest } from 'src/core/dispatchRequest';
|
||||||
|
|
||||||
|
describe('src/core/dispatchRequest.ts', () => {
|
||||||
|
test('应该有这些实例属性', () => {
|
||||||
|
expect(dispatchRequest).toBeTypeOf('function');
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,6 +1,6 @@
|
||||||
import { describe, test, expect } from 'vitest';
|
import { describe, test, expect } from 'vitest';
|
||||||
import { flattenHeaders } from 'src/core/flattenHeaders';
|
import { flattenHeaders } from '@/core/flattenHeaders';
|
||||||
import Axios from 'src/core/Axios';
|
import Axios from '@/core/Axios';
|
||||||
|
|
||||||
describe('src/core/flattenHeaders.ts', () => {
|
describe('src/core/flattenHeaders.ts', () => {
|
||||||
const keys = [...Axios.as, ...Axios.asp, ...Axios.asd];
|
const keys = [...Axios.as, ...Axios.asp, ...Axios.asd];
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { describe, test, expect } from 'vitest';
|
import { describe, test, expect } from 'vitest';
|
||||||
import { generateType } from 'src/core/generateType';
|
import { generateType } from '@/core/generateType';
|
||||||
import Axios from 'src/core/Axios';
|
import Axios from '@/core/Axios';
|
||||||
|
|
||||||
describe('src/core/generateType.ts', () => {
|
describe('src/core/generateType.ts', () => {
|
||||||
test('应该是一个 reuqest', () => {
|
test('应该是一个 reuqest', () => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { describe, test, expect, vi } from 'vitest';
|
import { describe, test, expect, vi } from 'vitest';
|
||||||
import { ignore } from 'src/helpers/ignore';
|
import { ignore } from '@/helpers/ignore';
|
||||||
import { mergeConfig } from 'src/core/mergeConfig';
|
import { mergeConfig } from '@/core/mergeConfig';
|
||||||
import { CancelToken } from 'src/core/cancel';
|
import { CancelToken } from '@/core/cancel';
|
||||||
|
|
||||||
describe('src/core/mergeConfig.ts', () => {
|
describe('src/core/mergeConfig.ts', () => {
|
||||||
test('应该支持空参数', () => {
|
test('应该支持空参数', () => {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { describe, test, expect } from 'vitest';
|
import { describe, test, expect } from 'vitest';
|
||||||
import { request } from 'src/core/request';
|
|
||||||
import {
|
import {
|
||||||
mockAdapter,
|
mockAdapter,
|
||||||
mockAdapterError,
|
mockAdapterError,
|
||||||
mockAdapterFail,
|
mockAdapterFail,
|
||||||
} from 'scripts/test.utils';
|
} from 'scripts/test.utils';
|
||||||
|
import { request } from '@/core/request';
|
||||||
|
|
||||||
describe('src/core/request.ts', () => {
|
describe('src/core/request.ts', () => {
|
||||||
test('应该抛出异常', () => {
|
test('应该抛出异常', () => {
|
||||||
|
@ -18,14 +18,25 @@ describe('src/core/request.ts', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('应该能够取到数据', async () => {
|
test('应该正确的响应请求', async () => {
|
||||||
await expect(
|
const s = request({
|
||||||
request({
|
|
||||||
adapter: mockAdapter(),
|
adapter: mockAdapter(),
|
||||||
url: '/test',
|
url: '/test',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
}),
|
});
|
||||||
).resolves.toMatchInlineSnapshot(`
|
const e = request({
|
||||||
|
adapter: mockAdapterError(),
|
||||||
|
url: '/test',
|
||||||
|
method: 'get',
|
||||||
|
validateStatus: () => false,
|
||||||
|
});
|
||||||
|
const f = request({
|
||||||
|
adapter: mockAdapterFail(),
|
||||||
|
url: '/test',
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(s).resolves.toMatchInlineSnapshot(`
|
||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
"adapter": [Function],
|
"adapter": [Function],
|
||||||
|
@ -34,19 +45,60 @@ describe('src/core/request.ts', () => {
|
||||||
},
|
},
|
||||||
"data": {},
|
"data": {},
|
||||||
"headers": {},
|
"headers": {},
|
||||||
"request": undefined,
|
"request": {
|
||||||
|
"abort": [Function],
|
||||||
|
},
|
||||||
"status": 200,
|
"status": 200,
|
||||||
"statusText": "OK",
|
"statusText": "OK",
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
await expect(
|
|
||||||
request({
|
await expect(e).rejects.toMatchInlineSnapshot(
|
||||||
adapter: mockAdapterError(),
|
'[Error: validate status fail]',
|
||||||
url: '/test',
|
);
|
||||||
method: 'get',
|
await expect(e.catch((e) => Object.assign({}, e))).resolves
|
||||||
}),
|
.toMatchInlineSnapshot(`
|
||||||
).resolves.toMatchInlineSnapshot(`
|
|
||||||
{
|
{
|
||||||
|
"config": {
|
||||||
|
"adapter": [Function],
|
||||||
|
"method": "get",
|
||||||
|
"url": "/test",
|
||||||
|
"validateStatus": [Function],
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"abort": [Function],
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"config": {
|
||||||
|
"adapter": [Function],
|
||||||
|
"method": "get",
|
||||||
|
"url": "/test",
|
||||||
|
"validateStatus": [Function],
|
||||||
|
},
|
||||||
|
"data": {},
|
||||||
|
"headers": {},
|
||||||
|
"request": {
|
||||||
|
"abort": [Function],
|
||||||
|
},
|
||||||
|
"status": 500,
|
||||||
|
"statusText": "ERROR",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
await expect(f).rejects.toMatchInlineSnapshot('[Error: request fail]');
|
||||||
|
await expect(f.catch((e) => Object.assign({}, e))).resolves
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"adapter": [Function],
|
||||||
|
"method": "get",
|
||||||
|
"url": "/test",
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"abort": [Function],
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
"config": {
|
"config": {
|
||||||
"adapter": [Function],
|
"adapter": [Function],
|
||||||
"method": "get",
|
"method": "get",
|
||||||
|
@ -54,17 +106,14 @@ describe('src/core/request.ts', () => {
|
||||||
},
|
},
|
||||||
"data": {},
|
"data": {},
|
||||||
"headers": {},
|
"headers": {},
|
||||||
"request": undefined,
|
"isFail": true,
|
||||||
|
"request": {
|
||||||
|
"abort": [Function],
|
||||||
|
},
|
||||||
"status": 400,
|
"status": 400,
|
||||||
"statusText": "FAIL",
|
"statusText": "FAIL",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
await expect(
|
|
||||||
request({
|
|
||||||
adapter: mockAdapterFail(),
|
|
||||||
url: '/test',
|
|
||||||
method: 'get',
|
|
||||||
}),
|
|
||||||
).rejects.toThrowErrorMatchingInlineSnapshot('"FAIL"');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { describe, test, expect } from 'vitest';
|
import { describe, test, expect } from 'vitest';
|
||||||
import { transformData } from 'src/core/transformData';
|
import { transformData } from '@/core/transformData';
|
||||||
|
|
||||||
describe('src/core/transformData.ts', () => {
|
describe('src/core/transformData.ts', () => {
|
||||||
test('应该支持空配置', () => {
|
test('应该支持空配置', () => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { describe, test, expect } from 'vitest';
|
import { describe, test, expect } from 'vitest';
|
||||||
import { transformURL } from 'src/core/transformURL';
|
import { transformURL } from '@/core/transformURL';
|
||||||
|
|
||||||
describe('src/core/transformURL.ts', () => {
|
describe('src/core/transformURL.ts', () => {
|
||||||
test('应该支持空配置', () => {
|
test('应该支持空配置', () => {
|
||||||
|
|
|
@ -7,7 +7,10 @@
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"moduleResolution": "node"
|
"moduleResolution": "node",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["src/*"]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"include": ["./src", "./test", "./global.d.ts", "./global.variables.d.ts"],
|
"include": ["./src", "./test", "./global.d.ts", "./global.variables.d.ts"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
|
|
|
@ -6,6 +6,9 @@ export default defineConfig({
|
||||||
test: {
|
test: {
|
||||||
root: resolve(__dirname),
|
root: resolve(__dirname),
|
||||||
globals: true,
|
globals: true,
|
||||||
|
alias: {
|
||||||
|
'@': resolve(__dirname, 'src'),
|
||||||
|
},
|
||||||
include: ['./test/**/*.test.ts'],
|
include: ['./test/**/*.test.ts'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue