axios-miniprogram/test/request/request.test.ts

377 lines
9.0 KiB
TypeScript

import { describe, test, expect, vi } from 'vitest';
import {
asyncTimeout,
eachMethods,
mockAdapter,
mockAdapterError,
mockAdapterFail,
testEachMethods,
} from 'scripts/test.utils';
import { request } from '@/request/request';
import axios from '@/axios';
describe('src/request/request.ts', () => {
test('应该支持转换 URL', () => {
const c1 = {
adapter(config: AnyObject) {
expect(config.url).toBe('http://api.com/test');
},
baseURL: 'http://api.com',
url: 'test',
method: 'get' as const,
};
const c2 = {
adapter(config: AnyObject) {
expect(config.url).toBe('http://api.com/test?id=1');
},
baseURL: 'http://api.com',
url: 'test',
method: 'get' as const,
params: {
id: 1,
},
};
const c3 = {
adapter(config: AnyObject) {
expect(config.url).toBe('http://api.com/test');
},
baseURL: 'http://api.com',
url: 'test',
method: 'post' as const,
data: {
id: 1,
},
};
request(c1);
request(c2);
request(c3);
});
testEachMethods('应该支持 %s 转全大写', (k) => {
const c = {
adapter(config: AnyObject) {
expect(config.method).toBe(k.toUpperCase());
},
url: '/',
method: k,
};
request(c);
});
testEachMethods('%s 方法应该返回正确的响应体结构', (k) => {
const c = {
adapter: mockAdapter(),
url: '/test',
method: k,
};
request(c).then((response) => {
expect(response.status).toBeTypeOf('number');
expect(response.statusText).toBeTypeOf('string');
expect(response.headers).toBeTypeOf('object');
expect(response.data).toBeTypeOf('object');
expect(response.config).toBeTypeOf('object');
expect(response.request).toBeTypeOf('object');
});
});
testEachMethods('%s 方法应该支持补全响应体结构', (k) => {
const c = {
// @ts-ignore
adapter: ({ success }) => {
success({
data: {},
});
},
url: '/test',
method: k,
};
request(c).then((response) => {
expect(response.status).toBeTypeOf('number');
expect(response.statusText).toBeTypeOf('string');
expect(response.headers).toBeTypeOf('object');
expect(response.data).toBeTypeOf('object');
expect(response.isFail).toBeTypeOf('undefined');
expect(response.config).toBeTypeOf('object');
expect(response.request).toBeTypeOf('undefined');
});
});
testEachMethods('%s 方法应该返回正确的响应错误结构', (k) => {
const c = {
adapter: mockAdapterError(),
validateStatus: () => false,
url: '/test',
method: k,
};
request(c).catch((error) => {
expect(error.message).toBeTypeOf('string');
expect(error.config).toBeTypeOf('object');
expect(error.request).toBeTypeOf('object');
expect(error.response.status).toBeTypeOf('number');
expect(error.response.statusText).toBeTypeOf('string');
expect(error.response.headers).toBeTypeOf('object');
expect(error.response.data).toBeTypeOf('object');
expect(error.response.isFail).toBeTypeOf('undefined');
expect(error.response.config).toBeTypeOf('object');
expect(error.response.request).toBeTypeOf('object');
});
});
testEachMethods('%s 方法应该返回正确的平台错误结构', (k) => {
const c = {
adapter: mockAdapterFail(),
validateStatus: () => false,
url: '/test',
method: k,
};
request(c).catch((error) => {
expect(error.message).toBeTypeOf('string');
expect(error.config).toBeTypeOf('object');
expect(error.request).toBeTypeOf('object');
expect(error.response.status).toBeTypeOf('number');
expect(error.response.statusText).toBeTypeOf('string');
expect(error.response.headers).toBeTypeOf('object');
expect(error.response.data).toBeTypeOf('object');
expect(error.response.isFail).toBeTruthy();
expect(error.response.config).toBeTypeOf('object');
expect(error.response.request).toBeTypeOf('object');
});
});
testEachMethods('%s 方法应该支持补全错误体结构', (k) => {
const c = {
// @ts-ignore
adapter: ({ fail }) => {
fail({
data: {},
});
},
url: '/test',
method: k,
};
request(c).catch((error) => {
expect(error.response.status).toBeTypeOf('number');
expect(error.response.statusText).toBeTypeOf('string');
expect(error.response.headers).toBeTypeOf('object');
expect(error.response.data).toBeTypeOf('object');
expect(error.response.isFail).toBeTruthy();
expect(error.response.config).toBeTypeOf('object');
expect(error.response.request).toBeTypeOf('undefined');
});
});
test('应该支持请求发送前取消请求', async () => {
const cb = vi.fn();
const task = {
abort: vi.fn(),
};
const { cancel, token } = axios.CancelToken.source();
cancel();
await request({
adapter: () => task,
url: '/test',
method: 'get' as const,
cancelToken: token,
}).catch(cb);
expect(task.abort).toBeCalled();
expect(cb).toBeCalled();
});
test('应该支持请求发送后取消请求', async () => {
const cb = vi.fn();
const task = {
abort: vi.fn(),
};
const { cancel, token } = axios.CancelToken.source();
const p = request({
adapter: () => task,
url: '/test',
method: 'get' as const,
cancelToken: token,
}).catch(cb);
cancel();
await p;
expect(task.abort).toBeCalled();
expect(cb).toBeCalled();
});
test('无 task 也应该可以取消请求', async () => {
const cb = vi.fn();
const { cancel, token } = axios.CancelToken.source();
cancel();
await request({
adapter: () => undefined,
url: '/test',
method: 'get' as const,
cancelToken: token,
}).catch(cb);
expect(cb).toBeCalled();
expect(axios.isCancel(cb.mock.calls[0][0])).toBeTruthy();
});
test('应该发送不同类型的请求', () => {
request({
adapter: ({ type }) => {
expect(type).toBe('upload');
},
url: 'test',
method: 'post',
upload: true,
});
request({
adapter: ({ type }) => {
expect(type).toBe('download');
},
url: 'test',
method: 'get',
download: true,
});
eachMethods((a) => {
request({
adapter: ({ type }) => {
expect(type).toBe('request');
},
url: 'test',
method: a,
});
});
});
test('应该可以监听上传进度', () => {
const on = vi.fn();
const cb = vi.fn();
request({
adapter: () => ({
onProgressUpdate: on,
}),
url: 'test',
method: 'post',
upload: true,
onUploadProgress: cb,
});
expect(on).toBeCalled();
expect(on.mock.calls[0][0]).toBe(cb);
});
test('取消请求时应该可以取消监听上传进度', async () => {
const on = vi.fn();
const cb = vi.fn();
const { cancel, token } = axios.CancelToken.source();
cancel();
await request({
adapter: () => ({
offProgressUpdate: on,
}),
url: 'test',
method: 'post',
upload: true,
onUploadProgress: cb,
cancelToken: token,
}).catch((err) => {
expect(axios.isCancel(err)).toBeTruthy();
});
await asyncTimeout();
expect(on).toBeCalled();
expect(on.mock.calls[0][0]).toBe(cb);
});
test('应该可以监听下载进度', async () => {
const on = vi.fn();
const cb = vi.fn();
request({
adapter: () => ({
onProgressUpdate: on,
}),
url: 'test',
method: 'get',
download: true,
onDownloadProgress: cb,
});
await asyncTimeout();
expect(on).toBeCalled();
expect(on.mock.calls[0][0]).toBe(cb);
});
test('取消请求时应该可以取消监听下载进度', async () => {
const on = vi.fn();
const cb = vi.fn();
const { cancel, token } = axios.CancelToken.source();
cancel();
await request({
adapter: () => ({
offProgressUpdate: on,
}),
url: 'test',
method: 'get',
download: true,
onDownloadProgress: cb,
cancelToken: token,
}).catch((err) => {
expect(axios.isCancel(err)).toBeTruthy();
});
expect(on).toBeCalled();
expect(on.mock.calls[0][0]).toBe(cb);
});
test('上传不应该监听下载进度/下载不应该监听上传进度', async () => {
const on = vi.fn();
const cb = vi.fn();
request({
adapter: () => ({
onProgressUpdate: on,
}),
url: 'test',
method: 'post',
upload: true,
onDownloadProgress: cb,
});
request({
adapter: () => ({
onProgressUpdate: on,
}),
url: 'test',
method: 'get',
download: true,
onUploadProgress: cb,
});
await asyncTimeout();
expect(on).not.toBeCalled();
expect(cb).not.toBeCalled();
});
});