From 1f4f65ffd1a45508f105e7594a9acf80e0ded4ff Mon Sep 17 00:00:00 2001 From: "954270063@qq.com" <954270063@qq.com> Date: Mon, 20 Apr 2020 22:33:15 +0800 Subject: [PATCH] :white_check_mark: --- README.md | 8 +- package.json | 2 +- src/adaptive.ts | 63 ++++++++++------ src/axios.ts | 8 +- src/cancel/isCancel.ts | 6 +- src/core/Axios.ts | 12 ++- src/core/createError.ts | 10 +-- src/core/dispatchRequest.ts | 4 +- src/core/flattenHeaders.ts | 7 +- src/core/mergeConfig.ts | 6 +- src/core/request.ts | 6 +- src/core/transformMethod.ts | 25 ++++++ src/core/transformRequest.ts | 29 +++---- src/defaults.ts | 2 +- src/helpers/buildURL.ts | 4 +- src/helpers/warning.ts | 24 ------ src/types.ts | 11 +-- test/adaptive.test.ts | 34 +++++++++ test/axios.test.ts | 109 +++++++++++++++++++++++++++ test/cancel/Cancel.test.ts | 21 ++++++ test/cancel/CancelToken.test.ts | 37 +++++++++ test/cancel/isCancel.test.ts | 18 +++++ test/core/Axios.test.ts | 73 ++++++++++++++++++ test/core/InterceptorManager.test.ts | 61 +++++++++++++++ test/core/flattenHeaders.test.ts | 40 ++++++++++ test/core/mergeConfig.test.ts | 63 ++++++++++++++++ test/core/transformData.test.ts | 33 ++++++++ test/core/transformMethod.test.ts | 19 +++++ test/core/transformRequest.test.ts | 48 ++++++++++++ test/core/transformResponse.test.ts | 44 +++++++++++ 30 files changed, 718 insertions(+), 109 deletions(-) create mode 100644 src/core/transformMethod.ts delete mode 100644 src/helpers/warning.ts create mode 100644 test/adaptive.test.ts create mode 100644 test/axios.test.ts create mode 100644 test/cancel/Cancel.test.ts create mode 100644 test/cancel/CancelToken.test.ts create mode 100644 test/cancel/isCancel.test.ts create mode 100644 test/core/Axios.test.ts create mode 100644 test/core/InterceptorManager.test.ts create mode 100644 test/core/flattenHeaders.test.ts create mode 100644 test/core/mergeConfig.test.ts create mode 100644 test/core/transformData.test.ts create mode 100644 test/core/transformMethod.test.ts create mode 100644 test/core/transformRequest.test.ts create mode 100644 test/core/transformResponse.test.ts diff --git a/README.md b/README.md index c230333..3c0e94a 100644 --- a/README.md +++ b/README.md @@ -33,10 +33,10 @@ $ npm i axios-miniprogram ## 使用 -可以通过将相关配置传递给`axios`来发送请求。 - ### `axios(config)` +可以通过将相关配置传递给`axios`来发送请求。 + ```typescript // 发送 GET 请求 axios({ @@ -61,10 +61,10 @@ axios({ }); ``` -也可以通过直接把`url`传给`axios`来发送请求。 - ### `axios(url, config?)` +也可以通过直接把`url`传给`axios`来发送请求。 + ```typescript // 默认发送 GET 请求 axios('/test/xxx').then((response) => { diff --git a/package.json b/package.json index c00f18c..1ec7d2c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "axios-miniprogram", - "version": "1.0.7", + "version": "1.0.9", "description": "基于 Promise 的 HTTP 请求库,适用于各大小程序平台。", "main": "package/index.js", "miniprogram": "package", diff --git a/src/adaptive.ts b/src/adaptive.ts index 2fa5964..e5b94af 100644 --- a/src/adaptive.ts +++ b/src/adaptive.ts @@ -2,43 +2,58 @@ * @Author: early-autumn * @Date: 2020-04-17 12:18:25 * @LastEditors: early-autumn - * @LastEditTime: 2020-04-20 01:14:16 + * @LastEditTime: 2020-04-20 21:51:02 */ import { Adapter, Platform } from './types'; -import warning from './helpers/warning'; +// 微信小程序 declare let wx: Platform; +// 支付宝小程序 declare let my: Platform; +// 百度小程序 declare let swan: Platform; +// 字节跳动小程序 declare let tt: Platform; +// QQ 小程序 declare let qq: Platform; +// uniapp 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 { - switch (true) { - // 微信小程序 - case wx !== undefined: - return wx.request; - // 支付宝小程序 - case my !== undefined: - return my.request ?? my.httpRequest; - // 百度小程序 - case swan !== undefined: - return swan.request; - // 字节跳动小程序 - case tt !== undefined: - return tt.request; - // QQ 小程序 - case qq !== undefined: - return qq.request; - // uniapp - case uni !== undefined: - return uni.request; - default: - warning('暂未适配此平台,您需要参阅文档使用自定义适配器手动适配当前平台'); +function adaptive(adapter?: Adapter): Adapter | undefined { + if (adapter !== undefined) { + return adapter; + } + + let request: Adapter | undefined; + + try { + const platform = platformList.shift(); + + if (platform === undefined) { + return; + } + + request = platform(); + + throw 'next'; + } catch (err) { + return adaptive(request); } } diff --git a/src/axios.ts b/src/axios.ts index 0070766..166d197 100644 --- a/src/axios.ts +++ b/src/axios.ts @@ -2,7 +2,7 @@ * @Author: early-autumn * @Date: 2020-04-15 12:45:18 * @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 Axios from './core/Axios'; @@ -50,8 +50,10 @@ function createInstance(config: AxiosRequestConfig): AxiosInstance { return instance.request(requestConfig); } - // Axios 实例的所有属性和方法合并至 axios 函数 - Object.assign(axios, instance, Object.getPrototypeOf(instance)); + // instance 的属性设置到 axios 函数中 + Object.assign(axios, instance); + // instance 的方法设置到 axios 函数中 + Object.setPrototypeOf(axios, Object.getPrototypeOf(instance)); return axios as AxiosInstance; } diff --git a/src/cancel/isCancel.ts b/src/cancel/isCancel.ts index f4d23a3..e7a7ee0 100644 --- a/src/cancel/isCancel.ts +++ b/src/cancel/isCancel.ts @@ -2,7 +2,7 @@ * @Author: early-autumn * @Date: 2020-04-14 09:23:25 * @LastEditors: early-autumn - * @LastEditTime: 2020-04-17 09:27:59 + * @LastEditTime: 2020-04-20 15:15:27 */ import Cancel from './Cancel'; @@ -11,6 +11,6 @@ import Cancel from './Cancel'; * * @param value 判断的值 */ -export default function isCancel(value: any) { - return value && value instanceof Cancel; +export default function isCancel(value: any): boolean { + return !!value && value instanceof Cancel; } diff --git a/src/core/Axios.ts b/src/core/Axios.ts index 88beb81..894fd85 100644 --- a/src/core/Axios.ts +++ b/src/core/Axios.ts @@ -2,7 +2,7 @@ * @Author: early-autumn * @Date: 2020-04-13 18:00:27 * @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 buildURL from '../helpers/buildURL'; @@ -14,7 +14,7 @@ export default class AxiosStatic implements Axios { /** * 默认配置 */ - defaults: AxiosRequestConfig; + public defaults: AxiosRequestConfig; /** * Axios 拦截器 @@ -35,9 +35,9 @@ export default class AxiosStatic implements Axios { * @param config Axios 请求配置 */ 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 请求配置 */ public request(config: AxiosRequestConfig): Promise> { - config = mergeConfig(this.defaults, config); - - let promiseRequest = Promise.resolve(config); + let promiseRequest = Promise.resolve(mergeConfig(this.defaults, config)); // 执行请求拦截器 this.interceptors.request.forEach(function executor({ resolved, rejected }) { diff --git a/src/core/createError.ts b/src/core/createError.ts index 4bdc1af..10b2d3d 100644 --- a/src/core/createError.ts +++ b/src/core/createError.ts @@ -2,7 +2,7 @@ * @Author: early-autumn * @Date: 2020-04-14 22:23:39 * @LastEditors: early-autumn - * @LastEditTime: 2020-04-19 18:49:43 + * @LastEditTime: 2020-04-20 13:23:04 */ import { AxiosRequestConfig, RequestConfig, AxiosResponse } from '../types'; @@ -13,22 +13,22 @@ class AxiosError extends Error { /** * 是 Axios 错误 */ - isAxiosError: boolean; + public isAxiosError: boolean; /** * Axios 请求配置 */ - config: AxiosRequestConfig; + public config: AxiosRequestConfig; /** * 通用请求配置 */ - request: RequestConfig; + public request: RequestConfig; /** * Axios 响应体 */ - response?: AxiosResponse; + public response?: AxiosResponse; constructor(message: string, config: AxiosRequestConfig, request: RequestConfig, response?: AxiosResponse) { super(message); diff --git a/src/core/dispatchRequest.ts b/src/core/dispatchRequest.ts index 0f2784d..84d1f3b 100644 --- a/src/core/dispatchRequest.ts +++ b/src/core/dispatchRequest.ts @@ -2,7 +2,7 @@ * @Author: early-autumn * @Date: 2020-04-13 18:01:16 * @LastEditors: early-autumn - * @LastEditTime: 2020-04-20 00:54:32 + * @LastEditTime: 2020-04-20 13:36:32 */ import { AxiosRequestConfig, AxiosResponse } from '../types'; import isCancel from '../cancel/isCancel'; @@ -29,8 +29,6 @@ function throwIfCancellationRequested(config: AxiosRequestConfig) { export default function dispatchRequest(config: AxiosRequestConfig): Promise { throwIfCancellationRequested(config); - config.method = config.method ?? 'get'; - config.headers = flattenHeaders(config); config.data = transformData(config.data ?? {}, config.headers, config.transformRequest); diff --git a/src/core/flattenHeaders.ts b/src/core/flattenHeaders.ts index d762f24..fcdb0b2 100644 --- a/src/core/flattenHeaders.ts +++ b/src/core/flattenHeaders.ts @@ -2,10 +2,11 @@ * @Author: early-autumn * @Date: 2020-04-18 12:00:01 * @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 { methodToLowercase } from './transformMethod'; /** * 拉平请求头 @@ -19,7 +20,7 @@ export default function flattenHeaders(config: AxiosRequestConfig): Headers { return {}; } - const method = (config.method as string).toLowerCase() as AliasMethod; + const method = methodToLowercase(config.method); return { ...(headers.common ?? {}), diff --git a/src/core/mergeConfig.ts b/src/core/mergeConfig.ts index 2a93665..fda83ab 100644 --- a/src/core/mergeConfig.ts +++ b/src/core/mergeConfig.ts @@ -2,7 +2,7 @@ * @Author: early-autumn * @Date: 2020-04-15 22:48:25 * @LastEditors: early-autumn - * @LastEditTime: 2020-04-20 10:32:06 + * @LastEditTime: 2020-04-20 20:27:37 */ import { AnyObject, AxiosRequestConfig } from '../types'; import { isPlainObject, deepMerge } from '../helpers/utils'; @@ -78,12 +78,8 @@ function deepMergeConfig( keys.forEach((key) => { if (isPlainObject(config2[key])) { config[key] = deepMerge(config1[key] ?? {}, config2[key] as AnyObject); - } else if (config2[key] !== undefined) { - config[key] = config2[key]; } else if (isPlainObject(config1[key])) { config[key] = deepMerge(config1[key] as AnyObject); - } else if (config1[key] !== undefined) { - config[key] = config1[key]; } }); } diff --git a/src/core/request.ts b/src/core/request.ts index 314184e..4b89bc5 100644 --- a/src/core/request.ts +++ b/src/core/request.ts @@ -2,10 +2,9 @@ * @Author: early-autumn * @Date: 2020-04-16 00:48:45 * @LastEditors: early-autumn - * @LastEditTime: 2020-04-20 01:12:12 + * @LastEditTime: 2020-04-20 14:24:07 */ import { AxiosRequestConfig, AxiosResponse, Response } from '../types'; -import warning from '../helpers/warning'; import transformRequest from './transformRequest'; import transformResponse from './transformResponse'; import createError from './createError'; @@ -35,8 +34,7 @@ export default function request(config: AxiosRequestConfig): Promise( config, + 'data', + 'headers', 'dataType', 'responseType', 'timeout', diff --git a/src/defaults.ts b/src/defaults.ts index 5c4a58c..a43a818 100644 --- a/src/defaults.ts +++ b/src/defaults.ts @@ -2,7 +2,7 @@ * @Author: early-autumn * @Date: 2020-04-15 22:09:38 * @LastEditors: early-autumn - * @LastEditTime: 2020-04-20 09:26:14 + * @LastEditTime: 2020-04-20 22:26:29 */ import { AxiosRequestConfig } from './types'; import adaptive from './adaptive'; diff --git a/src/helpers/buildURL.ts b/src/helpers/buildURL.ts index 41e2972..92d7996 100644 --- a/src/helpers/buildURL.ts +++ b/src/helpers/buildURL.ts @@ -2,7 +2,7 @@ * @Author: early-autumn * @Date: 2020-04-13 21:45:45 * @LastEditors: early-autumn - * @LastEditTime: 2020-04-20 09:35:48 + * @LastEditTime: 2020-04-20 21:21:23 */ import { AnyObject, Params } from '../types'; import { encode, isPlainObject, isDate } from './utils'; @@ -28,7 +28,7 @@ function generateURL(url: string, serializedParams: string): string { const prefix = url.indexOf('?') === -1 ? '?' : '&'; serializedParams = `${prefix}${serializedParams}`; - return `${url}${serializedParams}`; + return `${url.replace(/\/*$/, '')}${serializedParams}`; } /** diff --git a/src/helpers/warning.ts b/src/helpers/warning.ts deleted file mode 100644 index 03e38d1..0000000 --- a/src/helpers/warning.ts +++ /dev/null @@ -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) {} -} diff --git a/src/types.ts b/src/types.ts index ce263e0..384cfb8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2,7 +2,7 @@ * @Author: early-autumn * @Date: 2020-04-13 15:23:53 * @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; /** * 响应数据 @@ -230,10 +230,7 @@ export interface Adapter { * 平台 */ export interface Platform { - // 请求函数 - request?: Adapter; - // 兼容支付宝小程序 - httpRequest?: Adapter; + request: Adapter; } /** @@ -387,7 +384,7 @@ export interface AxiosResponse { * 拦截器成功的回调函数 */ export interface InterceptorResolved { - (value: T): Promise; + (value: T): T | Promise; } /** diff --git a/test/adaptive.test.ts b/test/adaptive.test.ts new file mode 100644 index 0000000..f322980 --- /dev/null +++ b/test/adaptive.test.ts @@ -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(); + }); +}); diff --git a/test/axios.test.ts b/test/axios.test.ts new file mode 100644 index 0000000..1e0c904 --- /dev/null +++ b/test/axios.test.ts @@ -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); + }); +}); diff --git a/test/cancel/Cancel.test.ts b/test/cancel/Cancel.test.ts new file mode 100644 index 0000000..ca0f07c --- /dev/null +++ b/test/cancel/Cancel.test.ts @@ -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'); + }); +}); diff --git a/test/cancel/CancelToken.test.ts b/test/cancel/CancelToken.test.ts new file mode 100644 index 0000000..cf66c1d --- /dev/null +++ b/test/cancel/CancelToken.test.ts @@ -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('取消'); + }); +}); diff --git a/test/cancel/isCancel.test.ts b/test/cancel/isCancel.test.ts new file mode 100644 index 0000000..88ae968 --- /dev/null +++ b/test/cancel/isCancel.test.ts @@ -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); + }); +}); diff --git a/test/core/Axios.test.ts b/test/core/Axios.test.ts new file mode 100644 index 0000000..8543026 --- /dev/null +++ b/test/core/Axios.test.ts @@ -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')); + }); +}); diff --git a/test/core/InterceptorManager.test.ts b/test/core/InterceptorManager.test.ts new file mode 100644 index 0000000..d43cf31 --- /dev/null +++ b/test/core/InterceptorManager.test.ts @@ -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')); + }); +}); diff --git a/test/core/flattenHeaders.test.ts b/test/core/flattenHeaders.test.ts new file mode 100644 index 0000000..68e2eae --- /dev/null +++ b/test/core/flattenHeaders.test.ts @@ -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' }); + }); +}); diff --git a/test/core/mergeConfig.test.ts b/test/core/mergeConfig.test.ts new file mode 100644 index 0000000..f8ba4d8 --- /dev/null +++ b/test/core/mergeConfig.test.ts @@ -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' }, + }); + }); +}); diff --git a/test/core/transformData.test.ts b/test/core/transformData.test.ts new file mode 100644 index 0000000..9792e83 --- /dev/null +++ b/test/core/transformData.test.ts @@ -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'); + }); +}); diff --git a/test/core/transformMethod.test.ts b/test/core/transformMethod.test.ts new file mode 100644 index 0000000..dd1a2ab --- /dev/null +++ b/test/core/transformMethod.test.ts @@ -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'); + }); +}); diff --git a/test/core/transformRequest.test.ts b/test/core/transformRequest.test.ts new file mode 100644 index 0000000..0768db6 --- /dev/null +++ b/test/core/transformRequest.test.ts @@ -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'); + }); +}); diff --git a/test/core/transformResponse.test.ts b/test/core/transformResponse.test.ts new file mode 100644 index 0000000..c85be1a --- /dev/null +++ b/test/core/transformResponse.test.ts @@ -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, + }); + }); +});