revert: 取消支持为路径添加中间件
parent
db787a2b5f
commit
1e5809aee3
|
@ -35,10 +35,10 @@ export function noop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mockResponse(
|
export function mockResponse(
|
||||||
status: number,
|
status = 200,
|
||||||
statusText: string,
|
statusText = 'OK',
|
||||||
headers: AnyObject,
|
headers: AnyObject = {},
|
||||||
data: AnyObject,
|
data: AnyObject = {},
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
status,
|
status,
|
||||||
|
|
|
@ -22,6 +22,7 @@ import {
|
||||||
WITH_PARAMS_METHODS,
|
WITH_PARAMS_METHODS,
|
||||||
} from '../constants/methods';
|
} from '../constants/methods';
|
||||||
import MiddlewareManager, {
|
import MiddlewareManager, {
|
||||||
|
MiddlewareContext,
|
||||||
MiddlewareNext,
|
MiddlewareNext,
|
||||||
MiddlewareUse,
|
MiddlewareUse,
|
||||||
} from './MiddlewareManager';
|
} from './MiddlewareManager';
|
||||||
|
@ -306,11 +307,6 @@ export interface AxiosResponseError extends AnyObject {
|
||||||
request?: AxiosAdapterPlatformTask;
|
request?: AxiosAdapterPlatformTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AxiosContext {
|
|
||||||
req: AxiosRequestConfig;
|
|
||||||
res: null | AxiosResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AxiosRequest {
|
export interface AxiosRequest {
|
||||||
<TData extends AxiosResponseData>(config: AxiosRequestConfig): Promise<
|
<TData extends AxiosResponseData>(config: AxiosRequestConfig): Promise<
|
||||||
AxiosResponse<TData>
|
AxiosResponse<TData>
|
||||||
|
@ -382,7 +378,7 @@ export default class Axios {
|
||||||
/**
|
/**
|
||||||
* 中间件
|
* 中间件
|
||||||
*/
|
*/
|
||||||
#middleware = new MiddlewareManager<AxiosContext>();
|
#middleware = new MiddlewareManager();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送 options 请求
|
* 发送 options 请求
|
||||||
|
@ -432,9 +428,9 @@ export default class Axios {
|
||||||
/**
|
/**
|
||||||
* 添加中间件
|
* 添加中间件
|
||||||
*/
|
*/
|
||||||
use: MiddlewareUse<AxiosContext>;
|
use: MiddlewareUse;
|
||||||
|
|
||||||
constructor(defaults: AxiosRequestConfig = {}, parent?: Axios) {
|
constructor(defaults: AxiosRequestConfig, parent?: Axios) {
|
||||||
this.defaults = defaults;
|
this.defaults = defaults;
|
||||||
this.#parent = parent;
|
this.#parent = parent;
|
||||||
this.use = this.#middleware.use;
|
this.use = this.#middleware.use;
|
||||||
|
@ -504,24 +500,23 @@ export default class Axios {
|
||||||
}
|
}
|
||||||
|
|
||||||
#requestHandler = async (config: AxiosRequestConfig) => {
|
#requestHandler = async (config: AxiosRequestConfig) => {
|
||||||
config.url = combineURL(config.baseURL, config.url);
|
const ctx: MiddlewareContext = {
|
||||||
const ctx: AxiosContext = {
|
|
||||||
req: config,
|
req: config,
|
||||||
res: null,
|
res: null,
|
||||||
};
|
};
|
||||||
await this.#flush(ctx, async () => {
|
await this.#wrap(ctx, async () => {
|
||||||
ctx.res = await dispatchRequest(ctx.req);
|
ctx.res = await dispatchRequest(ctx.req);
|
||||||
});
|
});
|
||||||
return ctx.res as AxiosResponse;
|
return ctx.res as AxiosResponse;
|
||||||
};
|
};
|
||||||
|
|
||||||
#flush(ctx: AxiosContext, finish: MiddlewareNext): Promise<void> {
|
#wrap(ctx: MiddlewareContext, flush: MiddlewareNext): Promise<void> {
|
||||||
if (this.#parent) {
|
if (this.#parent) {
|
||||||
return this.#parent.#flush(ctx, () => {
|
return this.#parent.#wrap(ctx, () => {
|
||||||
return this.#middleware.flush(ctx, finish);
|
return this.#middleware.wrap(ctx, flush);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return this.#middleware.flush(ctx, finish);
|
return this.#middleware.wrap(ctx, flush);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,76 +1,55 @@
|
||||||
import { assert } from '../helpers/error';
|
import { assert } from '../helpers/error';
|
||||||
import { combineURL } from '../helpers/combineURL';
|
import { combineURL } from '../helpers/combineURL';
|
||||||
import { isFunction, isString } from '../helpers/isTypes';
|
import { isFunction, isString } from '../helpers/isTypes';
|
||||||
|
import { AxiosRequestConfig, AxiosResponse } from './Axios';
|
||||||
|
|
||||||
export interface MiddlewareNext {
|
export interface MiddlewareNext {
|
||||||
(): Promise<void>;
|
(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MiddlewareCallback<Context extends AnyObject> {
|
export interface MiddlewareContext {
|
||||||
(ctx: Context, next: MiddlewareNext): Promise<void>;
|
req: AxiosRequestConfig;
|
||||||
|
res: null | AxiosResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MiddlewareUse<Context extends AnyObject> {
|
export interface MiddlewareCallback {
|
||||||
/**
|
(ctx: MiddlewareContext, next: MiddlewareNext): Promise<void>;
|
||||||
* 添加中间件
|
}
|
||||||
*
|
|
||||||
* @param path 中间件路径
|
export interface MiddlewareUse {
|
||||||
* @param callback 中间件回调
|
|
||||||
*/
|
|
||||||
(
|
|
||||||
path: string,
|
|
||||||
callback: MiddlewareCallback<Context>,
|
|
||||||
): MiddlewareManager<Context>;
|
|
||||||
/**
|
/**
|
||||||
* 添加中间件
|
* 添加中间件
|
||||||
*
|
*
|
||||||
* @param callback 中间件回调
|
* @param callback 中间件回调
|
||||||
*/
|
*/
|
||||||
(callback: MiddlewareCallback<Context>): MiddlewareManager<Context>;
|
(callback: MiddlewareCallback): MiddlewareManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class MiddlewareManager<Context extends AnyObject = AnyObject> {
|
export default class MiddlewareManager {
|
||||||
#map = new Map<string, MiddlewareCallback<Context>[]>();
|
/**
|
||||||
|
* 中间件
|
||||||
|
*/
|
||||||
|
#middlewares: MiddlewareCallback[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加中间件
|
* 添加中间件
|
||||||
*/
|
*/
|
||||||
use: MiddlewareUse<Context> = (
|
use: MiddlewareUse = (callback: MiddlewareCallback) => {
|
||||||
path: string | MiddlewareCallback<Context>,
|
|
||||||
callback?: MiddlewareCallback<Context>,
|
|
||||||
) => {
|
|
||||||
if (isFunction(path)) {
|
|
||||||
callback = path;
|
|
||||||
path = '/';
|
|
||||||
}
|
|
||||||
assert(isString(path), 'path 不是一个 string');
|
|
||||||
assert(!!path, 'path 不是一个长度大于零的 string');
|
|
||||||
assert(isFunction(callback), 'callback 不是一个 function');
|
assert(isFunction(callback), 'callback 不是一个 function');
|
||||||
|
this.#middlewares.push(callback!);
|
||||||
const middlewares = this.#map.get(path) ?? [];
|
|
||||||
middlewares.push(callback!);
|
|
||||||
this.#map.set(path, middlewares);
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
flush(ctx: Context, finish: MiddlewareNext) {
|
/**
|
||||||
const allMiddlewares: MiddlewareCallback<Context>[] = [];
|
* 包装器
|
||||||
|
*
|
||||||
for (const [path, middlewares] of this.#map.entries()) {
|
* @param ctx 中间件上下文
|
||||||
const url = combineURL(ctx.req.baseURL, path);
|
* @param flush 目标函数
|
||||||
const checkRE = new RegExp(`^${url}([/?].*)?`);
|
*/
|
||||||
|
wrap(ctx: MiddlewareContext, flush: MiddlewareNext) {
|
||||||
if (path === '/') {
|
const runners = [...this.#middlewares, flush];
|
||||||
allMiddlewares.push(...middlewares);
|
|
||||||
} else if (checkRE.test(ctx.req.url!)) {
|
|
||||||
allMiddlewares.push(...middlewares);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const tasks = [...allMiddlewares, finish];
|
|
||||||
return (function next(): Promise<void> {
|
return (function next(): Promise<void> {
|
||||||
return tasks.shift()!(ctx, next);
|
return runners.shift()!(ctx, next);
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ export function createInstance(config: AxiosRequestConfig, parent?: Axios) {
|
||||||
const context = new Axios(config, parent);
|
const context = new Axios(config, parent);
|
||||||
const instance = context.request as AxiosInstance;
|
const instance = context.request as AxiosInstance;
|
||||||
|
|
||||||
instance.getUri = function getUri(config: AxiosRequestConfig) {
|
instance.getUri = function getUri(config) {
|
||||||
const { url, params, paramsSerializer } = mergeConfig(
|
const { url, params, paramsSerializer } = mergeConfig(
|
||||||
instance.defaults,
|
instance.defaults,
|
||||||
config,
|
config,
|
||||||
|
@ -67,7 +67,7 @@ export function createInstance(config: AxiosRequestConfig, parent?: Axios) {
|
||||||
instance.create = function create(config) {
|
instance.create = function create(config) {
|
||||||
return createInstance(mergeConfig(instance.defaults, config));
|
return createInstance(mergeConfig(instance.defaults, config));
|
||||||
};
|
};
|
||||||
instance.extend = function extend(config: AxiosRequestConfig = {}) {
|
instance.extend = function extend(config) {
|
||||||
config.baseURL = combineURL(instance.defaults.baseURL, config.baseURL);
|
config.baseURL = combineURL(instance.defaults.baseURL, config.baseURL);
|
||||||
return createInstance(mergeConfig(instance.defaults, config), context);
|
return createInstance(mergeConfig(instance.defaults, config), context);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
import axios from './axios';
|
import axios from './axios';
|
||||||
|
|
||||||
|
export type {
|
||||||
|
MiddlewareContext,
|
||||||
|
MiddlewareCallback,
|
||||||
|
MiddlewareNext,
|
||||||
|
} from './core/MiddlewareManager';
|
||||||
export type {
|
export type {
|
||||||
AxiosRequestConfig,
|
AxiosRequestConfig,
|
||||||
AxiosRequestData,
|
AxiosRequestData,
|
||||||
|
@ -14,10 +19,6 @@ export type {
|
||||||
AxiosUploadProgressEvent,
|
AxiosUploadProgressEvent,
|
||||||
AxiosUploadProgressCallback,
|
AxiosUploadProgressCallback,
|
||||||
} from './core/Axios';
|
} from './core/Axios';
|
||||||
export type {
|
|
||||||
MiddlewareCallback,
|
|
||||||
MiddlewareNext,
|
|
||||||
} from './core/MiddlewareManager';
|
|
||||||
export type {
|
export type {
|
||||||
AxiosInstanceDefaults,
|
AxiosInstanceDefaults,
|
||||||
AxiosInstance,
|
AxiosInstance,
|
||||||
|
|
|
@ -11,7 +11,6 @@ describe('src/axios.ts', () => {
|
||||||
test('应该有这些静态属性', () => {
|
test('应该有这些静态属性', () => {
|
||||||
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);
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
} from '@/constants/methods';
|
} from '@/constants/methods';
|
||||||
import defaults from '@/defaults';
|
import defaults from '@/defaults';
|
||||||
import axios from '@/axios';
|
import axios from '@/axios';
|
||||||
|
import { createInstance } from '@/core/createInstance';
|
||||||
|
|
||||||
describe('src/axios.ts', () => {
|
describe('src/axios.ts', () => {
|
||||||
const data = { result: null };
|
const data = { result: null };
|
||||||
|
@ -15,6 +16,9 @@ describe('src/axios.ts', () => {
|
||||||
expect(axios.defaults).toBe(defaults);
|
expect(axios.defaults).toBe(defaults);
|
||||||
expect(axios.interceptors).toBeTypeOf('object');
|
expect(axios.interceptors).toBeTypeOf('object');
|
||||||
expect(axios.getUri).toBeTypeOf('function');
|
expect(axios.getUri).toBeTypeOf('function');
|
||||||
|
expect(axios.create).toBeTypeOf('function');
|
||||||
|
expect(axios.extend).toBeTypeOf('function');
|
||||||
|
expect(axios.use).toBeTypeOf('function');
|
||||||
expect(axios.fork).toBeTypeOf('function');
|
expect(axios.fork).toBeTypeOf('function');
|
||||||
expect(axios.request).toBeTypeOf('function');
|
expect(axios.request).toBeTypeOf('function');
|
||||||
});
|
});
|
||||||
|
@ -162,4 +166,21 @@ describe('src/axios.ts', () => {
|
||||||
'test?id=1',
|
'test?id=1',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('应该支持中间件', async () => {
|
||||||
|
const axios = createInstance(defaults);
|
||||||
|
axios.defaults.adapter = mockAdapter();
|
||||||
|
|
||||||
|
const cb = vi.fn(async (ctx, next) => {
|
||||||
|
expect(ctx.res).toBeNull();
|
||||||
|
await next();
|
||||||
|
expect(ctx.res).toBeTypeOf('object');
|
||||||
|
});
|
||||||
|
|
||||||
|
axios.use(cb);
|
||||||
|
|
||||||
|
await axios.get('test');
|
||||||
|
|
||||||
|
expect(cb).toBeCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -29,6 +29,7 @@ describe('src/core/Axios.ts', () => {
|
||||||
expect(axiosObj.defaults).toEqual(c);
|
expect(axiosObj.defaults).toEqual(c);
|
||||||
expect(axiosObj.interceptors).toBeTypeOf('object');
|
expect(axiosObj.interceptors).toBeTypeOf('object');
|
||||||
expect(axiosObj.request).toBeTypeOf('function');
|
expect(axiosObj.request).toBeTypeOf('function');
|
||||||
|
expect(axiosObj.use).toBeTypeOf('function');
|
||||||
});
|
});
|
||||||
|
|
||||||
testEachMethods('%s 应该是一个函数', (k) => {
|
testEachMethods('%s 应该是一个函数', (k) => {
|
||||||
|
@ -36,23 +37,34 @@ describe('src/core/Axios.ts', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('应该可以发送普通别名请求', () => {
|
test('应该可以发送普通别名请求', () => {
|
||||||
const c = {
|
const axiosObj = new Axios({
|
||||||
adapter: mockAdapter({
|
adapter: mockAdapter({
|
||||||
before: (config) => {
|
|
||||||
expect(config.url).toBe('http://api.com/test');
|
|
||||||
},
|
|
||||||
data,
|
data,
|
||||||
}),
|
}),
|
||||||
|
});
|
||||||
|
const c = {
|
||||||
|
baseURL: 'https://api.com',
|
||||||
};
|
};
|
||||||
|
|
||||||
PLAIN_METHODS.forEach((a) => {
|
PLAIN_METHODS.forEach((a) => {
|
||||||
|
axiosObj[a]('test').then((res) => {
|
||||||
|
expect(res.config.baseURL).toBeUndefined();
|
||||||
|
expect(res.data).toEqual(data);
|
||||||
|
});
|
||||||
axiosObj[a]('test', c).then((res) => {
|
axiosObj[a]('test', c).then((res) => {
|
||||||
|
expect(res.config.baseURL).toBe('https://api.com');
|
||||||
expect(res.data).toEqual(data);
|
expect(res.data).toEqual(data);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('应该可以发送带参数的别名请求', () => {
|
test('应该可以发送带参数的别名请求', () => {
|
||||||
|
const axiosObj = new Axios({
|
||||||
|
adapter: mockAdapter({
|
||||||
|
data,
|
||||||
|
}),
|
||||||
|
baseURL: 'http://api.com',
|
||||||
|
});
|
||||||
const p = { id: 1 };
|
const p = { id: 1 };
|
||||||
const c1 = {
|
const c1 = {
|
||||||
adapter: mockAdapter({
|
adapter: mockAdapter({
|
||||||
|
@ -74,6 +86,12 @@ describe('src/core/Axios.ts', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
WITH_PARAMS_METHODS.forEach((a) => {
|
WITH_PARAMS_METHODS.forEach((a) => {
|
||||||
|
axiosObj[a]('test').then((res) => {
|
||||||
|
expect(res.data).toEqual(data);
|
||||||
|
});
|
||||||
|
axiosObj[a]('test', p).then((res) => {
|
||||||
|
expect(res.data).toEqual(data);
|
||||||
|
});
|
||||||
axiosObj[a]('test', p, c1).then((res) => {
|
axiosObj[a]('test', p, c1).then((res) => {
|
||||||
expect(res.data).toEqual(data);
|
expect(res.data).toEqual(data);
|
||||||
});
|
});
|
||||||
|
@ -84,6 +102,12 @@ describe('src/core/Axios.ts', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('应该可以发送带数据的别名请求', () => {
|
test('应该可以发送带数据的别名请求', () => {
|
||||||
|
const axiosObj = new Axios({
|
||||||
|
adapter: mockAdapter({
|
||||||
|
data,
|
||||||
|
}),
|
||||||
|
baseURL: 'http://api.com',
|
||||||
|
});
|
||||||
const d = { id: 1 };
|
const d = { id: 1 };
|
||||||
const c1 = {
|
const c1 = {
|
||||||
adapter: mockAdapter({
|
adapter: mockAdapter({
|
||||||
|
@ -105,6 +129,12 @@ describe('src/core/Axios.ts', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
WITH_DATA_METHODS.forEach((a) => {
|
WITH_DATA_METHODS.forEach((a) => {
|
||||||
|
axiosObj[a]('test').then((res) => {
|
||||||
|
expect(res.data).toEqual(data);
|
||||||
|
});
|
||||||
|
axiosObj[a]('test', d).then((res) => {
|
||||||
|
expect(res.data).toEqual(data);
|
||||||
|
});
|
||||||
axiosObj[a]('test', d, c1).then((res) => {
|
axiosObj[a]('test', d, c1).then((res) => {
|
||||||
expect(res.data).toEqual(data);
|
expect(res.data).toEqual(data);
|
||||||
});
|
});
|
||||||
|
@ -207,7 +237,7 @@ describe('src/core/Axios.ts', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('添加多个请求拦截器时应该按添加顺序从后往前依次执行', () => {
|
test('添加多个请求拦截器时应该按添加顺序从后往前依次执行', () => {
|
||||||
const axiosObj = new Axios();
|
const axiosObj = new Axios({});
|
||||||
|
|
||||||
const cb1 = vi.fn((v) => {
|
const cb1 = vi.fn((v) => {
|
||||||
expect(v.params.index).toBe(2);
|
expect(v.params.index).toBe(2);
|
||||||
|
@ -240,7 +270,7 @@ describe('src/core/Axios.ts', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('请求拦截器应该支持抛出异常', async () => {
|
test('请求拦截器应该支持抛出异常', async () => {
|
||||||
const axiosObj = new Axios();
|
const axiosObj = new Axios({});
|
||||||
const c = { adapter: vi.fn(), url: 'test' };
|
const c = { adapter: vi.fn(), url: 'test' };
|
||||||
const body = (v: any) => {
|
const body = (v: any) => {
|
||||||
throw { ...v, throw: true };
|
throw { ...v, throw: true };
|
||||||
|
@ -293,7 +323,7 @@ describe('src/core/Axios.ts', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('添加多个响应拦截器时应该按添加顺序从前往后依次执行', async () => {
|
test('添加多个响应拦截器时应该按添加顺序从前往后依次执行', async () => {
|
||||||
const axiosObj = new Axios();
|
const axiosObj = new Axios({});
|
||||||
|
|
||||||
const cb1 = vi.fn((v) => {
|
const cb1 = vi.fn((v) => {
|
||||||
expect(v.data.index).toBe(0);
|
expect(v.data.index).toBe(0);
|
||||||
|
@ -323,7 +353,7 @@ describe('src/core/Axios.ts', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('响应拦截器应该支持抛出异常', async () => {
|
test('响应拦截器应该支持抛出异常', async () => {
|
||||||
const axiosObj = new Axios();
|
const axiosObj = new Axios({});
|
||||||
const c = { adapter: vi.fn(mockAdapter()), url: 'test' };
|
const c = { adapter: vi.fn(mockAdapter()), url: 'test' };
|
||||||
const body = () => {
|
const body = () => {
|
||||||
throw { throw: true };
|
throw { throw: true };
|
||||||
|
@ -347,4 +377,21 @@ describe('src/core/Axios.ts', () => {
|
||||||
expect(res2).not.toBeCalled();
|
expect(res2).not.toBeCalled();
|
||||||
expect(rej2).toBeCalled();
|
expect(rej2).toBeCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('应该支持中间件', async () => {
|
||||||
|
const axiosObj = new Axios({
|
||||||
|
adapter: mockAdapter(),
|
||||||
|
});
|
||||||
|
const cb = vi.fn(async (ctx, next) => {
|
||||||
|
expect(ctx.res).toBeNull();
|
||||||
|
await next();
|
||||||
|
expect(ctx.res).toBeTypeOf('object');
|
||||||
|
});
|
||||||
|
|
||||||
|
axiosObj.use(cb);
|
||||||
|
|
||||||
|
await axiosObj.get('test');
|
||||||
|
|
||||||
|
expect(cb).toBeCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
import { describe, test, expect, vi } from 'vitest';
|
||||||
|
import MiddlewareManager, { MiddlewareContext } from '@/core/MiddlewareManager';
|
||||||
|
import { AxiosResponse } from '@/index';
|
||||||
|
|
||||||
|
describe('src/core/MiddlewareManager.ts', () => {
|
||||||
|
test('应该有这些实例属性', () => {
|
||||||
|
const m = new MiddlewareManager();
|
||||||
|
|
||||||
|
expect(m.use).toBeTypeOf('function');
|
||||||
|
expect(m.wrap).toBeTypeOf('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该抛出异常', () => {
|
||||||
|
const m = new MiddlewareManager();
|
||||||
|
|
||||||
|
expect(() => m.use(undefined as any)).toThrowError(
|
||||||
|
'[axios-miniprogram]: callback 不是一个 function',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该支持添加中间件', () => {
|
||||||
|
const m = new MiddlewareManager();
|
||||||
|
const c: MiddlewareContext = {
|
||||||
|
req: {},
|
||||||
|
res: null,
|
||||||
|
};
|
||||||
|
const res = {} as AxiosResponse;
|
||||||
|
|
||||||
|
const cb = vi.fn(async (ctx, next) => {
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
const flush = vi.fn(async () => {
|
||||||
|
c.res = res;
|
||||||
|
});
|
||||||
|
|
||||||
|
m.use(cb);
|
||||||
|
m.wrap(c, flush);
|
||||||
|
|
||||||
|
expect(cb).toBeCalled();
|
||||||
|
expect(flush).toBeCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该支持洋葱模型', async () => {
|
||||||
|
const m = new MiddlewareManager();
|
||||||
|
const c: MiddlewareContext = {
|
||||||
|
req: {},
|
||||||
|
res: null,
|
||||||
|
};
|
||||||
|
const res = {} as AxiosResponse;
|
||||||
|
|
||||||
|
const cb1 = vi.fn(async (ctx, next) => {
|
||||||
|
// 1
|
||||||
|
expect(ctx.req.step).toBeUndefined();
|
||||||
|
ctx.req.step = 'cb1 start';
|
||||||
|
await next();
|
||||||
|
// 8
|
||||||
|
expect(ctx.res.step).toBe('cb2 end');
|
||||||
|
ctx.res.step = 'cb1 end';
|
||||||
|
});
|
||||||
|
const cb2 = vi.fn((ctx, next) => {
|
||||||
|
// 2
|
||||||
|
expect(ctx.req.step).toBe('cb1 start');
|
||||||
|
ctx.req.step = 'cb2 start';
|
||||||
|
return next().then(() => {
|
||||||
|
// 7
|
||||||
|
expect(ctx.res.step).toBe('cb3 end');
|
||||||
|
ctx.res.step = 'cb2 end';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const cb3 = vi.fn(async (ctx, next) => {
|
||||||
|
// 3
|
||||||
|
expect(ctx.req.step).toBe('cb2 start');
|
||||||
|
ctx.req.step = 'cb3 start';
|
||||||
|
await next();
|
||||||
|
// 6
|
||||||
|
expect(ctx.res.step).toBe('flush end');
|
||||||
|
ctx.res.step = 'cb3 end';
|
||||||
|
});
|
||||||
|
const flush = vi.fn(async () => {
|
||||||
|
// 4
|
||||||
|
expect(c.req.step).toBe('cb3 start');
|
||||||
|
c.req.step = 'flush start';
|
||||||
|
c.res = res;
|
||||||
|
// 5
|
||||||
|
expect(c.res.step).toBeUndefined();
|
||||||
|
c.res.step = 'flush end';
|
||||||
|
});
|
||||||
|
|
||||||
|
m.use(cb1);
|
||||||
|
m.use(cb2);
|
||||||
|
m.use(cb3);
|
||||||
|
await m.wrap(c, flush);
|
||||||
|
|
||||||
|
expect(c.req.step).toBe('flush start');
|
||||||
|
expect(c.res!.step).toBe('cb1 end');
|
||||||
|
expect(cb1).toBeCalled();
|
||||||
|
expect(cb2).toBeCalled();
|
||||||
|
expect(cb3).toBeCalled();
|
||||||
|
expect(flush).toBeCalled();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,91 @@
|
||||||
|
import { describe, test, expect, vi } from 'vitest';
|
||||||
|
import { eachMethods, mockAdapter } from 'scripts/test.utils';
|
||||||
|
import { createInstance } from '@/core/createInstance';
|
||||||
|
|
||||||
|
describe('src/core/createInstance.ts', () => {
|
||||||
|
test('应该可以创建实例', () => {
|
||||||
|
const i = createInstance({});
|
||||||
|
|
||||||
|
expect(i).toBeTypeOf('function');
|
||||||
|
expect(i.defaults).toBeTypeOf('object');
|
||||||
|
expect(i.interceptors).toBeTypeOf('object');
|
||||||
|
expect(i.getUri).toBeTypeOf('function');
|
||||||
|
expect(i.create).toBeTypeOf('function');
|
||||||
|
expect(i.extend).toBeTypeOf('function');
|
||||||
|
expect(i.fork).toBeTypeOf('function');
|
||||||
|
expect(i.use).toBeTypeOf('function');
|
||||||
|
expect(i.request).toBeTypeOf('function');
|
||||||
|
|
||||||
|
eachMethods((k) => {
|
||||||
|
expect(i[k]).toBeTypeOf('function');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该支持合并配置', () => {
|
||||||
|
const parent = createInstance({});
|
||||||
|
const child = parent.create({
|
||||||
|
baseURL: 'https://api.com',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(parent.defaults.baseURL).toBeUndefined();
|
||||||
|
expect(child.defaults.baseURL).toBe('https://api.com');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该支持复用拦截器', async () => {
|
||||||
|
const parent = createInstance({
|
||||||
|
baseURL: 'https://api.com',
|
||||||
|
});
|
||||||
|
const child = parent.extend({
|
||||||
|
adapter: mockAdapter(),
|
||||||
|
});
|
||||||
|
const cb1 = vi.fn((config) => config);
|
||||||
|
const cb2 = vi.fn((response) => response);
|
||||||
|
const cb3 = vi.fn((config) => config);
|
||||||
|
const cb4 = vi.fn((response) => response);
|
||||||
|
|
||||||
|
parent.interceptors.request.use(cb1);
|
||||||
|
parent.interceptors.response.use(cb2);
|
||||||
|
child.interceptors.request.use(cb3);
|
||||||
|
child.interceptors.response.use(cb4);
|
||||||
|
|
||||||
|
await child('test');
|
||||||
|
|
||||||
|
expect(cb1).toBeCalled();
|
||||||
|
expect(cb2).toBeCalled();
|
||||||
|
expect(cb3).toBeCalled();
|
||||||
|
expect(cb4).toBeCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该支持复用中间件', async () => {
|
||||||
|
const parent = createInstance({
|
||||||
|
baseURL: 'https://api.com',
|
||||||
|
});
|
||||||
|
const child = parent.extend({
|
||||||
|
adapter: mockAdapter(),
|
||||||
|
});
|
||||||
|
const cb1 = vi.fn(async (ctx, next) => {
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
const cb2 = vi.fn(async (ctx, next) => {
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
const cb3 = vi.fn(async (ctx, next) => {
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
const cb4 = vi.fn(async (ctx, next) => {
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
parent.use(cb1);
|
||||||
|
parent.use(cb2);
|
||||||
|
child.use(cb3);
|
||||||
|
child.use(cb4);
|
||||||
|
|
||||||
|
await child('test');
|
||||||
|
|
||||||
|
expect(cb1).toBeCalled();
|
||||||
|
expect(cb2).toBeCalled();
|
||||||
|
expect(cb3).toBeCalled();
|
||||||
|
expect(cb4).toBeCalled();
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue