Skip to content

Commit 76d4023

Browse files
authored
feat: support mock.delay (#73)
* feat: support mock.delay * chore: add changelog * chore: support url parameter * chore(mock): use this.config, no need to pass from mock()
1 parent 9dba782 commit 76d4023

File tree

9 files changed

+204
-3
lines changed

9 files changed

+204
-3
lines changed

.changeset/eleven-snails-cry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@umijs/tnf': patch
3+
---
4+
5+
feat: configure the delay of the mock globally.

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ An object that maps package names to their corresponding paths.
122122

123123
The configuration passed to lessLoader.
124124

125+
### mock
126+
127+
- Type: `{ delay?: string | number }`
128+
- Default: `{ delay: 0 }`
129+
130+
In addition to supporting numbers, delay also supports string ranges, such as delay: '500-1000', which randomly selects a value between 500ms and 1000ms.And allowing the configuration to be overridden by the url parameter, such as /api/users?delay=3000.
131+
125132
### plugins
126133

127134
- Type: `Plugin[]`

examples/normal/.tnfrc.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ export default defineConfig({
2626
},
2727
},
2828
],
29+
mock: { delay: '500-1000' },
2930
});

examples/normal/mock/foo.js

Lines changed: 148 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,153 @@
1+
const data = {
2+
"users": [
3+
{
4+
"id": 1,
5+
"firstName": "Emily",
6+
"lastName": "Johnson",
7+
"maidenName": "Smith",
8+
"age": 28,
9+
"gender": "female",
10+
"email": "emily.johnson@x.dummyjson.com",
11+
"phone": "+81 965-431-3024",
12+
"username": "emilys",
13+
"password": "emilyspass",
14+
"birthDate": "1996-5-30",
15+
"image": "https://dummyjson.com/icon/emilys/128",
16+
"bloodGroup": "O-",
17+
"height": 193.24,
18+
"weight": 63.16,
19+
"eyeColor": "Green",
20+
"hair": {
21+
"color": "Brown",
22+
"type": "Curly"
23+
},
24+
"ip": "42.48.100.32",
25+
"address": {
26+
"address": "626 Main Street",
27+
"city": "Phoenix",
28+
"state": "Mississippi",
29+
"stateCode": "MS",
30+
"postalCode": "29112",
31+
"coordinates": {
32+
"lat": -77.16213,
33+
"lng": -92.084824
34+
},
35+
"country": "United States"
36+
},
37+
"macAddress": "47:fa:41:18:ec:eb",
38+
"university": "University of Wisconsin--Madison",
39+
"bank": {
40+
"cardExpire": "03/26",
41+
"cardNumber": "9289760655481815",
42+
"cardType": "Elo",
43+
"currency": "CNY",
44+
"iban": "YPUXISOBI7TTHPK2BR3HAIXL"
45+
},
46+
"company": {
47+
"department": "Engineering",
48+
"name": "Dooley, Kozey and Cronin",
49+
"title": "Sales Manager",
50+
"address": {
51+
"address": "263 Tenth Street",
52+
"city": "San Francisco",
53+
"state": "Wisconsin",
54+
"stateCode": "WI",
55+
"postalCode": "37657",
56+
"coordinates": {
57+
"lat": 71.814525,
58+
"lng": -161.150263
59+
},
60+
"country": "United States"
61+
}
62+
},
63+
"ein": "977-175",
64+
"ssn": "900-590-289",
65+
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36",
66+
"crypto": {
67+
"coin": "Bitcoin",
68+
"wallet": "0xb9fc2fe63b2a6c003f1c324c3bfa53259162181a",
69+
"network": "Ethereum (ERC20)"
70+
},
71+
"role": "admin"
72+
},
73+
{
74+
"id": 2,
75+
"firstName": "Michael",
76+
"lastName": "Williams",
77+
"maidenName": "",
78+
"age": 35,
79+
"gender": "male",
80+
"email": "michael.williams@x.dummyjson.com",
81+
"phone": "+49 258-627-6644",
82+
"username": "michaelw",
83+
"password": "michaelwpass",
84+
"birthDate": "1989-8-10",
85+
"image": "https://dummyjson.com/icon/michaelw/128",
86+
"bloodGroup": "B+",
87+
"height": 186.22,
88+
"weight": 76.32,
89+
"eyeColor": "Red",
90+
"hair": {
91+
"color": "Green",
92+
"type": "Straight"
93+
},
94+
"ip": "12.13.116.142",
95+
"address": {
96+
"address": "385 Fifth Street",
97+
"city": "Houston",
98+
"state": "Alabama",
99+
"stateCode": "AL",
100+
"postalCode": "38807",
101+
"coordinates": {
102+
"lat": 22.815468,
103+
"lng": 115.608581
104+
},
105+
"country": "United States"
106+
},
107+
"macAddress": "79:15:78:99:60:aa",
108+
"university": "Ohio State University",
109+
"bank": {
110+
"cardExpire": "02/27",
111+
"cardNumber": "6737807858721625",
112+
"cardType": "Elo",
113+
"currency": "SEK",
114+
"iban": "83IDT77FWYLCJVR8ISDACFH0"
115+
},
116+
"company": {
117+
"department": "Support",
118+
"name": "Spinka - Dickinson",
119+
"title": "Support Specialist",
120+
"address": {
121+
"address": "395 Main Street",
122+
"city": "Los Angeles",
123+
"state": "New Hampshire",
124+
"stateCode": "NH",
125+
"postalCode": "73442",
126+
"coordinates": {
127+
"lat": 79.098326,
128+
"lng": -119.624845
129+
},
130+
"country": "United States"
131+
}
132+
},
133+
"ein": "912-602",
134+
"ssn": "108-953-962",
135+
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/97.0.1072.76 Safari/537.36",
136+
"crypto": {
137+
"coin": "Bitcoin",
138+
"wallet": "0xb9fc2fe63b2a6c003f1c324c3bfa53259162181a",
139+
"network": "Ethereum (ERC20)"
140+
},
141+
"role": "admin"
142+
},
143+
],
144+
"total": 208,
145+
"skip": 0,
146+
"limit": 30
147+
}
1148

2149
module.exports = {
3150
'GET /api/foo': (req, res) => {
4-
res.json({ message: 'hello' });
151+
res.json(data);
5152
},
6153
};

examples/normal/src/pages/foo.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
export const Route = createFileRoute('/foo')({
99
component: Foo,
1010
loader: async ({ context }) => {
11-
const res = await fetch('https://dummyjson.com/users');
11+
// const res = await fetch('https://dummyjson.com/users');
12+
const res = await fetch('/api/foo?delay=5000');
1213
const data = await res.json();
1314
return data;
1415
},

src/config/types.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,19 @@ export const ConfigSchema = z
9393
renderMode: z.enum(['stream', 'string']).optional(),
9494
})
9595
.optional(),
96+
mock: z
97+
.object({
98+
delay: z
99+
.union([
100+
z.number().optional(),
101+
z
102+
.string()
103+
.regex(/^\d+-\d+$/)
104+
.optional(),
105+
])
106+
.optional(),
107+
})
108+
.optional(),
96109
})
97110
.strict();
98111

src/funplugins/mock/createMockMiddleware.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import pathToRegexp from 'path-to-regexp';
66
import type { MockData } from './types';
77

88
export function createMockMiddleware(context: MockData): RequestHandler {
9-
return (req, res, next) => {
9+
return async (req, res, next) => {
1010
const method = req.method.toUpperCase();
1111
for (const key of Object.keys(context.mocks)) {
1212
const mock = context.mocks[key]!;
@@ -26,6 +26,28 @@ export function createMockMiddleware(context: MockData): RequestHandler {
2626
}
2727
}
2828
req.params = params;
29+
30+
// parse delay from path, like /api/users?delay=3000
31+
// delay in params url is greater than that configuration mock.delay
32+
let delay = Number(req.query?.delay) || 0;
33+
if (delay === 0) {
34+
const delayValue = context.config?.mock?.delay;
35+
if (typeof delayValue === 'string' && delayValue.includes('-')) {
36+
const [min, max] = delayValue
37+
.split('-')
38+
.map(Number)
39+
.filter((n) => !isNaN(n));
40+
if (min !== undefined && max !== undefined) {
41+
delay = Math.floor(Math.random() * (max - min + 1)) + min;
42+
}
43+
} else {
44+
delay = Number(delayValue ?? 0);
45+
}
46+
}
47+
if (delay > 0) {
48+
await new Promise((resolve) => setTimeout(resolve, delay));
49+
}
50+
2951
// handler
3052
if (method === 'GET') {
3153
mock.handler(req, res, next);

src/funplugins/mock/mock.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { Config } from '../../config/types';
12
import type { Plugin } from '../../plugin/types';
23
import { createMockMiddleware } from './createMockMiddleware';
34
import { getMockData } from './getMockData';
@@ -11,6 +12,7 @@ export function mock(opts: MockOptions): Plugin {
1112
server.middlewares.use(
1213
createMockMiddleware({
1314
mocks,
15+
config: this.config as Config,
1416
}),
1517
);
1618
},

src/funplugins/mock/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { Config } from '../../config/types';
2+
13
export interface Mock {
24
method: string;
35
path: string;
@@ -13,4 +15,5 @@ export interface MockOptions {
1315

1416
export interface MockData {
1517
mocks: Record<string, Mock>;
18+
config?: Config;
1619
}

0 commit comments

Comments
 (0)