pull/1/head
954270063@qq.com 2020-04-20 22:33:15 +08:00
parent b505dade41
commit 1f4f65ffd1
30 changed files with 718 additions and 109 deletions

View File

@ -33,10 +33,10 @@ $ npm i axios-miniprogram
## 使用 ## 使用
可以通过将相关配置传递给`axios`来发送请求。
### `axios(config)` ### `axios(config)`
可以通过将相关配置传递给`axios`来发送请求。
```typescript ```typescript
// 发送 GET 请求 // 发送 GET 请求
axios({ axios({
@ -61,10 +61,10 @@ axios({
}); });
``` ```
也可以通过直接把`url`传给`axios`来发送请求。
### `axios(url, config?)` ### `axios(url, config?)`
也可以通过直接把`url`传给`axios`来发送请求。
```typescript ```typescript
// 默认发送 GET 请求 // 默认发送 GET 请求
axios('/test/xxx').then((response) => { axios('/test/xxx').then((response) => {

View File

@ -1,6 +1,6 @@
{ {
"name": "axios-miniprogram", "name": "axios-miniprogram",
"version": "1.0.7", "version": "1.0.9",
"description": "基于 Promise 的 HTTP 请求库,适用于各大小程序平台。", "description": "基于 Promise 的 HTTP 请求库,适用于各大小程序平台。",
"main": "package/index.js", "main": "package/index.js",
"miniprogram": "package", "miniprogram": "package",

View File

@ -2,43 +2,58 @@
* @Author: early-autumn * @Author: early-autumn
* @Date: 2020-04-17 12:18:25 * @Date: 2020-04-17 12:18:25
* @LastEditors: early-autumn * @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 01:14:16 * @LastEditTime: 2020-04-20 21:51:02
*/ */
import { Adapter, Platform } from './types'; import { Adapter, Platform } from './types';
import warning from './helpers/warning';
// 微信小程序
declare let wx: Platform; declare let wx: Platform;
// 支付宝小程序
declare let my: Platform; declare let my: Platform;
// 百度小程序
declare let swan: Platform; declare let swan: Platform;
// 字节跳动小程序
declare let tt: Platform; declare let tt: Platform;
// QQ 小程序
declare let qq: Platform; declare let qq: Platform;
// uniapp
declare let uni: Platform; declare let uni: Platform;
const platformList = [
() => wx.request,
() => my.request,
() => swan.request,
() => tt.request,
() => qq.request,
() => uni.request,
];
/** /**
* *
*
* 使 try + catch , typescript , wx,my,...
*
* ReferenceError: wx is not defined
*/ */
function adaptive(): Adapter | undefined { function adaptive(adapter?: Adapter): Adapter | undefined {
switch (true) { if (adapter !== undefined) {
// 微信小程序 return adapter;
case wx !== undefined: }
return wx.request;
// 支付宝小程序 let request: Adapter | undefined;
case my !== undefined:
return my.request ?? my.httpRequest; try {
// 百度小程序 const platform = platformList.shift();
case swan !== undefined:
return swan.request; if (platform === undefined) {
// 字节跳动小程序 return;
case tt !== undefined: }
return tt.request;
// QQ 小程序 request = platform();
case qq !== undefined:
return qq.request; throw 'next';
// uniapp } catch (err) {
case uni !== undefined: return adaptive(request);
return uni.request;
default:
warning('暂未适配此平台,您需要参阅文档使用自定义适配器手动适配当前平台');
} }
} }

View File

@ -2,7 +2,7 @@
* @Author: early-autumn * @Author: early-autumn
* @Date: 2020-04-15 12:45:18 * @Date: 2020-04-15 12:45:18
* @LastEditors: early-autumn * @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 09:27:03 * @LastEditTime: 2020-04-20 14:48:03
*/ */
import { AxiosRequestConfig, Data, AxiosResponse, AxiosBaseInstance, AxiosInstance } from './types'; import { AxiosRequestConfig, Data, AxiosResponse, AxiosBaseInstance, AxiosInstance } from './types';
import Axios from './core/Axios'; import Axios from './core/Axios';
@ -50,8 +50,10 @@ function createInstance(config: AxiosRequestConfig): AxiosInstance {
return instance.request(requestConfig); return instance.request(requestConfig);
} }
// Axios 实例的所有属性和方法合并至 axios 函数 // instance 的属性设置到 axios 函数中
Object.assign(axios, instance, Object.getPrototypeOf(instance)); Object.assign(axios, instance);
// instance 的方法设置到 axios 函数中
Object.setPrototypeOf(axios, Object.getPrototypeOf(instance));
return axios as AxiosInstance; return axios as AxiosInstance;
} }

View File

@ -2,7 +2,7 @@
* @Author: early-autumn * @Author: early-autumn
* @Date: 2020-04-14 09:23:25 * @Date: 2020-04-14 09:23:25
* @LastEditors: early-autumn * @LastEditors: early-autumn
* @LastEditTime: 2020-04-17 09:27:59 * @LastEditTime: 2020-04-20 15:15:27
*/ */
import Cancel from './Cancel'; import Cancel from './Cancel';
@ -11,6 +11,6 @@ import Cancel from './Cancel';
* *
* @param value * @param value
*/ */
export default function isCancel(value: any) { export default function isCancel(value: any): boolean {
return value && value instanceof Cancel; return !!value && value instanceof Cancel;
} }

View File

@ -2,7 +2,7 @@
* @Author: early-autumn * @Author: early-autumn
* @Date: 2020-04-13 18:00:27 * @Date: 2020-04-13 18:00:27
* @LastEditors: early-autumn * @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 09:12:46 * @LastEditTime: 2020-04-20 13:21:44
*/ */
import { Method, Params, Data, Interceptors, AxiosRequestConfig, AxiosResponse, Axios } from '../types'; import { Method, Params, Data, Interceptors, AxiosRequestConfig, AxiosResponse, Axios } from '../types';
import buildURL from '../helpers/buildURL'; import buildURL from '../helpers/buildURL';
@ -14,7 +14,7 @@ export default class AxiosStatic implements Axios {
/** /**
* *
*/ */
defaults: AxiosRequestConfig; public defaults: AxiosRequestConfig;
/** /**
* Axios * Axios
@ -35,9 +35,9 @@ export default class AxiosStatic implements Axios {
* @param config Axios * @param config Axios
*/ */
public getUri(config: AxiosRequestConfig): string { public getUri(config: AxiosRequestConfig): string {
config = mergeConfig(this.defaults, config); const { url = '', params, paramsSerializer } = mergeConfig(this.defaults, config);
return buildURL(config.url ?? '', config.params, config.paramsSerializer).replace(/^\?/, ''); return buildURL(url, params, paramsSerializer).replace(/^\?/, '');
} }
/** /**
@ -46,9 +46,7 @@ export default class AxiosStatic implements Axios {
* @param config Axios * @param config Axios
*/ */
public request<T extends Data>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> { public request<T extends Data>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> {
config = mergeConfig(this.defaults, config); let promiseRequest = Promise.resolve(mergeConfig(this.defaults, config));
let promiseRequest = Promise.resolve(config);
// 执行请求拦截器 // 执行请求拦截器
this.interceptors.request.forEach(function executor({ resolved, rejected }) { this.interceptors.request.forEach(function executor({ resolved, rejected }) {

View File

@ -2,7 +2,7 @@
* @Author: early-autumn * @Author: early-autumn
* @Date: 2020-04-14 22:23:39 * @Date: 2020-04-14 22:23:39
* @LastEditors: early-autumn * @LastEditors: early-autumn
* @LastEditTime: 2020-04-19 18:49:43 * @LastEditTime: 2020-04-20 13:23:04
*/ */
import { AxiosRequestConfig, RequestConfig, AxiosResponse } from '../types'; import { AxiosRequestConfig, RequestConfig, AxiosResponse } from '../types';
@ -13,22 +13,22 @@ class AxiosError extends Error {
/** /**
* Axios * Axios
*/ */
isAxiosError: boolean; public isAxiosError: boolean;
/** /**
* Axios * Axios
*/ */
config: AxiosRequestConfig; public config: AxiosRequestConfig;
/** /**
* *
*/ */
request: RequestConfig; public request: RequestConfig;
/** /**
* Axios * Axios
*/ */
response?: AxiosResponse; public response?: AxiosResponse;
constructor(message: string, config: AxiosRequestConfig, request: RequestConfig, response?: AxiosResponse) { constructor(message: string, config: AxiosRequestConfig, request: RequestConfig, response?: AxiosResponse) {
super(message); super(message);

View File

@ -2,7 +2,7 @@
* @Author: early-autumn * @Author: early-autumn
* @Date: 2020-04-13 18:01:16 * @Date: 2020-04-13 18:01:16
* @LastEditors: early-autumn * @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 00:54:32 * @LastEditTime: 2020-04-20 13:36:32
*/ */
import { AxiosRequestConfig, AxiosResponse } from '../types'; import { AxiosRequestConfig, AxiosResponse } from '../types';
import isCancel from '../cancel/isCancel'; import isCancel from '../cancel/isCancel';
@ -29,8 +29,6 @@ function throwIfCancellationRequested(config: AxiosRequestConfig) {
export default function dispatchRequest(config: AxiosRequestConfig): Promise<AxiosResponse> { export default function dispatchRequest(config: AxiosRequestConfig): Promise<AxiosResponse> {
throwIfCancellationRequested(config); throwIfCancellationRequested(config);
config.method = config.method ?? 'get';
config.headers = flattenHeaders(config); config.headers = flattenHeaders(config);
config.data = transformData(config.data ?? {}, config.headers, config.transformRequest); config.data = transformData(config.data ?? {}, config.headers, config.transformRequest);

View File

@ -2,10 +2,11 @@
* @Author: early-autumn * @Author: early-autumn
* @Date: 2020-04-18 12:00:01 * @Date: 2020-04-18 12:00:01
* @LastEditors: early-autumn * @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 00:41:57 * @LastEditTime: 2020-04-20 13:44:26
*/ */
import { AliasMethod, Headers, AxiosRequestConfig } from '../types'; import { Headers, AxiosRequestConfig } from '../types';
import { omit } from '../helpers/utils'; import { omit } from '../helpers/utils';
import { methodToLowercase } from './transformMethod';
/** /**
* *
@ -19,7 +20,7 @@ export default function flattenHeaders(config: AxiosRequestConfig): Headers {
return {}; return {};
} }
const method = (config.method as string).toLowerCase() as AliasMethod; const method = methodToLowercase(config.method);
return { return {
...(headers.common ?? {}), ...(headers.common ?? {}),

View File

@ -2,7 +2,7 @@
* @Author: early-autumn * @Author: early-autumn
* @Date: 2020-04-15 22:48:25 * @Date: 2020-04-15 22:48:25
* @LastEditors: early-autumn * @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 10:32:06 * @LastEditTime: 2020-04-20 20:27:37
*/ */
import { AnyObject, AxiosRequestConfig } from '../types'; import { AnyObject, AxiosRequestConfig } from '../types';
import { isPlainObject, deepMerge } from '../helpers/utils'; import { isPlainObject, deepMerge } from '../helpers/utils';
@ -78,12 +78,8 @@ function deepMergeConfig(
keys.forEach((key) => { keys.forEach((key) => {
if (isPlainObject(config2[key])) { if (isPlainObject(config2[key])) {
config[key] = deepMerge(config1[key] ?? {}, config2[key] as AnyObject); config[key] = deepMerge(config1[key] ?? {}, config2[key] as AnyObject);
} else if (config2[key] !== undefined) {
config[key] = config2[key];
} else if (isPlainObject(config1[key])) { } else if (isPlainObject(config1[key])) {
config[key] = deepMerge(config1[key] as AnyObject); config[key] = deepMerge(config1[key] as AnyObject);
} else if (config1[key] !== undefined) {
config[key] = config1[key];
} }
}); });
} }

View File

@ -2,10 +2,9 @@
* @Author: early-autumn * @Author: early-autumn
* @Date: 2020-04-16 00:48:45 * @Date: 2020-04-16 00:48:45
* @LastEditors: early-autumn * @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 01:12:12 * @LastEditTime: 2020-04-20 14:24:07
*/ */
import { AxiosRequestConfig, AxiosResponse, Response } from '../types'; import { AxiosRequestConfig, AxiosResponse, Response } from '../types';
import warning from '../helpers/warning';
import transformRequest from './transformRequest'; import transformRequest from './transformRequest';
import transformResponse from './transformResponse'; import transformResponse from './transformResponse';
import createError from './createError'; import createError from './createError';
@ -35,8 +34,7 @@ export default function request(config: AxiosRequestConfig): Promise<AxiosRespon
} }
if (adapter === undefined) { if (adapter === undefined) {
catchError('暂未适配此平台,您需要参阅文档使用自定义适配器手动适配当前平台'); catchError('平台适配失败,您需要参阅文档使用自定义适配器手动适配当前平台');
warning('暂未适配此平台,您需要参阅文档使用自定义适配器手动适配当前平台');
return; return;
} }

View File

@ -0,0 +1,25 @@
/*
* @Author: early-autumn
* @Date: 2020-04-20 13:31:45
* @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 13:45:11
*/
import { AliasMethod, AdapterMethod, Method } from '../types';
/**
*
*
* @param config Axios
*/
export function methodToLowercase(method: Method = 'get'): AliasMethod {
return method.toLowerCase() as AliasMethod;
}
/**
*
*
* @param config Axios
*/
export function methodToUppercase(method: Method = 'GET'): AdapterMethod {
return method.toUpperCase() as AdapterMethod;
}

View File

@ -2,24 +2,25 @@
* @Author: early-autumn * @Author: early-autumn
* @Date: 2020-04-17 15:05:43 * @Date: 2020-04-17 15:05:43
* @LastEditors: early-autumn * @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 09:19:49 * @LastEditTime: 2020-04-20 13:41:15
*/ */
import { AdapterMethod, AxiosRequestConfig, RequestConfig } from '../types'; import { AxiosRequestConfig, RequestConfig } from '../types';
import { pick } from '../helpers/utils'; import { pick } from '../helpers/utils';
import isAbsoluteURL from '../helpers/isAbsoluteURL'; import isAbsoluteURL from '../helpers/isAbsoluteURL';
import combineURL from '../helpers/combineURL'; import combineURL from '../helpers/combineURL';
import buildURL from '../helpers/buildURL'; import buildURL from '../helpers/buildURL';
import { methodToUppercase } from './transformMethod';
type PickKeys = 'dataType' | 'responseType' | 'timeout' | 'enableHttp2' | 'enableQuic' | 'enableCache' | 'sslVerify'; type PickKeys =
| 'data'
/** | 'headers'
* | 'dataType'
* | 'responseType'
* @param config Axios | 'timeout'
*/ | 'enableHttp2'
function methodUppercase(config: AxiosRequestConfig): AdapterMethod { | 'enableQuic'
return (config.method ?? 'get').toUpperCase() as AdapterMethod; | 'enableCache'
} | 'sslVerify';
/** /**
* baseURL url params URL * baseURL url params URL
@ -42,9 +43,11 @@ function transformURL(config: AxiosRequestConfig): string {
*/ */
export default function transformRequest(config: AxiosRequestConfig): RequestConfig { export default function transformRequest(config: AxiosRequestConfig): RequestConfig {
const url = transformURL(config); const url = transformURL(config);
const method = methodUppercase(config); const method = methodToUppercase(config.method);
const pickRequest = pick<AxiosRequestConfig, PickKeys>( const pickRequest = pick<AxiosRequestConfig, PickKeys>(
config, config,
'data',
'headers',
'dataType', 'dataType',
'responseType', 'responseType',
'timeout', 'timeout',

View File

@ -2,7 +2,7 @@
* @Author: early-autumn * @Author: early-autumn
* @Date: 2020-04-15 22:09:38 * @Date: 2020-04-15 22:09:38
* @LastEditors: early-autumn * @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 09:26:14 * @LastEditTime: 2020-04-20 22:26:29
*/ */
import { AxiosRequestConfig } from './types'; import { AxiosRequestConfig } from './types';
import adaptive from './adaptive'; import adaptive from './adaptive';

View File

@ -2,7 +2,7 @@
* @Author: early-autumn * @Author: early-autumn
* @Date: 2020-04-13 21:45:45 * @Date: 2020-04-13 21:45:45
* @LastEditors: early-autumn * @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 09:35:48 * @LastEditTime: 2020-04-20 21:21:23
*/ */
import { AnyObject, Params } from '../types'; import { AnyObject, Params } from '../types';
import { encode, isPlainObject, isDate } from './utils'; import { encode, isPlainObject, isDate } from './utils';
@ -28,7 +28,7 @@ function generateURL(url: string, serializedParams: string): string {
const prefix = url.indexOf('?') === -1 ? '?' : '&'; const prefix = url.indexOf('?') === -1 ? '?' : '&';
serializedParams = `${prefix}${serializedParams}`; serializedParams = `${prefix}${serializedParams}`;
return `${url}${serializedParams}`; return `${url.replace(/\/*$/, '')}${serializedParams}`;
} }
/** /**

View File

@ -1,24 +0,0 @@
/*
* @Author: early-autumn
* @Date: 2020-04-19 22:30:24
* @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 09:49:35
*/
/**
*
*
* @param message
*/
export default function warning(message: string): void {
const errMsg = `[axios-miniprogram]
${message}`;
if (typeof console !== 'undefined' && typeof console.error === 'function') {
console.error(errMsg);
}
try {
throw new Error(errMsg);
} catch (e) {}
}

View File

@ -2,7 +2,7 @@
* @Author: early-autumn * @Author: early-autumn
* @Date: 2020-04-13 15:23:53 * @Date: 2020-04-13 15:23:53
* @LastEditors: early-autumn * @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 10:32:48 * @LastEditTime: 2020-04-20 21:28:26
*/ */
/** /**
* *
@ -176,7 +176,7 @@ export interface Response {
/** /**
* Headers * Headers
*/ */
headers: Headers; headers?: Headers;
/** /**
* *
@ -230,10 +230,7 @@ export interface Adapter {
* *
*/ */
export interface Platform { export interface Platform {
// 请求函数 request: Adapter;
request?: Adapter;
// 兼容支付宝小程序
httpRequest?: Adapter;
} }
/** /**
@ -387,7 +384,7 @@ export interface AxiosResponse<T extends Data = Data> {
* *
*/ */
export interface InterceptorResolved<T = any> { export interface InterceptorResolved<T = any> {
(value: T): Promise<T>; (value: T): T | Promise<T>;
} }
/** /**

34
test/adaptive.test.ts Normal file
View File

@ -0,0 +1,34 @@
/*
* @Author: early-autumn
* @Date: 2020-04-20 17:22:26
* @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 22:20:47
*/
import adaptive from '../src/adaptive';
declare global {
namespace NodeJS {
interface Global {
wx: any;
}
}
}
describe('测试 src/adaptive.ts', () => {
it('适配成功', () => {
const request = jest.fn();
global.wx = {
request,
};
const adapter = adaptive();
expect(adapter).toBe(request);
});
it('适配失败', () => {
global.wx = undefined;
expect(adaptive()).toBeUndefined();
});
});

109
test/axios.test.ts Normal file
View File

@ -0,0 +1,109 @@
/*
* @Author: early-autumn
* @Date: 2020-04-20 13:58:00
* @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 22:32:14
*/
import axios from '../src/axios';
const task = { abort: jest.fn() };
describe('测试 src/axios.ts', () => {
it('default', (done) => {
axios('/test').catch((error) => {
expect(error.isAxiosError).toBe(true);
expect(error.message).toBe('平台适配失败,您需要参阅文档使用自定义适配器手动适配当前平台');
done();
});
});
it('axios call', async () => {
axios.defaults.adapter = jest.fn((config) => {
expect(config.method).toBe('GET');
expect(config.url).toBe('/test');
config.success({ status: 200, data: '{"a":0}', headers: {} });
return task;
});
await axios({ url: '/test' });
await axios('/test');
await axios.request({ url: '/test' });
axios.defaults.adapter = jest.fn((config) => {
expect(config.method).toBe(config.url.toUpperCase().replace('/', ''));
config.success({ status: 200, data: {}, headers: {} });
return task;
});
await axios.options('options');
await axios.get('get');
await axios.head('head');
await axios.post('post');
await axios.put('put');
await axios.delete('delete');
await axios.trace('trace');
await axios.connect('connect');
});
it('axios 携带参数', async () => {
const url = '/test';
const params = {
id: 1,
};
axios.defaults.adapter = (config) => {
expect(config.method).toBe('GET');
expect(config.url).toBe('/test?id=1');
config.success({ status: 200, data: '', headers: {} });
return task;
};
await axios({
url,
params,
});
await axios(url, {
params,
});
await axios.get(url, params);
});
it('axios 携带数据', async () => {
const url = '/test';
const data = {
id: 1,
};
axios.defaults.adapter = (config) => {
expect(config.method).toBe('POST');
expect(config.url).toBe(url);
expect(config.data).toEqual(data);
config.success({ status: 200, data: '', headers: {} });
return task;
};
await axios({
method: 'post',
url,
data,
});
await axios(url, {
method: 'post',
data,
});
await axios.post(url, data);
});
it('axios.create 工厂方法', () => {
const instance = axios.create();
expect(instance.defaults).toEqual(axios.defaults);
});
});

View File

@ -0,0 +1,21 @@
/*
* @Author: early-autumn
* @Date: 2020-04-20 15:09:33
* @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 15:17:27
*/
import Cancel from '../../src/cancel/Cancel';
describe('测试 src/cancel/Cancel.ts', () => {
it('默认', () => {
const cancel = new Cancel();
expect(cancel.toString()).toBe('Cancel');
});
it('自定义', () => {
const cancel = new Cancel('custom');
expect(cancel.toString()).toBe('Cancel: custom');
});
});

View File

@ -0,0 +1,37 @@
/*
* @Author: early-autumn
* @Date: 2020-04-20 15:17:50
* @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 22:10:39
*/
import CancelToken from '../../src/cancel/CancelToken';
describe('测试 src/cancel/CancelToken.ts', () => {
it('实例化', (done) => {
const token = new CancelToken(function(cancel) {
cancel('取消');
});
setTimeout(() => {
// 应该抛出取消
expect(() => token.throwIfRequested()).toThrow();
done();
});
});
it('工厂方法', async () => {
const source = CancelToken.source();
// 还没有取消 返回 Undefuned
expect(source.token.throwIfRequested()).toBeUndefined();
await source.cancel('取消');
// 应该抛出取消
expect(() => source.token.throwIfRequested()).toThrow();
// 重复取消无效
await source.cancel('取消');
});
});

View File

@ -0,0 +1,18 @@
/*
* @Author: early-autumn
* @Date: 2020-04-20 15:12:17
* @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 15:17:16
*/
import isCancel from '../../src/cancel/isCancel';
import Cancel from '../../src/cancel/Cancel';
describe('测试 src/cancel/isCancel', () => {
it('是一个取消?', () => {
const cancel1 = 0;
const cancel2 = new Cancel();
expect(isCancel(cancel1)).toBe(false);
expect(isCancel(cancel2)).toBe(true);
});
});

73
test/core/Axios.test.ts Normal file
View File

@ -0,0 +1,73 @@
/*
* @Author: early-autumn
* @Date: 2020-04-20 20:47:09
* @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 22:17:18
*/
import Axios from '../../src/core/Axios';
const instance = new Axios();
describe('测试 src/core/Axios.ts', () => {
it('defaults', () => {
expect(instance.defaults).toEqual({});
});
it('getUri', () => {
expect(instance.getUri({})).toEqual('');
expect(instance.getUri({ url: '/test' })).toEqual('/test');
expect(instance.getUri({ url: '', params: { id: 1 } })).toEqual('id=1');
expect(instance.getUri({ url: '/test', params: { id: 1 } })).toEqual('/test?id=1');
});
it('interceptors 成功', async () => {
instance.defaults.adapter = function adapter({ data, success }) {
expect(data).toBe('interceptors_request');
success({ data: 'data', headers: {} });
return { abort: jest.fn() };
};
instance.interceptors.request.use(function(config) {
config.data = 'interceptors_request';
return config;
});
instance.interceptors.response.use(function(response) {
response.data = 'interceptors_response';
return response;
});
await instance
.request({
method: 'post',
data: '',
})
.then(({ data }) => expect(data).toBe('interceptors_response'));
});
it('interceptors 失败', async () => {
instance.interceptors.response.use(function(response) {
throw response;
});
await instance
.request({
method: 'post',
data: '',
})
.catch((error) => expect(error.data).toBe('interceptors_response'));
instance.interceptors.request.use(function(config) {
throw config;
});
await instance
.request({
method: 'post',
data: '',
})
.catch((error) => expect(error.method).toBe('post'));
});
});

View File

@ -0,0 +1,61 @@
/*
* @Author: early-autumn
* @Date: 2020-04-20 15:40:44
* @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 22:05:48
*/
import InterceptorManager from '../../src/core/InterceptorManager';
describe('测试 src/core/InterceptorManager.ts', () => {
it('实例化', () => {
const interceptor = new InterceptorManager();
const executor = jest.fn();
interceptor.forEach(executor);
// executor 不应该被执行
expect(executor.mock.calls.length).toBe(0);
});
it('注册和取消注册', () => {
const interceptor = new InterceptorManager();
const executor1 = jest.fn();
const executor2 = jest.fn();
const id1 = interceptor.use(() => undefined);
const id2 = interceptor.use(() => undefined);
interceptor.forEach(executor1);
// executor1 应该被执行了两次
expect(executor1.mock.calls.length).toBe(2);
interceptor.eject(id1);
interceptor.eject(id2);
interceptor.forEach(executor2);
// executor2 不应该被执行
expect(executor2.mock.calls.length).toBe(0);
});
it('倒序遍历', () => {
const interceptor = new InterceptorManager();
let id = 0;
// 应该后被执行
interceptor.use((id) => expect(id).toBe(1));
// 应该先被执行
interceptor.use((id) => expect(id).toBe(0));
interceptor.forEach(({ resolved }) => {
resolved(id++);
}, 'reverse');
});
it('异常', () => {
const interceptor = new InterceptorManager();
interceptor.use(() => undefined);
interceptor.forEach(({ rejected }) => rejected('error'));
});
});

View File

@ -0,0 +1,40 @@
/*
* @Author: early-autumn
* @Date: 2020-04-20 20:39:42
* @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 20:45:17
*/
import flattenHeaders from '../../src/core/flattenHeaders';
describe('测试 src/core/flattenHeaders.ts', () => {
it('默认', () => {
expect(flattenHeaders({})).toEqual({});
});
it('默认 get', () => {
expect(
flattenHeaders({
headers: {
common: { common: 'common' },
get: { get: 'get' },
post: { post: 'post' },
rest: 'rest',
},
})
).toEqual({ common: 'common', get: 'get', rest: 'rest' });
});
it('拉平', () => {
expect(
flattenHeaders({
method: 'post',
headers: {
common: { common: 'common' },
get: { get: 'get' },
post: { post: 'post' },
rest: 'rest',
},
})
).toEqual({ common: 'common', post: 'post', rest: 'rest' });
});
});

View File

@ -0,0 +1,63 @@
/*
* @Author: early-autumn
* @Date: 2020-04-20 19:16:32
* @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 20:29:17
*/
import mergeConfig from '../../src/core/mergeConfig';
import defaults from '../../src/defaults';
import { AxiosRequestConfig } from '../../src/types';
describe('测试 src/core/mergeConfig.ts', () => {
it('默认', () => {
expect(mergeConfig()).toEqual({});
expect(mergeConfig({ baseURL: 'https://www.xxx.com' })).toEqual({ baseURL: 'https://www.xxx.com' });
expect(mergeConfig(undefined, { baseURL: 'https://www.xxx.com' })).toEqual({ baseURL: 'https://www.xxx.com' });
});
it('只取 config2', () => {
const config2 = { url: 'https://www.config2.com', data: { config2: 0 } };
const config = mergeConfig(defaults, config2);
expect(config.url).toEqual(config2.url);
expect(config.data).toEqual(config2.data);
});
it('优先取 config2', () => {
expect(mergeConfig(defaults, {})).toEqual(defaults);
const config2: AxiosRequestConfig = {
baseURL: 'https://www.config2.com',
method: 'post',
timeout: 10000,
};
const config = mergeConfig(defaults, config2);
expect(config.baseURL).toEqual(config2.baseURL);
expect(config.method).toEqual(config2.method);
expect(config.timeout).toEqual(config2.timeout);
});
it('深度合并', () => {
const config1 = { params: { config1: 0 }, headers: { Config1: '0' } };
const config2 = { params: { config2: 0 }, headers: { Config2: '0' } };
expect(mergeConfig(config1, {})).toEqual(config1);
expect(mergeConfig(config1, config2)).toEqual({
params: { config1: 0, config2: 0 },
headers: { Config1: '0', Config2: '0' },
});
expect(mergeConfig({ params: {} }, { params: { config: 'config2' } })).toEqual({
params: { config: 'config2' },
});
expect(mergeConfig({ params: { config: 'config1' } }, {})).toEqual({
params: { config: 'config1' },
});
});
});

View File

@ -0,0 +1,33 @@
/*
* @Author: early-autumn
* @Date: 2020-04-20 20:31:29
* @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 20:38:49
*/
import { Data } from '../../src/types';
import transformData from '../../src/core/transformData';
describe('测试 src/core/transformData.ts', () => {
it('默认', () => {
expect(transformData({ a: 1 }, {})).toEqual({ a: 1 });
});
it('转换', () => {
function transform(data: Data) {
return data + '1';
}
expect(transformData('1', {}, transform)).toEqual('11');
});
it('多次转换', () => {
const transforms = [
function transform(data: Data) {
return data + '1';
},
function transform(data: Data) {
return data + '1';
},
];
expect(transformData('1', {}, transforms)).toEqual('111');
});
});

View File

@ -0,0 +1,19 @@
/*
* @Author: early-autumn
* @Date: 2020-04-20 16:14:52
* @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 16:17:39
*/
import { methodToLowercase, methodToUppercase } from '../../src/core/transformMethod';
describe('测试 src/core/transformMethod.ts', () => {
it('默认', () => {
expect(methodToLowercase()).toBe('get');
expect(methodToUppercase()).toBe('GET');
});
it('传参', () => {
expect(methodToLowercase('POST')).toBe('post');
expect(methodToUppercase('post')).toBe('POST');
});
});

View File

@ -0,0 +1,48 @@
/*
* @Author: early-autumn
* @Date: 2020-04-20 21:08:23
* @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 21:17:31
*/
import transformRequest from '../../src/core/transformRequest';
describe('测试 src/core/transformRequest.ts', () => {
it('默认', () => {
expect(transformRequest({})).toEqual({
url: '/',
method: 'GET',
headers: undefined,
data: undefined,
dataType: undefined,
enableCache: undefined,
enableHttp2: undefined,
enableQuic: undefined,
header: undefined,
responseType: undefined,
sslVerify: undefined,
timeout: undefined,
});
});
it('基本', () => {
const request = transformRequest({
baseURL: 'https://www.xxx.com///',
method: 'get',
url: '/test',
params: {
id: 1,
},
});
const request2 = transformRequest({
baseURL: 'https://www.xxx.com',
method: 'get',
url: 'https://www.yyy.com/test/',
params: {
id: 1,
},
});
expect(request.url).toEqual('https://www.xxx.com/test?id=1');
expect(request2.url).toEqual('https://www.yyy.com/test?id=1');
});
});

View File

@ -0,0 +1,44 @@
/*
* @Author: early-autumn
* @Date: 2020-04-20 21:25:08
* @LastEditors: early-autumn
* @LastEditTime: 2020-04-20 21:34:20
*/
import transformResponse from '../../src/core/transformResponse';
describe('测试 src/core/transformResponse.ts', () => {
it('默认', () => {
expect(transformResponse({ data: {} }, {})).toEqual({
status: 400,
statusText: 'Bad Adapter',
data: {},
headers: {},
config: {},
cookies: undefined,
profile: undefined,
});
});
it('status + headers', () => {
expect(transformResponse({ status: 200, headers: { status: 'ok' }, data: {} }, {})).toEqual({
status: 200,
statusText: 'OK',
data: {},
headers: { status: 'ok' },
config: {},
cookies: undefined,
profile: undefined,
});
});
it('statusCode + header', () => {
expect(transformResponse({ statusCode: 204, header: { status: 'ok' }, data: {} }, {})).toEqual({
status: 204,
statusText: '',
data: {},
headers: { status: 'ok' },
config: {},
cookies: undefined,
profile: undefined,
});
});
});