From 258954afc1c39483ff6b1828c8904c5b284890d2 Mon Sep 17 00:00:00 2001 From: zjx0905 <954270063@qq.com> Date: Thu, 20 Apr 2023 10:57:10 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=8E=A7=E5=88=B6=E5=8F=B0=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E8=BE=93=E5=87=BA=E9=80=82=E9=85=8D=E5=99=A8=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/test.utils.ts | 14 ++- src/core/dispatchRequest.ts | 11 +- src/core/request.ts | 4 +- test/adapter.platform.test.ts | 3 +- test/core/dispatchRequest.test.ts | 36 ++++-- test/core/request.test.ts | 203 ++++++++++++++---------------- 6 files changed, 142 insertions(+), 129 deletions(-) diff --git a/scripts/test.utils.ts b/scripts/test.utils.ts index 1a18e0e..510247e 100644 --- a/scripts/test.utils.ts +++ b/scripts/test.utils.ts @@ -1,4 +1,10 @@ -import { AxiosAdapterRequestConfig } from 'src'; +import { test } from 'vitest'; +import { + requestMethodNames, + requestMethodWithParamsNames, + requestMethodWithDataNames, +} from '@/core/AxiosDomain'; +import { AxiosAdapterRequestConfig } from '@/adapter'; export function asyncNext() { return Promise.resolve().then; @@ -106,3 +112,9 @@ export function mockAdapterError(options: MockAdapterOptions = {}) { export function mockAdapterFail(options: MockAdapterOptions = {}) { return mockAdapterBase('fail', options); } + +export const testEachMethods = test.each([ + ...requestMethodNames, + ...requestMethodWithParamsNames, + ...requestMethodWithDataNames, +]); diff --git a/src/core/dispatchRequest.ts b/src/core/dispatchRequest.ts index 8ead70c..650130e 100644 --- a/src/core/dispatchRequest.ts +++ b/src/core/dispatchRequest.ts @@ -4,7 +4,7 @@ import { Cancel, isCancel, isCancelToken } from './cancel'; import { flattenHeaders } from './flattenHeaders'; import { AxiosTransformer, transformData } from './transformData'; import { request } from './request'; -import { AxiosRequestConfig, AxiosResponse } from './Axios'; +import { AxiosRequestConfig, AxiosRequestMethod, AxiosResponse } from './Axios'; import { transformURL } from './transformURL'; import { AxiosErrorResponse } from './createError'; import { requestMethodWithDataNames } from './AxiosDomain'; @@ -32,6 +32,7 @@ export function dispatchRequest(config: AxiosRequestConfig) { assert(isString(config.method), 'method 不是一个 string'); config.url = transformURL(config); + config.method = config.method!.toUpperCase() as AxiosRequestMethod; config.headers = flattenHeaders(config); // 可以携带 data 的请求方法,转换 data @@ -49,13 +50,13 @@ export function dispatchRequest(config: AxiosRequestConfig) { return response; } - function onError(reason: Cancel | AxiosErrorResponse) { - if (!isCancel(reason)) { + function onError(error: Cancel | AxiosErrorResponse) { + if (!isCancel(error)) { throwIfCancellationRequested(config); - dataTransformer(reason.response, config.transformResponse); + dataTransformer(error.response, config.transformResponse); } - return Promise.reject(reason); + return Promise.reject(error); } function dataTransformer( diff --git a/src/core/request.ts b/src/core/request.ts index 82cfba0..9a79a02 100644 --- a/src/core/request.ts +++ b/src/core/request.ts @@ -31,7 +31,7 @@ export function request(config: AxiosRequestConfig) { ...config, url: url!, type: generateType(config), - method: method!.toUpperCase() as AxiosAdapterRequestMethod, + method: method as AxiosAdapterRequestMethod, success, fail, }; @@ -44,6 +44,8 @@ export function request(config: AxiosRequestConfig) { status: 400, statusText: 'Bad Adapter', }); + + console.error(err); } function success(baseResponse: AxiosAdapterResponse): void { diff --git a/test/adapter.platform.test.ts b/test/adapter.platform.test.ts index 65fa465..94556f8 100644 --- a/test/adapter.platform.test.ts +++ b/test/adapter.platform.test.ts @@ -19,8 +19,8 @@ describe.each(platforms)('src/adapter.ts', (p) => { beforeEach(() => { vi.stubGlobal(p, { request: vi.fn(), - uploadFile: vi.fn(), downloadFile: vi.fn(), + uploadFile: vi.fn(), }); }); @@ -32,7 +32,6 @@ describe.each(platforms)('src/adapter.ts', (p) => { const a = getDefaultAdapter(); if (p !== 'unknown') { expect(a).toBeTypeOf('function'); - (expect(a).property('name') as any).toBe('adapter'); } else { // unknown 未知平台 expect(a).toBeUndefined(); diff --git a/test/core/dispatchRequest.test.ts b/test/core/dispatchRequest.test.ts index 0bda36c..cd5b7d4 100644 --- a/test/core/dispatchRequest.test.ts +++ b/test/core/dispatchRequest.test.ts @@ -1,14 +1,15 @@ import { describe, test, expect, vi } from 'vitest'; import { asyncNext, mockAdapter } from 'scripts/test.utils'; import { dispatchRequest } from '@/core/dispatchRequest'; -import axios from '@/axios'; -import _defaults from '@/defaults'; import { requestMethodNames, requestMethodWithDataNames, requestMethodWithParamsNames, } from '@/core/AxiosDomain'; +import axios from '@/axios'; +import _defaults from '@/defaults'; + describe('src/core/dispatchRequest.ts', () => { const defaults = { ..._defaults, @@ -37,6 +38,22 @@ describe('src/core/dispatchRequest.ts', () => { ).not.toThrowError(); }); + test.each([ + ...requestMethodNames, + ...requestMethodWithDataNames, + ...requestMethodWithParamsNames, + ])('应该支持 %s 转全大写', (k) => { + const c = { + adapter: mockAdapter(), + url: '/', + method: k, + }; + + dispatchRequest(c); + + expect(c.method).toBe(k.toUpperCase()); + }); + test('坏的适配器应该抛出异常', () => { expect( dispatchRequest({ @@ -51,7 +68,7 @@ describe('src/core/dispatchRequest.ts', () => { "config": { "adapter": [Function], "headers": {}, - "method": "get", + "method": "GET", "url": "", }, "request": undefined, @@ -59,7 +76,7 @@ describe('src/core/dispatchRequest.ts', () => { "config": { "adapter": [Function], "headers": {}, - "method": "get", + "method": "GET", "url": "", }, "data": undefined, @@ -126,19 +143,18 @@ describe('src/core/dispatchRequest.ts', () => { }); }); - test('应该支持转换请求数据', () => { + test.each(requestMethodWithDataNames)('%s 方法应该支持转换请求数据', (k) => { const c = { ...defaults, url: 'test', + method: k, data: {}, transformRequest: () => ({ id: 1 }), }; - requestMethodWithDataNames.forEach((k) => { - const s = { ...c, method: k }; - dispatchRequest(s); - expect(s.data).toEqual({ id: 1 }); - }); + dispatchRequest(c); + + expect(c.data).toEqual({ id: 1 }); }); test('不能带数据的请求方法应该删除数据', () => { diff --git a/test/core/request.test.ts b/test/core/request.test.ts index dadee04..5a9640c 100644 --- a/test/core/request.test.ts +++ b/test/core/request.test.ts @@ -4,6 +4,7 @@ import { mockAdapter, mockAdapterError, mockAdapterFail, + testEachMethods, } from 'scripts/test.utils'; import { request } from '@/core/request'; import { @@ -14,128 +15,110 @@ import { import axios from '@/axios'; describe('src/core/request.ts', () => { - test('应该返回正确的响应体结构', () => { - [ - ...requestMethodNames, - ...requestMethodWithDataNames, - ...requestMethodWithParamsNames, - ].forEach((k) => { - request({ - adapter: mockAdapter(), - url: '/test', - method: k, - }).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 = { + 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'); }); }); - test('应该支持补全响应体结构', () => { - [ - ...requestMethodNames, - ...requestMethodWithDataNames, - ...requestMethodWithParamsNames, - ].forEach((k) => { - request({ - adapter: ({ success }) => { - success({ - data: {}, - }); - }, - url: '/test', - method: k, - }).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 = { + // @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'); }); }); - test('应该返回正确的响应错误结构', () => { - [ - ...requestMethodNames, - ...requestMethodWithDataNames, - ...requestMethodWithParamsNames, - ].forEach((k) => { - request({ - adapter: mockAdapterError(), - validateStatus: () => false, - url: '/test', - method: k, - }).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: 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'); }); }); - test('应该返回正确的平台错误结构', () => { - [ - ...requestMethodNames, - ...requestMethodWithDataNames, - ...requestMethodWithParamsNames, - ].forEach((k) => { - request({ - adapter: mockAdapterFail(), - validateStatus: () => false, - url: '/test', - method: k, - }).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 = { + 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'); }); }); - test('应该支持补全错误体结构', () => { - [ - ...requestMethodNames, - ...requestMethodWithDataNames, - ...requestMethodWithParamsNames, - ].forEach((k) => { - request({ - adapter: ({ fail }) => { - fail({ - data: {}, - }); - }, - url: '/test', - method: k, - }).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'); - }); + 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'); }); });