From 4409a5720ba1e58a4c218ee67f71d5f05beee6a8 Mon Sep 17 00:00:00 2001 From: zjx0905 <954270063@qq.com> Date: Mon, 3 Apr 2023 21:03:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=90=88=E5=B9=B6?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #38 --- docs/config/adapter.md | 4 +- global.d.ts | 11 -- global.variables.d.ts | 10 ++ rollup.config.js | 4 +- scripts/test.utils.ts | 45 +++++--- src/core/Axios.ts | 52 ++++----- src/core/dispatchRequest.ts | 38 +++---- src/core/mergeConfig.ts | 91 +++++++-------- src/core/request.ts | 6 +- src/helpers/error.ts | 11 +- test/axios.test.ts | 26 ++--- test/core/cancel.test.ts | 117 +++++++++---------- test/core/createError.test.ts | 30 ++--- test/core/flattenHeaders.test.ts | 115 +++++++++++++++++++ test/core/generateType.test.ts | 35 +----- test/core/mergeConfig.test.ts | 173 +++++++++++++++++++++++++++++ test/core/request.test.ts | 75 +++++++++++++ test/core/transformData.test.ts | 58 ++++++++++ test/core/transformURL.test.ts | 74 ++++++++++++ test/helpers/buildURL.test.ts | 32 +++--- test/helpers/combineURL.test.ts | 14 +-- test/helpers/deepMerge.test.ts | 70 +++++------- test/helpers/dynamicURL.test.ts | 16 +-- test/helpers/error.test.ts | 18 +-- test/helpers/ignore.test.ts | 52 +++++---- test/helpers/isAbsoluteURL.test.ts | 18 +-- tsconfig.json | 2 +- 27 files changed, 821 insertions(+), 376 deletions(-) create mode 100644 global.variables.d.ts create mode 100644 test/core/flattenHeaders.test.ts create mode 100644 test/core/mergeConfig.test.ts create mode 100644 test/core/request.test.ts create mode 100644 test/core/transformData.test.ts create mode 100644 test/core/transformURL.test.ts diff --git a/docs/config/adapter.md b/docs/config/adapter.md index a175d64..a9c9c0e 100644 --- a/docs/config/adapter.md +++ b/docs/config/adapter.md @@ -13,6 +13,8 @@ axios.defaults.adapter = function adapter(adapterConfig) { url, // 请求方法 method, + // 请求参数 + params, // 请求数据 data, // 请求头 同 headers @@ -53,7 +55,7 @@ axios.defaults.adapter = function adapter(adapterConfig) { return wx.downloadFile({ url, method, - filePath: data.filePath, + filePath: params.filePath, header: headers, success, fail, diff --git a/global.d.ts b/global.d.ts index 9c03c7c..46cf3dc 100644 --- a/global.d.ts +++ b/global.d.ts @@ -1,12 +1 @@ -declare const uni: unknown; -declare const wx: unknown; -declare const my: unknown; -declare const swan: unknown; -declare const tt: unknown; -declare const qq: unknown; -declare const qh: unknown; -declare const ks: unknown; -declare const dd: unknown; -declare const jd: unknown; - type AnyObject = Record; diff --git a/global.variables.d.ts b/global.variables.d.ts new file mode 100644 index 0000000..588fd13 --- /dev/null +++ b/global.variables.d.ts @@ -0,0 +1,10 @@ +declare const uni: unknown; +declare const wx: unknown; +declare const my: unknown; +declare const swan: unknown; +declare const tt: unknown; +declare const qq: unknown; +declare const qh: unknown; +declare const ks: unknown; +declare const dd: unknown; +declare const jd: unknown; diff --git a/rollup.config.js b/rollup.config.js index 667d6a3..466304c 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -23,7 +23,7 @@ function main() { function buildConfig(format) { const isDts = format === 'dts'; const output = { - file: resolvePath(format, isDts), + file: resolveOutput(format, isDts), format: isDts ? 'es' : format, name: pkg.name, exports: 'default', @@ -51,7 +51,7 @@ function buildConfig(format) { }; } -function resolvePath(format, isDts) { +function resolveOutput(format, isDts) { return path.resolve( distPath, `${pkg.name}${isDts ? '.d.ts' : `.${format}.js`}`, diff --git a/scripts/test.utils.ts b/scripts/test.utils.ts index ad44740..7c1161d 100644 --- a/scripts/test.utils.ts +++ b/scripts/test.utils.ts @@ -8,7 +8,7 @@ export function asyncTimeout(delay = 0) { return new Promise((resolve) => setTimeout(resolve, delay)); } -export function captureError(fn: () => void): T { +export function captureError(fn: () => void) { try { fn(); throw new Error('without Error'); @@ -17,7 +17,7 @@ export function captureError(fn: () => void): T { } } -export function cleanedStack(error: Error) { +export function checkStack(error: Error) { if (error.stack) { return error.stack.indexOf('at') === error.stack.indexOf('at /'); } @@ -28,7 +28,7 @@ export function noop() { return; } -export function mockResponse( +export function mockResponseBase( status: number, statusText: string, headers: AnyObject, @@ -42,12 +42,15 @@ export function mockResponse( }; } -export function mockSuccess(headers: AnyObject = {}, data: AnyObject = {}) { - return mockResponse(200, 'OK', headers, data); +export function mockResponse(headers: AnyObject = {}, data: AnyObject = {}) { + return mockResponseBase(200, 'OK', headers, data); } -export function mockFail(headers: AnyObject = {}, data: AnyObject = {}) { - return mockResponse(400, 'FAIL', headers, data); +export function mockResponseError( + headers: AnyObject = {}, + data: AnyObject = {}, +) { + return mockResponseBase(400, 'FAIL', headers, data); } export interface MockAdapterOptions { @@ -58,8 +61,8 @@ export interface MockAdapterOptions { after?: () => void; } -export function mockAdapter( - type: 'success' | 'fail', +export function mockAdapterBase( + type: 'success' | 'error' | 'fail' = 'success', options: MockAdapterOptions = {}, ) { const { headers = {}, data = {}, delay = 0, before, after } = options; @@ -67,20 +70,30 @@ export function mockAdapter( return (config: AxiosAdapterRequestConfig) => { before?.(config); setTimeout(() => { - if (type === 'success') { - config.success(mockSuccess(headers, data)); - } else { - config.fail(mockFail(headers, data)); + switch (type) { + case 'success': + config.success(mockResponse(headers, data)); + break; + case 'error': + config.success(mockResponseError(headers, data)); + break; + case 'fail': + config.fail(mockResponseError(headers)); + break; } after?.(); }, delay); }; } -export function mockAdapterSuccess(options: MockAdapterOptions = {}) { - return mockAdapter('success', options); +export function mockAdapter(options: MockAdapterOptions = {}) { + return mockAdapterBase('success', options); +} + +export function mockAdapterError(options: MockAdapterOptions = {}) { + return mockAdapterBase('error', options); } export function mockAdapterFail(options: MockAdapterOptions = {}) { - return mockAdapter('fail', options); + return mockAdapterBase('fail', options); } diff --git a/src/core/Axios.ts b/src/core/Axios.ts index 4271736..920ee20 100644 --- a/src/core/Axios.ts +++ b/src/core/Axios.ts @@ -198,20 +198,34 @@ export default class Axios { this.defaults = defaults; for (const alias of Axios.as) { - this[alias] = (url, config) => { - return this._req(alias, url, undefined, config); + this[alias] = (url, config = {}) => { + return this.request({ + ...config, + method: alias, + url, + }); }; } for (const alias of Axios.pas) { - this[alias] = (url, params, config) => { - return this._req(alias, url, params, config); + this[alias] = (url, params, config = {}) => { + return this.request({ + ...config, + method: alias, + params, + url, + }); }; } for (const alias of Axios.das) { this[alias] = (url, data, config) => { - return this._reqWithData(alias, url, data, config); + return this.request({ + ...config, + method: alias, + data, + url, + }); }; } } @@ -249,32 +263,4 @@ export default class Axios { return promiseResponse as Promise>; } - - private _req( - method: AxiosRequestMethod, - url: string, - params?: AnyObject, - config?: AxiosRequestConfig, - ): Promise> { - return this.request({ - ...(config ?? {}), - method, - url, - params, - }); - } - - private _reqWithData( - method: AxiosRequestMethod, - url: string, - data?: AnyObject | AxiosRequestFormData, - config?: AxiosRequestConfig, - ): Promise> { - return this.request({ - ...(config ?? {}), - method, - url, - data, - }); - } } diff --git a/src/core/dispatchRequest.ts b/src/core/dispatchRequest.ts index 2a1f5fe..017cad6 100644 --- a/src/core/dispatchRequest.ts +++ b/src/core/dispatchRequest.ts @@ -27,32 +27,28 @@ export default function dispatchRequest( config.transformRequest, ); - return request(config).then( - (response: AxiosResponse) => { + function transformer(response: AxiosResponse) { + response.data = transformData( + response.data as AnyObject, + response.headers, + config.transformResponse, + ) as TData; + } + + return request(config) + .then((response: AxiosResponse) => { throwIfCancellationRequested(config); - - response.data = transformData( - response.data as AnyObject, - response.headers, - config.transformResponse, - ) as TData; - + transformer(response); return response; - }, - (reason: unknown) => { + }) + .catch((reason: unknown) => { if (!isCancel(reason)) { throwIfCancellationRequested(config); - - if (isPlainObject(reason) && isPlainObject(reason.response)) { - reason.response.data = transformData( - reason.response.data, - reason.response.headers, - config.transformResponse, - ); + const response = (reason as AnyObject)?.response; + if (isPlainObject(response)) { + transformer(response as AxiosResponse); } } - throw config.errorHandler?.(reason) ?? reason; - }, - ); + }); } diff --git a/src/core/mergeConfig.ts b/src/core/mergeConfig.ts index fd814d1..dde7d68 100644 --- a/src/core/mergeConfig.ts +++ b/src/core/mergeConfig.ts @@ -2,35 +2,17 @@ import { isUndefined, isPlainObject } from '../helpers/isTypes'; import { deepMerge } from '../helpers/deepMerge'; import { AxiosRequestConfig } from './Axios'; -type AxiosRequestConfigKey = keyof AxiosRequestConfig; - -const onlyFromConfig2Keys: AxiosRequestConfigKey[] = [ - 'url', - 'method', - 'data', - 'upload', - 'download', -]; -const priorityFromConfig2Keys: AxiosRequestConfigKey[] = [ - 'adapter', - 'baseURL', - 'paramsSerializer', - 'transformRequest', - 'transformResponse', - 'errorHandler', - 'cancelToken', - 'dataType', - 'responseType', - 'timeout', - 'enableHttp2', - 'enableQuic', - 'enableCache', - 'sslVerify', - 'validateStatus', - 'onUploadProgress', - 'onDownloadProgress', -]; -const deepMergeConfigKeys: AxiosRequestConfigKey[] = ['headers', 'params']; +const fromConfig2Map: Record = { + url: true, + method: true, + data: true, + upload: true, + download: true, +}; +const deepMergeConfigMap: Record = { + headers: true, + params: true, +}; export function mergeConfig( config1: AxiosRequestConfig = {}, @@ -38,33 +20,36 @@ export function mergeConfig( ): AxiosRequestConfig { const config: AxiosRequestConfig = {}; - for (const key of onlyFromConfig2Keys) { - const value = config2[key]; + // 所有已知键名 + const keysSet = Array.from( + new Set([...Object.keys(config1), ...Object.keys(config2)]), + ); - if (!isUndefined(value)) { - config[key] = value as any; + for (const key of keysSet) { + const val1 = config1[key] as any; + const val2 = config2[key] as any; + + // 只从 config2 中取值 + if (fromConfig2Map[key]) { + if (!isUndefined(val2)) config[key] = val2; } - } - - for (const key of priorityFromConfig2Keys) { - const value1 = config1[key]; - const value2 = config2[key]; - - if (!isUndefined(value2)) { - config[key] = value2 as any; - } else if (!isUndefined(value1)) { - config[key] = value1 as any; + // 深度合并 config1 和 config2 中的对象 + else if (deepMergeConfigMap[key]) { + if (isPlainObject(val1) && isPlainObject(val2)) { + config[key] = deepMerge(val1, val2); + } else if (isPlainObject(val1)) { + config[key] = deepMerge(val1); + } else if (isPlainObject(val2)) { + config[key] = deepMerge(val2); + } } - } - - for (const key of deepMergeConfigKeys) { - const value1 = config1[key]; - const value2 = config2[key]; - - if (isPlainObject(value2)) { - config[key] = deepMerge(value1 ?? {}, value2) as any; - } else if (isPlainObject(value1)) { - config[key] = deepMerge(value1) as any; + // 优先从 config2 中取值,如果没有值就从 config1 中取值 + else { + if (!isUndefined(val2)) { + config[key] = val2; + } else if (!isUndefined(val1)) { + config[key] = val1; + } } } diff --git a/src/core/request.ts b/src/core/request.ts index 784a14f..44cfef5 100644 --- a/src/core/request.ts +++ b/src/core/request.ts @@ -1,4 +1,4 @@ -import { isFunction, isPlainObject } from '../helpers/isTypes'; +import { isFunction, isPlainObject, isString } from '../helpers/isTypes'; import { assert } from '../helpers/error'; import { AxiosAdapterRequestConfig, @@ -42,10 +42,12 @@ export function request( ): Promise> { return new Promise((resolve, reject) => { assert(isFunction(config.adapter), 'adapter 不是一个 function'); + assert(isString(config.url), 'url 不是一个 string'); + assert(isString(config.method), 'method 不是一个 string'); const adapterConfig: AxiosAdapterRequestConfig = { ...config, - url: config.url ?? '', + url: config.url, type: generateType(config), method: config.method!.toUpperCase() as AxiosAdapterRequestMethod, success, diff --git a/src/helpers/error.ts b/src/helpers/error.ts index 03fca6f..af5cfc9 100644 --- a/src/helpers/error.ts +++ b/src/helpers/error.ts @@ -11,12 +11,13 @@ export function throwError(msg: string): void { } export function cleanStack(error: Error) { - if (error.stack) { - const start = error.stack.indexOf('at'); - const end = error.stack.search(/at ([\w-_.]+:)?\//i); + const { stack } = error; + if (stack) { + const start = stack.indexOf('at'); + const end = stack.search(/at ([\w-_.]+:)?\//i); if (start < end) { - const removed = error.stack.slice(start, end); - error.stack = error.stack.replace(removed, ''); + const removed = stack.slice(start, end); + error.stack = stack.replace(removed, ''); } } } diff --git a/test/axios.test.ts b/test/axios.test.ts index 01ef256..c9fe326 100644 --- a/test/axios.test.ts +++ b/test/axios.test.ts @@ -1,42 +1,42 @@ import { describe, test, expect } from 'vitest'; import axios from 'src/axios'; -import { mockAdapterFail, mockAdapterSuccess } from 'scripts/test.utils'; +import { mockAdapter, mockAdapterError } from 'scripts/test.utils'; describe('src/axios.ts', () => { test('应该处理成功和失败', () => { axios({ - adapter: mockAdapterSuccess({ + adapter: mockAdapter({ headers: { type: 'json' }, data: { v1: 1 }, before: (config) => { - expect(config.url).toBe('http://api.com/user/1?id=1'); + expect(config.url).toBe('http://api.com/test/1?id=1'); }, }), baseURL: 'http://api.com', - url: 'user/:id', + url: 'test/:id', params: { id: 1, }, - }).then((response) => { - expect(response.headers).toEqual({ type: 'json' }); - expect(response.data).toEqual({ v1: 1 }); + }).then((res) => { + expect(res.headers).toEqual({ type: 'json' }); + expect(res.data).toEqual({ v1: 1 }); }); - axios('user/:id', { - adapter: mockAdapterFail({ + axios('test/:id', { + adapter: mockAdapterError({ headers: { type: 'json' }, data: { v1: 1 }, before: (config) => { - expect(config.url).toBe('http://api.com/user/1'); + expect(config.url).toBe('http://api.com/test/1'); }, }), baseURL: 'http://api.com', data: { id: 1, }, - }).catch((error) => { - expect(error.response.headers).toEqual({ type: 'json' }); - expect(error.response.data).toEqual({ v1: 1 }); + }).catch((err) => { + expect(err.response.headers).toEqual({ type: 'json' }); + expect(err.response.data).toEqual({ v1: 1 }); }); }); }); diff --git a/test/core/cancel.test.ts b/test/core/cancel.test.ts index ca7b25c..73a5ce7 100644 --- a/test/core/cancel.test.ts +++ b/test/core/cancel.test.ts @@ -2,7 +2,7 @@ import { describe, test, expect, vi } from 'vitest'; import { asyncNext, captureError, - mockAdapterSuccess, + mockAdapter, noop, asyncTimeout, } from 'scripts/test.utils'; @@ -16,17 +16,17 @@ import { describe('src/helpers/cancel.ts', () => { test('应该支持空参数', () => { - const cancel = new Cancel(); + const c = new Cancel(); - expect(cancel.message).toBeUndefined(); - expect(cancel.toString()).toBe('Cancel'); + expect(c.message).toBeUndefined(); + expect(c.toString()).toBe('Cancel'); }); test('传入参数时应该有正确的返回结果', () => { - const cancel = new Cancel('error'); + const c = new Cancel('error'); - expect(cancel.message).toBe('error'); - expect(cancel.toString()).toBe('Cancel: error'); + expect(c.message).toBe('error'); + expect(c.toString()).toBe('Cancel: error'); }); test('应该正确判断 Cancel', () => { @@ -36,44 +36,47 @@ describe('src/helpers/cancel.ts', () => { }); test('应该可以取消', () => { - let cancelAction!: () => void; - const cancelToken = new CancelToken((action) => { - cancelAction = action; - }); + let ca!: () => void; + const ct = new CancelToken((a) => (ca = a)); - expect(cancelToken.throwIfRequested()).toBeUndefined(); - cancelAction(); - expect(() => cancelToken.throwIfRequested()).toThrowError(); + expect(ct.throwIfRequested()).toBeUndefined(); + + ca(); + + expect(() => ct.throwIfRequested()).toThrowError(); }); test('应该抛出正确的异常信息', async () => { - let cancelAction!: (msg: string) => void; - const cancelToken = new CancelToken((action) => { - cancelAction = action; - }); + let ca!: (msg: string) => void; + const ct = new CancelToken((a) => (ca = a)); - cancelAction('stop'); - const error = captureError(() => cancelToken.throwIfRequested()); - expect(error.message).toBe('stop'); - expect(error.toString()).toBe('Cancel: stop'); + const te = () => ct.throwIfRequested(); + + ca('stop'); + + expect(te).toThrowErrorMatchingInlineSnapshot(` + Cancel { + "message": "stop", + } + `); + expect(captureError(te).toString()).toBe('Cancel: stop'); }); test('回调函数应该被异步执行', async () => { - const canceled = vi.fn(); - let cancelAction!: () => void; - const cancelToken = new CancelToken((action) => { - cancelAction = action; - }); - cancelToken.onCancel(canceled); - expect(canceled).not.toBeCalled(); + const cb = vi.fn(); + let ca!: () => void; + const ct = new CancelToken((a) => (ca = a)); - cancelAction(); + ct.onCancel(cb); + expect(cb).not.toBeCalled(); - expect(canceled).not.toBeCalled(); + ca(); + + expect(cb).not.toBeCalled(); await asyncNext(); - expect(canceled).toBeCalled(); - expect(isCancel(canceled.mock.calls[0][0])).toBeTruthy(); + expect(cb).toBeCalled(); + expect(isCancel(cb.mock.calls[0][0])).toBeTruthy(); }); test('应该正确判断 CancelToken', () => { @@ -83,49 +86,51 @@ describe('src/helpers/cancel.ts', () => { }); test('应该有正确返回结果', () => { - const source = CancelToken.source(); + const s = CancelToken.source(); - expect(source.cancel).toBeTypeOf('function'); - expect(isCancelToken(source.token)).toBeTruthy(); + expect(s.cancel).toBeTypeOf('function'); + expect(isCancelToken(s.token)).toBeTruthy(); }); test('应该可以取消', () => { - const source = CancelToken.source(); + const s = CancelToken.source(); - expect(source.token.throwIfRequested()).toBeUndefined(); + expect(s.token.throwIfRequested()).toBeUndefined(); - source.cancel(); + s.cancel(); - expect(() => source.token.throwIfRequested()).toThrowError(); + expect(() => s.token.throwIfRequested()).toThrowError(); }); test('应该可以在请求发出之前取消', async () => { - const canceled = vi.fn(); - const source = CancelToken.source(); + const cb = vi.fn(); + const s = CancelToken.source(); + + s.cancel(); - source.cancel(); axios({ - adapter: mockAdapterSuccess(), - cancelToken: source.token, - }).catch(canceled); + adapter: mockAdapter(), + cancelToken: s.token, + }).catch(cb); await asyncTimeout(); - expect(canceled).toBeCalled(); - expect(isCancel(canceled.mock.calls[0][0])).toBeTruthy(); + expect(cb).toBeCalled(); + expect(isCancel(cb.mock.calls[0][0])).toBeTruthy(); }); test('应该可以在请求发出之后取消', async () => { - const canceled = vi.fn(); - const source = CancelToken.source(); + const cb = vi.fn(); + const s = CancelToken.source(); axios({ - adapter: mockAdapterSuccess(), - cancelToken: source.token, - }).catch(canceled); - source.cancel(); + adapter: mockAdapter(), + cancelToken: s.token, + }).catch(cb); + + s.cancel(); await asyncTimeout(); - expect(canceled).toBeCalled(); - expect(isCancel(canceled.mock.calls[0][0])).toBeTruthy(); + expect(cb).toBeCalled(); + expect(isCancel(cb.mock.calls[0][0])).toBeTruthy(); }); }); diff --git a/test/core/createError.test.ts b/test/core/createError.test.ts index 005e300..cad20e4 100644 --- a/test/core/createError.test.ts +++ b/test/core/createError.test.ts @@ -1,27 +1,27 @@ import { describe, test, expect } from 'vitest'; -import { cleanedStack } from 'scripts/test.utils'; +import { checkStack } from 'scripts/test.utils'; import { createError } from 'src/core/createError'; describe('src/core/createError.ts', () => { test('应该支持空参数', () => { - const config = {}; - const axiosError = createError('error', config); + const c = {}; + const err = createError('error', c); - expect(axiosError.isAxiosError).toBeTruthy(); - expect(axiosError.message).toBe('error'); - expect(axiosError.config).toBe(config); - expect(cleanedStack(axiosError)).toBeTruthy(); + expect(err.isAxiosError).toBeTruthy(); + expect(err.message).toBe('error'); + expect(err.config).toBe(c); + expect(checkStack(err)).toBeTruthy(); }); test('应该支持传入更多参数', () => { - const config = {}; - const request = {}; - const response = {}; - const axiosError = createError('error', config, request, response as any); + const c = {}; + const req = {}; + const res = {}; + const err = createError('error', c, req, res as any); - expect(axiosError.message).toBe('error'); - expect(axiosError.config).toBe(config); - expect(axiosError.request).toBe(request); - expect(axiosError.response).toBe(response); + expect(err.message).toBe('error'); + expect(err.config).toBe(c); + expect(err.request).toBe(req); + expect(err.response).toBe(res); }); }); diff --git a/test/core/flattenHeaders.test.ts b/test/core/flattenHeaders.test.ts new file mode 100644 index 0000000..5bac678 --- /dev/null +++ b/test/core/flattenHeaders.test.ts @@ -0,0 +1,115 @@ +import { describe, test, expect } from 'vitest'; +import { flattenHeaders } from 'src/core/flattenHeaders'; +import Axios from 'src/core/Axios'; + +describe('src/core/flattenHeaders.ts', () => { + const keys = [...Axios.as, ...Axios.pas, ...Axios.das]; + const baseHeaders = { + options: { + v1: 'options1', + v2: 'options2', + }, + trace: { + v1: 'trace1', + v2: 'trace2', + }, + connect: { + v1: 'connect1', + v2: 'connect2', + }, + head: { + v1: 'head1', + v2: 'head2', + }, + get: { + v1: 'get1', + v2: 'get2', + }, + delete: { + v1: 'delete1', + v2: 'delete2', + }, + post: { + v1: 'post1', + v2: 'post2', + }, + put: { + v1: 'put1', + v2: 'put2', + }, + }; + + test('应该支持空配置', () => { + expect(flattenHeaders({})).toBeUndefined(); + }); + + test('应该支持自定义 headers', () => { + const h = { + v1: '1', + v2: '2', + }; + expect(flattenHeaders({ headers: h, method: 'get' })).toEqual(h); + }); + + test('应该支持别名 headers,并且自定义 headers 优先级应该高于别名 headers', () => { + const h1 = baseHeaders; + const h2 = { v1: 1, v2: 2 }; + const h3 = { ...h1, ...h2 }; + + keys.forEach((a) => { + expect(flattenHeaders({ headers: h1, method: a })).toEqual(h1[a]); + expect(flattenHeaders({ headers: h3, method: a })).toEqual(h2); + }); + }); + + test('应该支持通用 headers,并且别名 headers 优先级应该高于通用 headers', () => { + const h1 = { + common: { + v1: 'common1', + v2: 'common2', + }, + }; + const h2 = { ...baseHeaders, ...h1 }; + + keys.forEach((a) => { + expect(flattenHeaders({ headers: h1, method: a })).toEqual(h1.common); + expect(flattenHeaders({ headers: h2, method: a })).toEqual(h2[a]); + }); + }); + + test.each( + keys.map((k) => [ + k, + { + common: { + v1: 'common1', + v2: 'common1', + }, + [k]: { + v3: `${k}1`, + v4: `${k}2`, + }, + v5: 5, + v6: 6, + }, + ]), + )('应该获取到完整的 %s headers', (k, h) => { + const h1 = { + v1: 'common1', + v2: 'common1', + v5: 5, + v6: 6, + }; + const h2 = { + ...h1, + v3: `${k}1`, + v4: `${k}2`, + }; + + keys.forEach((a) => { + expect(flattenHeaders({ headers: h, method: a })).toEqual( + a !== k ? h1 : h2, + ); + }); + }); +}); diff --git a/test/core/generateType.test.ts b/test/core/generateType.test.ts index 354d689..961cfc1 100644 --- a/test/core/generateType.test.ts +++ b/test/core/generateType.test.ts @@ -1,50 +1,19 @@ import { describe, test, expect } from 'vitest'; -import { mockAdapterSuccess } from 'scripts/test.utils'; import { generateType } from 'src/core/generateType'; import Axios from 'src/core/Axios'; -import axios from 'src/axios'; describe('src/core/generateType.ts', () => { test('应该是一个 reuqest', () => { - for (const alias of [...Axios.as, ...Axios.pas, ...Axios.das]) { - expect(generateType({ method: alias })).toBe('request'); - - axios({ - adapter: mockAdapterSuccess({ - before: (config) => { - expect(config.type).toBe('request'); - }, - }), - method: alias, - }); + for (const a of [...Axios.as, ...Axios.pas, ...Axios.das]) { + expect(generateType({ method: a })).toBe('request'); } }); test('应该是一个 upload', () => { expect(generateType({ method: 'post', upload: true })).toBe('upload'); - - axios({ - adapter: mockAdapterSuccess({ - before: (config) => { - expect(config.type).toBe('upload'); - }, - }), - method: 'post', - upload: true, - }); }); test('应该是一个 download', () => { expect(generateType({ method: 'get', download: true })).toBe('download'); - - axios({ - adapter: mockAdapterSuccess({ - before: (config) => { - expect(config.type).toBe('download'); - }, - }), - method: 'get', - download: true, - }); }); }); diff --git a/test/core/mergeConfig.test.ts b/test/core/mergeConfig.test.ts new file mode 100644 index 0000000..7dc7479 --- /dev/null +++ b/test/core/mergeConfig.test.ts @@ -0,0 +1,173 @@ +import { describe, test, expect, vi } from 'vitest'; +import { ignore } from 'src/helpers/ignore'; +import { mergeConfig } from 'src/core/mergeConfig'; +import { CancelToken } from 'src/core/cancel'; + +describe('src/core/mergeConfig.ts', () => { + test('应该支持空参数', () => { + expect(mergeConfig()).toEqual({}); + expect(mergeConfig({ baseURL: '/api' })).toEqual({ baseURL: '/api' }); + }); + + test('应该只取 config2', () => { + const c1 = { + url: 'a', + method: 'get' as const, + data: {}, + upload: true, + download: true, + }; + const c2 = { + url: 'b', + method: 'post' as const, + data: {}, + upload: false, + download: false, + }; + + expect(mergeConfig(c1, {})).toEqual({}); + expect(mergeConfig({}, c2)).toEqual(c2); + expect(mergeConfig(c1, c2)).toEqual(c2); + + Object.keys(c2).forEach((_) => { + const key = _ as keyof typeof c2; + expect(mergeConfig(ignore(c1, key), c2)).toEqual(c2); + expect(mergeConfig(c1, ignore(c2, key))).toEqual(ignore(c2, key)); + }); + }); + + test('应该深度合并', () => { + const c1 = { + headers: { + common: { + v1: 1, + }, + v1: 1, + }, + params: { + v1: 1, + }, + }; + const c2 = { + headers: { + common: { + v2: 2, + }, + v2: 2, + }, + params: { + v2: 2, + }, + }; + const mc = { + headers: { + common: { + v1: 1, + v2: 2, + }, + v1: 1, + v2: 2, + }, + params: { + v1: 1, + v2: 2, + }, + }; + + expect(mergeConfig(c1, {})).toEqual(c1); + expect(mergeConfig({}, c2)).toEqual(c2); + expect(mergeConfig(c1, c2)).toEqual(mc); + + Object.keys(c2).forEach((_) => { + const key = _ as keyof typeof c2; + expect(mergeConfig(ignore(c1, key), c2)).toEqual({ + ...mc, + [key]: c2[key], + }); + expect(mergeConfig(c1, ignore(c2, key))).toEqual({ + ...mc, + [key]: c1[key], + }); + }); + }); + + test('应该优先取 config2', () => { + const c1 = { + adapter: vi.fn(), + baseURL: 'https://c1.com', + paramsSerializer: vi.fn(), + transformRequest: vi.fn(), + transformResponse: vi.fn(), + errorHandler: vi.fn(), + cancelToken: CancelToken.source().token, + dataType: 'json', + responseType: 'json', + timeout: 1000, + validateStatus: vi.fn(), + onUploadProgress: vi.fn(), + onDownloadProgress: vi.fn(), + }; + const c2 = { + adapter: vi.fn(), + baseURL: 'https://c2.com', + paramsSerializer: vi.fn(), + transformRequest: vi.fn(), + transformResponse: vi.fn(), + errorHandler: vi.fn(), + cancelToken: CancelToken.source().token, + dataType: 'json', + responseType: 'json', + timeout: 1000, + validateStatus: vi.fn(), + onUploadProgress: vi.fn(), + onDownloadProgress: vi.fn(), + }; + + expect(mergeConfig(c1, {})).toEqual(c1); + expect(mergeConfig({}, c2)).toEqual(c2); + expect(mergeConfig(c1, c2)).toEqual(c2); + + Object.keys(c2).forEach((_) => { + const key = _ as keyof typeof c2; + expect(mergeConfig(ignore(c1, key), c2)).toEqual(c2); + expect(mergeConfig(c1, ignore(c2, key))).toEqual({ + ...c2, + [key]: c1[key], + }); + }); + }); + + test('应该支持自定义配置', () => { + const c1 = { + custom1: 1, + custom2: 'c1', + custom3: vi.fn(), + custom4: { c1: 1 }, + custom5: ['c1'], + custom6: new Date(), + custom7: () => 1, + }; + const c2 = { + custom1: 2, + custom2: 'c2', + custom3: vi.fn(), + custom4: { c2: 2 }, + custom5: ['c2'], + custom6: new Date(), + custom7: () => 2, + }; + + expect(mergeConfig(c1, {})).toEqual(c1); + expect(mergeConfig({}, c2)).toEqual(c2); + expect(mergeConfig(c1, c2)).toEqual(c2); + + Object.keys(c2).forEach((_) => { + const key = _ as keyof typeof c2; + expect(mergeConfig(ignore(c1, key), c2)).toEqual(c2); + expect(mergeConfig(c1, ignore(c2, key))).toEqual({ + ...c2, + [key]: c1[key], + }); + }); + }); +}); diff --git a/test/core/request.test.ts b/test/core/request.test.ts new file mode 100644 index 0000000..8f1f9be --- /dev/null +++ b/test/core/request.test.ts @@ -0,0 +1,75 @@ +import { describe, test, expect } from 'vitest'; +import { request } from 'src/core/request'; +import { + mockAdapter, + mockAdapterError, + mockAdapterFail, +} from 'scripts/test.utils'; + +describe('src/core/request.ts', () => { + test('应该抛出异常', async () => { + await expect(request({})).rejects.toThrowErrorMatchingInlineSnapshot( + '"[axios-miniprogram]: adapter 不是一个 function"', + ); + await expect( + request({ adapter: mockAdapter() }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + '"[axios-miniprogram]: url 不是一个 string"', + ); + await expect( + request({ adapter: mockAdapter(), url: 'test' }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + '"[axios-miniprogram]: method 不是一个 string"', + ); + }); + + test('应该能够取到数据', async () => { + await expect( + request({ + adapter: mockAdapter(), + url: '/test', + method: 'get', + }), + ).resolves.toMatchInlineSnapshot(` + { + "config": { + "adapter": [Function], + "method": "get", + "url": "/test", + }, + "data": {}, + "headers": {}, + "request": undefined, + "status": 200, + "statusText": "OK", + } + `); + await expect( + request({ + adapter: mockAdapterError(), + url: '/test', + method: 'get', + }), + ).resolves.toMatchInlineSnapshot(` + { + "config": { + "adapter": [Function], + "method": "get", + "url": "/test", + }, + "data": {}, + "headers": {}, + "request": undefined, + "status": 400, + "statusText": "FAIL", + } + `); + await expect( + request({ + adapter: mockAdapterFail(), + url: '/test', + method: 'get', + }), + ).rejects.toThrowErrorMatchingInlineSnapshot('"网络错误"'); + }); +}); diff --git a/test/core/transformData.test.ts b/test/core/transformData.test.ts new file mode 100644 index 0000000..32adf57 --- /dev/null +++ b/test/core/transformData.test.ts @@ -0,0 +1,58 @@ +import { describe, test, expect } from 'vitest'; +import { transformData } from 'src/core/transformData'; + +describe('src/core/transformData.ts', () => { + test('应该支持空配置', () => { + expect(transformData()).toBeUndefined(); + expect(transformData({})).toEqual({}); + }); + + test('应该支持转换器', () => { + const h = { + type: 0, + }; + const d = { + v1: 1, + }; + const t = { + v2: 2, + }; + + const fn = (data: any, headers: any) => { + expect(data).toEqual(d); + expect(headers).toEqual(h); + return t; + }; + + expect(transformData(d, h, fn)).toEqual(t); + }); + + test('应该支持转换器数组', () => { + const h = { + type: 0, + }; + const d = { + v1: 1, + }; + const t1 = { + v2: 2, + }; + const t2 = { + v3: 3, + }; + + const fn1 = (data: any, headers: any) => { + expect(data).toEqual(d); + expect(headers).toEqual(h); + return t1; + }; + + const fn2 = (data: any, headers: any) => { + expect(data).toEqual(t1); + expect(headers).toEqual(h); + return t2; + }; + + expect(transformData(d, h, [fn1, fn2])).toEqual(t2); + }); +}); diff --git a/test/core/transformURL.test.ts b/test/core/transformURL.test.ts new file mode 100644 index 0000000..32b2eba --- /dev/null +++ b/test/core/transformURL.test.ts @@ -0,0 +1,74 @@ +import { describe, test, expect } from 'vitest'; +import { transformURL } from 'src/core/transformURL'; + +describe('src/core/transformURL.ts', () => { + test('应该支持空配置', () => { + expect(transformURL({})).toBe(''); + expect(transformURL({ baseURL: 'http://api.com' })).toBe('http://api.com'); + expect(transformURL({ url: 'test' })).toBe('/test'); + }); + + test('应该合并 URL', () => { + expect( + transformURL({ + baseURL: 'http://api.com', + url: 'test', + }), + ).toBe('http://api.com/test'); + expect( + transformURL({ + baseURL: 'http://api.com', + url: '/test', + }), + ).toBe('http://api.com/test'); + }); + + test('应该支持绝对路径', () => { + expect( + transformURL({ + baseURL: 'http://api.com', + url: 'http://api2.com', + }), + ).toBe('http://api2.com'); + }); + + test('应该支持动态 URL', () => { + expect( + transformURL({ + baseURL: 'http://api.com', + url: 'test/:name/:type', + params: { + name: 'axios', + type: 0, + }, + }), + ).toBe('http://api.com/test/axios/0?name=axios&type=0'); + expect( + transformURL({ + baseURL: 'http://api.com', + url: 'test/:name/:type', + data: { + name: 'axios', + type: 0, + }, + }), + ).toBe('http://api.com/test/axios/0'); + }); + + test('应该支持自定义参数系列化器', () => { + expect( + transformURL({ + baseURL: 'http://api.com', + url: 'test', + paramsSerializer: () => 'type=0', + }), + ).toBe('http://api.com/test?type=0'); + expect( + transformURL({ + baseURL: 'http://api.com', + url: 'test?name=axios', + paramsSerializer: () => 'type=0', + }), + ).toBe('http://api.com/test?name=axios&type=0'); + }); +}); diff --git a/test/helpers/buildURL.test.ts b/test/helpers/buildURL.test.ts index 8faddb8..86474d1 100644 --- a/test/helpers/buildURL.test.ts +++ b/test/helpers/buildURL.test.ts @@ -3,61 +3,61 @@ import { buildURL } from 'src/helpers/buildURL'; describe('src/helpers/buildURL.ts', () => { test('应该支持空参数', () => { - expect(buildURL('/user')).toBe('/user'); + expect(buildURL('/test')).toBe('/test'); }); test('应该清理哈希值', () => { - expect(buildURL('/user#hash')).toBe('/user'); + expect(buildURL('/test#hash')).toBe('/test'); }); test('应该对参数进行系列化', () => { expect( - buildURL('/user#hash', { + buildURL('/test#hash', { v1: 1, v2: undefined, v3: null, v4: '4', v5: NaN, }), - ).toBe('/user?v1=1&v4=4'); + ).toBe('/test?v1=1&v4=4'); expect( - buildURL('/user?v1=1', { + buildURL('/test?v1=1', { v2: 2, }), - ).toBe('/user?v1=1&v2=2'); + ).toBe('/test?v1=1&v2=2'); }); test('应该对数组进行系列化', () => { expect( - buildURL('/user', { + buildURL('/test', { arr: [1, 2], }), - ).toBe('/user?arr[]=1&arr[]=2'); + ).toBe('/test?arr[]=1&arr[]=2'); }); test('应该对对象进行系列化', () => { expect( - buildURL('/user', { + buildURL('/test', { obj: { k1: 1, k2: 2, }, }), - ).toBe('/user?obj[k1]=1&obj[k2]=2'); + ).toBe('/test?obj[k1]=1&obj[k2]=2'); }); test('应该对日期进行系列化', () => { - const date = new Date(); - expect(buildURL('/user', { date })).toBe( - `/user?date=${date.toISOString()}`, + const d = new Date(); + expect(buildURL('/test', { date: d })).toBe( + `/test?date=${d.toISOString()}`, ); }); test('应该支持自定义序列化器', () => { - expect(buildURL('/user', {}, () => 'v1=1&v2=2')).toBe('/user?v1=1&v2=2'); - expect(buildURL('/user?v1=1', {}, () => 'v2=2&v3=3')).toBe( - '/user?v1=1&v2=2&v3=3', + expect(buildURL('/test', {}, () => 'v1=1&v2=2')).toBe('/test?v1=1&v2=2'); + expect(buildURL('/test?v1=1', {}, () => 'v2=2&v3=3')).toBe( + '/test?v1=1&v2=2&v3=3', ); }); }); diff --git a/test/helpers/combineURL.test.ts b/test/helpers/combineURL.test.ts index 644f4b1..dd5189d 100644 --- a/test/helpers/combineURL.test.ts +++ b/test/helpers/combineURL.test.ts @@ -9,17 +9,17 @@ describe('src/helpers/combineURL.ts', () => { }); test('应该得到拼接后的结果', () => { - expect(combineURL('http://api.com', '/user')).toBe('http://api.com/user'); - expect(combineURL('file://api.com', '/user')).toBe('file://api.com/user'); - expect(combineURL('unknow://api.com', '/user')).toBe( - 'unknow://api.com/user', + expect(combineURL('http://api.com', '/test')).toBe('http://api.com/test'); + expect(combineURL('file://api.com', '/test')).toBe('file://api.com/test'); + expect(combineURL('unknow://api.com', '/test')).toBe( + 'unknow://api.com/test', ); }); test('应该清理多余的斜线', () => { - expect(combineURL('//api//', '//user//')).toBe('/api/user/'); - expect(combineURL('http://api.com//', '//user//')).toBe( - 'http://api.com/user/', + expect(combineURL('//api//', '//test//')).toBe('/api/test/'); + expect(combineURL('http://api.com//', '//test//')).toBe( + 'http://api.com/test/', ); }); }); diff --git a/test/helpers/deepMerge.test.ts b/test/helpers/deepMerge.test.ts index 31bf985..39199dd 100644 --- a/test/helpers/deepMerge.test.ts +++ b/test/helpers/deepMerge.test.ts @@ -3,66 +3,50 @@ import { deepMerge } from 'src/helpers/deepMerge'; describe('src/helpers/deepMerge.ts', () => { test('应该支持空参数', () => { - expect(deepMerge()).toEqual({}); - }); - - test('应该直接返回第一个参数', () => { - expect( - deepMerge({ - v1: 1, - v2: [1], - v3: { v: 'v3' }, - v4: undefined, - v5: null, - v6: 'v6', - }), - ).toEqual({ + const o = { v1: 1, v2: [1], v3: { v: 'v3' }, v4: undefined, v5: null, v6: 'v6', - }); + }; + + expect(deepMerge()).toEqual({}); + expect(deepMerge(o)).toEqual(o); }); test('应该进行合并', () => { - expect( - deepMerge( - { - v1: 1, - v2: 2, - v3: 3, - }, - { - v2: 22, - v3: undefined, - v4: 4, - }, - ), - ).toEqual({ + const o1 = { v1: 1, + v2: 2, + v3: 3, + }; + const o2 = { v2: 22, v3: undefined, v4: 4, + }; + + expect(deepMerge(o1, o2)).toEqual({ + ...o1, + ...o2, }); }); test('应该合并对象里的对象', () => { - expect( - deepMerge( - { - v1: { v: 1 }, - v2: { v: 2 }, - v3: 3, - }, - { - v1: { vv: 11 }, - v2: 2, - v3: { v: 3 }, - }, - ), - ).toEqual({ + const o1 = { + v1: { v: 1 }, + v2: { v: 2 }, + v3: 3, + }; + const o2 = { + v1: { vv: 11 }, + v2: 2, + v3: { v: 3 }, + }; + + expect(deepMerge(o1, o2)).toEqual({ v1: { v: 1, vv: 11 }, v2: 2, v3: { v: 3 }, diff --git a/test/helpers/dynamicURL.test.ts b/test/helpers/dynamicURL.test.ts index b8a08bd..88b4373 100644 --- a/test/helpers/dynamicURL.test.ts +++ b/test/helpers/dynamicURL.test.ts @@ -3,20 +3,20 @@ import { dynamicURL } from 'src/helpers/dynamicURL'; describe('src/helpers/dynamicURL.ts', () => { test('应该替换关键字', () => { - expect(dynamicURL('http://api.com/user/:id', {})).toBe( - 'http://api.com/user/undefined', + expect(dynamicURL('http://api.com/test/:id', {})).toBe( + 'http://api.com/test/undefined', ); - expect(dynamicURL('http://api.com/user/:id', { id: 1 })).toBe( - 'http://api.com/user/1', + expect(dynamicURL('http://api.com/test/:id', { id: 1 })).toBe( + 'http://api.com/test/1', ); }); test('应该支持多个关键字', () => { expect( - dynamicURL('http://api.com/users/name/:name/age/:age/list', { - name: 'my', - age: 18, + dynamicURL('http://api.com/tests/name/:name/type/:type/list', { + name: 'axios', + type: 0, }), - ).toBe('http://api.com/users/name/my/age/18/list'); + ).toBe('http://api.com/tests/name/axios/type/0/list'); }); }); diff --git a/test/helpers/error.test.ts b/test/helpers/error.test.ts index 042460a..1d81038 100644 --- a/test/helpers/error.test.ts +++ b/test/helpers/error.test.ts @@ -1,5 +1,5 @@ import { describe, test, expect } from 'vitest'; -import { captureError, cleanedStack } from 'scripts/test.utils'; +import { captureError, checkStack } from 'scripts/test.utils'; import { assert, throwError, cleanStack } from 'src/helpers/error'; describe('src/helpers/error.ts', () => { @@ -9,25 +9,27 @@ describe('src/helpers/error.ts', () => { test('第一个参数为 false 时应该抛出异常', () => { expect(() => assert(false, '')).toThrowError(); - expect(cleanedStack(captureError(() => assert(false, '')))).toBeTruthy(); + expect(checkStack(captureError(() => assert(false, '')))).toBeTruthy(); }); test('应该抛出异常', () => { - expect(() => throwError('')).toThrowError('[axios-miniprogram]: '); - expect(() => throwError('error')).toThrowError( - '[axios-miniprogram]: error', + expect(() => throwError('')).toThrowErrorMatchingInlineSnapshot( + '"[axios-miniprogram]: "', ); - expect(cleanedStack(captureError(() => throwError('error')))).toBeTruthy(); + expect(() => throwError('error')).toThrowErrorMatchingInlineSnapshot( + '"[axios-miniprogram]: error"', + ); + expect(checkStack(captureError(() => throwError('error')))).toBeTruthy(); }); test('应该清掉多余的错误栈', () => { const ce = () => new Error(); const error = ce(); - expect(cleanedStack(error)).toBeFalsy(); + expect(checkStack(error)).toBeFalsy(); cleanStack(error); - expect(cleanedStack(error)).toBeTruthy(); + expect(checkStack(error)).toBeTruthy(); }); }); diff --git a/test/helpers/ignore.test.ts b/test/helpers/ignore.test.ts index 4aa4d37..ddbaa77 100644 --- a/test/helpers/ignore.test.ts +++ b/test/helpers/ignore.test.ts @@ -3,31 +3,37 @@ import { ignore } from 'src/helpers/ignore'; describe('src/helpers/ignore.ts', () => { test('不应该改变传入的对象', () => { - expect( - ignore({ - v1: 1, - }), - ).toEqual({ - v1: 1, - }); + expect(ignore({ v1: 1 })).toEqual({ v1: 1 }); }); test('应该忽略指定键值', () => { - expect( - ignore( - { - v1: 1, - v2: {}, - v3: [], - v4: undefined, - v5: 5, - v6: null, - }, - 'v1', - 'v2', - 'v3', - 'v4', - ), - ).toEqual({ v5: 5, v6: null }); + const o = { + v1: 1, + v2: {}, + v3: [], + }; + + expect(ignore(o, 'v1')).toEqual({ + v2: {}, + v3: [], + }); + expect(ignore(o, 'v2')).toEqual({ + v1: 1, + v3: [], + }); + expect(ignore(o, 'v3')).toEqual({ + v1: 1, + v2: {}, + }); + expect(ignore(o, 'v1', 'v2')).toEqual({ + v3: [], + }); + expect(ignore(o, 'v2', 'v3')).toEqual({ + v1: 1, + }); + expect(ignore(o, 'v1', 'v3')).toEqual({ + v2: {}, + }); + expect(ignore(o, 'v1', 'v2', 'v3')).toEqual({}); }); }); diff --git a/test/helpers/isAbsoluteURL.test.ts b/test/helpers/isAbsoluteURL.test.ts index eda4a17..e3f560c 100644 --- a/test/helpers/isAbsoluteURL.test.ts +++ b/test/helpers/isAbsoluteURL.test.ts @@ -4,17 +4,17 @@ import { isAbsoluteURL } from 'src/helpers/isAbsoluteURL'; describe('src/helpers/isAbsoluteURL.ts', () => { test('应该不是绝对路径', () => { expect(isAbsoluteURL('user')).toBeFalsy(); - expect(isAbsoluteURL('/user')).toBeFalsy(); - expect(isAbsoluteURL('//user')).toBeFalsy(); - expect(isAbsoluteURL('://user')).toBeFalsy(); + expect(isAbsoluteURL('/test')).toBeFalsy(); + expect(isAbsoluteURL('//test')).toBeFalsy(); + expect(isAbsoluteURL('://test')).toBeFalsy(); }); test('应该是绝对路径', () => { - expect(isAbsoluteURL('http://user')).toBeTruthy(); - expect(isAbsoluteURL('HTTP://user')).toBeTruthy(); - expect(isAbsoluteURL('https://user')).toBeTruthy(); - expect(isAbsoluteURL('custom://user')).toBeTruthy(); - expect(isAbsoluteURL('custom-v1.0://user')).toBeTruthy(); - expect(isAbsoluteURL('custom_v1.0://user')).toBeTruthy(); + expect(isAbsoluteURL('http://test')).toBeTruthy(); + expect(isAbsoluteURL('HTTP://test')).toBeTruthy(); + expect(isAbsoluteURL('https://test')).toBeTruthy(); + expect(isAbsoluteURL('custom://test')).toBeTruthy(); + expect(isAbsoluteURL('custom-v1.0://test')).toBeTruthy(); + expect(isAbsoluteURL('custom_v1.0://test')).toBeTruthy(); }); }); diff --git a/tsconfig.json b/tsconfig.json index 505f2ca..488f013 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,6 @@ "noEmit": true, "moduleResolution": "node" }, - "include": ["./src", "./test", "./global.d.ts"], + "include": ["./src", "./test", "./global.d.ts", "./global.variables.d.ts"], "exclude": ["node_modules"] }