@yeepay/request-mock 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/dist/index.d.mts +21 -0
- package/dist/index.mjs +47 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# @yeepay/request-mock
|
|
2
|
+
|
|
3
|
+
为 `@yeepay/request` 添加本地开发与测试 Mock。支持 glob/正则模块匹配、includes、excludes、延迟、可注入日志和未命中透传。
|
|
4
|
+
|
|
5
|
+
## 安装与示例
|
|
6
|
+
|
|
7
|
+
`pnpm add -D @yeepay/request-mock`
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
const mocked = withRequestMock(http, {
|
|
11
|
+
modules: { '/users/*': ({ url }) => ({ id: url.split('/').at(-1) }) },
|
|
12
|
+
})
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 配置与迁移
|
|
16
|
+
|
|
17
|
+
`includes` 和 `excludes` 控制启用范围,`delayMs` 模拟延迟,`logger` 由应用注入。未命中请求透传真实客户端。该包不得加入生产依赖;从 Axios Mock Adapter 迁移时改为包装公开 HttpClient。
|
|
18
|
+
|
|
19
|
+
[公司飞书规范](https://yeepay.feishu.cn/docx/S67Wd9mdVokULGxIRmFcQiK8nKg)
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { HttpClient } from "@yeepay/request";
|
|
2
|
+
//#region src/index.d.ts
|
|
3
|
+
type MockPattern = string | RegExp;
|
|
4
|
+
interface MockContext<TBody = unknown> {
|
|
5
|
+
body?: TBody | undefined;
|
|
6
|
+
method: string;
|
|
7
|
+
url: string;
|
|
8
|
+
}
|
|
9
|
+
type MockHandler = unknown | ((context: MockContext) => Promise<unknown> | unknown);
|
|
10
|
+
interface RequestMockOptions {
|
|
11
|
+
delayMs?: number;
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
excludes?: readonly MockPattern[];
|
|
14
|
+
includes?: readonly MockPattern[];
|
|
15
|
+
logger?: (message: string) => void;
|
|
16
|
+
modules: Readonly<Record<string, MockHandler>>;
|
|
17
|
+
}
|
|
18
|
+
declare function withRequestMock(client: HttpClient, options: RequestMockOptions): HttpClient;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { MockContext, MockHandler, MockPattern, RequestMockOptions, withRequestMock };
|
|
21
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import picomatch from "picomatch";
|
|
2
|
+
//#region src/index.ts
|
|
3
|
+
function matches(value, pattern) {
|
|
4
|
+
return pattern instanceof RegExp ? pattern.test(value) : picomatch.isMatch(value, pattern);
|
|
5
|
+
}
|
|
6
|
+
function allowed(url, options) {
|
|
7
|
+
if ((options.excludes ?? []).some((pattern) => matches(url, pattern))) return false;
|
|
8
|
+
return (options.includes ?? ["**"]).some((pattern) => matches(url, pattern));
|
|
9
|
+
}
|
|
10
|
+
function wait(duration) {
|
|
11
|
+
return new Promise((resolve) => setTimeout(resolve, duration));
|
|
12
|
+
}
|
|
13
|
+
function withRequestMock(client, options) {
|
|
14
|
+
async function request(method, url, config = {}) {
|
|
15
|
+
if (options.enabled === false || !allowed(url, options)) return client.request(method, url, config);
|
|
16
|
+
const entry = Object.entries(options.modules).find(([pattern]) => matches(url, pattern));
|
|
17
|
+
if (!entry) return client.request(method, url, config);
|
|
18
|
+
if ((options.delayMs ?? 0) > 0) await wait(options.delayMs ?? 0);
|
|
19
|
+
options.logger?.(`[request-mock] ${method.toUpperCase()} ${url}`);
|
|
20
|
+
return typeof entry[1] === "function" ? await entry[1]({
|
|
21
|
+
body: config.body,
|
|
22
|
+
method: method.toUpperCase(),
|
|
23
|
+
url
|
|
24
|
+
}) : entry[1];
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
request,
|
|
28
|
+
get: (url, config) => request("GET", url, config),
|
|
29
|
+
post: (url, body, config) => request("POST", url, {
|
|
30
|
+
...config,
|
|
31
|
+
body
|
|
32
|
+
}),
|
|
33
|
+
put: (url, body, config) => request("PUT", url, {
|
|
34
|
+
...config,
|
|
35
|
+
body
|
|
36
|
+
}),
|
|
37
|
+
patch: (url, body, config) => request("PATCH", url, {
|
|
38
|
+
...config,
|
|
39
|
+
body
|
|
40
|
+
}),
|
|
41
|
+
delete: (url, config) => request("DELETE", url, config)
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { withRequestMock };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { HttpClient, HttpRequestConfig } from '@yeepay/request'\nimport picomatch from 'picomatch'\n\nexport type MockPattern = string | RegExp\nexport interface MockContext<TBody = unknown> {\n body?: TBody | undefined\n method: string\n url: string\n}\nexport type MockHandler = unknown | ((context: MockContext) => Promise<unknown> | unknown)\n\nexport interface RequestMockOptions {\n delayMs?: number\n enabled?: boolean\n excludes?: readonly MockPattern[]\n includes?: readonly MockPattern[]\n logger?: (message: string) => void\n modules: Readonly<Record<string, MockHandler>>\n}\n\nfunction matches(value: string, pattern: MockPattern): boolean {\n return pattern instanceof RegExp ? pattern.test(value) : picomatch.isMatch(value, pattern)\n}\n\nfunction allowed(url: string, options: RequestMockOptions): boolean {\n if ((options.excludes ?? []).some(pattern => matches(url, pattern)))\n return false\n return (options.includes ?? ['**']).some(pattern => matches(url, pattern))\n}\n\nfunction wait(duration: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, duration))\n}\n\nexport function withRequestMock(client: HttpClient, options: RequestMockOptions): HttpClient {\n async function request<TResponse, TBody = unknown>(method: string, url: string, config: HttpRequestConfig<TBody> = {}): Promise<TResponse> {\n if (options.enabled === false || !allowed(url, options))\n return client.request<TResponse, TBody>(method, url, config)\n const entry = Object.entries(options.modules).find(([pattern]) => matches(url, pattern))\n if (!entry)\n return client.request<TResponse, TBody>(method, url, config)\n if ((options.delayMs ?? 0) > 0)\n await wait(options.delayMs ?? 0)\n options.logger?.(`[request-mock] ${method.toUpperCase()} ${url}`)\n const value = typeof entry[1] === 'function'\n ? await entry[1]({ body: config.body, method: method.toUpperCase(), url })\n : entry[1]\n return value as TResponse\n }\n\n return {\n request,\n get: (url, config) => request('GET', url, config),\n post: (url, body, config) => request('POST', url, { ...config, body }),\n put: (url, body, config) => request('PUT', url, { ...config, body }),\n patch: (url, body, config) => request('PATCH', url, { ...config, body }),\n delete: (url, config) => request('DELETE', url, config),\n }\n}\n"],"mappings":";;AAoBA,SAAS,QAAQ,OAAe,SAA+B;CAC7D,OAAO,mBAAmB,SAAS,QAAQ,KAAK,KAAK,IAAI,UAAU,QAAQ,OAAO,OAAO;AAC3F;AAEA,SAAS,QAAQ,KAAa,SAAsC;CAClE,KAAK,QAAQ,YAAY,CAAC,EAAA,CAAG,MAAK,YAAW,QAAQ,KAAK,OAAO,CAAC,GAChE,OAAO;CACT,QAAQ,QAAQ,YAAY,CAAC,IAAI,EAAA,CAAG,MAAK,YAAW,QAAQ,KAAK,OAAO,CAAC;AAC3E;AAEA,SAAS,KAAK,UAAiC;CAC7C,OAAO,IAAI,SAAQ,YAAW,WAAW,SAAS,QAAQ,CAAC;AAC7D;AAEA,SAAgB,gBAAgB,QAAoB,SAAyC;CAC3F,eAAe,QAAoC,QAAgB,KAAa,SAAmC,CAAC,GAAuB;EACzI,IAAI,QAAQ,YAAY,SAAS,CAAC,QAAQ,KAAK,OAAO,GACpD,OAAO,OAAO,QAA0B,QAAQ,KAAK,MAAM;EAC7D,MAAM,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC,CAAC,MAAM,CAAC,aAAa,QAAQ,KAAK,OAAO,CAAC;EACvF,IAAI,CAAC,OACH,OAAO,OAAO,QAA0B,QAAQ,KAAK,MAAM;EAC7D,KAAK,QAAQ,WAAW,KAAK,GAC3B,MAAM,KAAK,QAAQ,WAAW,CAAC;EACjC,QAAQ,SAAS,kBAAkB,OAAO,YAAY,EAAE,GAAG,KAAK;EAIhE,OAHc,OAAO,MAAM,OAAO,aAC9B,MAAM,MAAM,EAAE,CAAC;GAAE,MAAM,OAAO;GAAM,QAAQ,OAAO,YAAY;GAAG;EAAI,CAAC,IACvE,MAAM;CAEZ;CAEA,OAAO;EACL;EACA,MAAM,KAAK,WAAW,QAAQ,OAAO,KAAK,MAAM;EAChD,OAAO,KAAK,MAAM,WAAW,QAAQ,QAAQ,KAAK;GAAE,GAAG;GAAQ;EAAK,CAAC;EACrE,MAAM,KAAK,MAAM,WAAW,QAAQ,OAAO,KAAK;GAAE,GAAG;GAAQ;EAAK,CAAC;EACnE,QAAQ,KAAK,MAAM,WAAW,QAAQ,SAAS,KAAK;GAAE,GAAG;GAAQ;EAAK,CAAC;EACvE,SAAS,KAAK,WAAW,QAAQ,UAAU,KAAK,MAAM;CACxD;AACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@yeepay/request-mock",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"README.md"
|
|
8
|
+
],
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.mts",
|
|
12
|
+
"import": "./dist/index.mjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsdown src/index.ts --format esm --dts --sourcemap",
|
|
17
|
+
"clean": "rm -rf dist",
|
|
18
|
+
"typecheck": "tsc --noEmit"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"picomatch": "4.0.5"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"@yeepay/request": "^0.1.0-alpha.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/picomatch": "4.0.2",
|
|
28
|
+
"@yeepay/request": "workspace:*"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
}
|
|
33
|
+
}
|