mockaton 11.3.1 → 11.4.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 +3 -3
- package/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/client/ApiCommander.js +3 -0
- package/src/client/ApiConstants.js +1 -0
- package/src/client/app-store.js +10 -0
- package/src/client/app.js +44 -2
- package/src/client/styles.css +33 -7
- package/src/server/Api.js +12 -0
- package/src/server/ApiConstants.js +1 -0
- package/src/server/Mockaton.test.js +14 -1
package/README.md
CHANGED
|
@@ -50,9 +50,9 @@ curl localhost:2020/api/user
|
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
<picture>
|
|
53
|
-
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.
|
|
54
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.
|
|
55
|
-
<img alt="Mockaton Dashboard" src="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.
|
|
53
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp822x740.light.gold.png">
|
|
54
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp822x740.dark.gold.png">
|
|
55
|
+
<img alt="Mockaton Dashboard" src="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp822x740.dark.gold.png">
|
|
56
56
|
</picture>
|
|
57
57
|
|
|
58
58
|
On the dashboard you can:
|
package/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -23,6 +23,9 @@ export class Commander {
|
|
|
23
23
|
|
|
24
24
|
/** @returns {Promise<Response>} */
|
|
25
25
|
setGlobalDelay = delay => this.#patch(API.globalDelay, delay)
|
|
26
|
+
|
|
27
|
+
/** @returns {Promise<Response>} */
|
|
28
|
+
setGlobalDelayJitter = jitterPct => this.#patch(API.globalDelayJitter, jitterPct)
|
|
26
29
|
|
|
27
30
|
/** @returns {Promise<Response>} */
|
|
28
31
|
setCorsAllowed = value => this.#patch(API.cors, value)
|
|
@@ -12,6 +12,7 @@ export const API = {
|
|
|
12
12
|
delayStatic: MOUNT + '/delay-static',
|
|
13
13
|
fallback: MOUNT + '/fallback',
|
|
14
14
|
globalDelay: MOUNT + '/global-delay',
|
|
15
|
+
globalDelayJitter: MOUNT + '/global-delay-jitter',
|
|
15
16
|
proxied: MOUNT + '/proxied',
|
|
16
17
|
reset: MOUNT + '/reset',
|
|
17
18
|
select: MOUNT + '/select',
|
package/src/client/app-store.js
CHANGED
|
@@ -16,6 +16,7 @@ export const store = {
|
|
|
16
16
|
cookies: [],
|
|
17
17
|
comments: [],
|
|
18
18
|
delay: 0,
|
|
19
|
+
delayJitter: 0,
|
|
19
20
|
|
|
20
21
|
collectProxied: false,
|
|
21
22
|
proxyFallback: '',
|
|
@@ -84,6 +85,15 @@ export const store = {
|
|
|
84
85
|
}
|
|
85
86
|
catch (error) { store.onError(error) }
|
|
86
87
|
},
|
|
88
|
+
|
|
89
|
+
async setGlobalDelayJitter(value) {
|
|
90
|
+
try {
|
|
91
|
+
const response = await api.setGlobalDelayJitter(value)
|
|
92
|
+
if (!response.ok) throw response
|
|
93
|
+
store.delayJitter = value
|
|
94
|
+
}
|
|
95
|
+
catch (error) { store.onError(error) }
|
|
96
|
+
},
|
|
87
97
|
|
|
88
98
|
async selectCookie(name) {
|
|
89
99
|
try {
|
package/src/client/app.js
CHANGED
|
@@ -17,6 +17,8 @@ const CSS = {
|
|
|
17
17
|
FallbackBackend: null,
|
|
18
18
|
Field: null,
|
|
19
19
|
GlobalDelayField: null,
|
|
20
|
+
GlobalDelayJitterField: null,
|
|
21
|
+
GlobalDelayWrap: null,
|
|
20
22
|
GroupByMethod: null,
|
|
21
23
|
InternalServerErrorToggler: null,
|
|
22
24
|
Logo: null,
|
|
@@ -118,14 +120,18 @@ function Header() {
|
|
|
118
120
|
height: 22
|
|
119
121
|
})),
|
|
120
122
|
r('div', null,
|
|
121
|
-
|
|
123
|
+
r('div', className(CSS.GlobalDelayWrap),
|
|
124
|
+
GlobalDelayField(),
|
|
125
|
+
GlobalDelayJitterField()),
|
|
122
126
|
BulkSelector(),
|
|
123
127
|
CookieSelector(),
|
|
124
128
|
ProxyFallbackField(),
|
|
125
129
|
ResetButton(),
|
|
126
|
-
SettingsMenuTrigger()
|
|
130
|
+
SettingsMenuTrigger()
|
|
131
|
+
)))
|
|
127
132
|
}
|
|
128
133
|
|
|
134
|
+
|
|
129
135
|
function GlobalDelayField() {
|
|
130
136
|
function onChange() {
|
|
131
137
|
store.setGlobalDelay(this.valueAsNumber)
|
|
@@ -142,6 +148,7 @@ function GlobalDelayField() {
|
|
|
142
148
|
r('label', className(CSS.Field, CSS.GlobalDelayField),
|
|
143
149
|
r('span', null, t`Delay (ms)`),
|
|
144
150
|
r('input', {
|
|
151
|
+
name: 'delay',
|
|
145
152
|
type: 'number',
|
|
146
153
|
min: 0,
|
|
147
154
|
step: 100,
|
|
@@ -152,6 +159,38 @@ function GlobalDelayField() {
|
|
|
152
159
|
})))
|
|
153
160
|
}
|
|
154
161
|
|
|
162
|
+
function GlobalDelayJitterField() {
|
|
163
|
+
function onChange() {
|
|
164
|
+
this.value = this.valueAsNumber.toFixed(0)
|
|
165
|
+
this.value = Math.max(0, this.valueAsNumber)
|
|
166
|
+
this.value = Math.min(300, this.valueAsNumber)
|
|
167
|
+
store.setGlobalDelayJitter(this.valueAsNumber / 100)
|
|
168
|
+
}
|
|
169
|
+
function onWheel(event) {
|
|
170
|
+
if (event.deltaY > 0)
|
|
171
|
+
this.stepUp()
|
|
172
|
+
else
|
|
173
|
+
this.stepDown()
|
|
174
|
+
clearTimeout(onWheel.timer)
|
|
175
|
+
onWheel.timer = setTimeout(onChange.bind(this), 300)
|
|
176
|
+
}
|
|
177
|
+
return (
|
|
178
|
+
r('label', className(CSS.Field, CSS.GlobalDelayJitterField),
|
|
179
|
+
r('span', null, t`Max Jitter %`),
|
|
180
|
+
r('input', {
|
|
181
|
+
name: 'delay-jitter',
|
|
182
|
+
type: 'number',
|
|
183
|
+
min: 0,
|
|
184
|
+
max: 300,
|
|
185
|
+
step: 10,
|
|
186
|
+
autocomplete: 'none',
|
|
187
|
+
value: (store.delayJitter * 100).toFixed(0),
|
|
188
|
+
onChange,
|
|
189
|
+
onWheel: [onWheel, { passive: true }]
|
|
190
|
+
})))
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
|
|
155
194
|
function BulkSelector() {
|
|
156
195
|
const { comments } = store
|
|
157
196
|
const firstOption = t`Pick Comment…`
|
|
@@ -208,6 +247,7 @@ function ProxyFallbackField() {
|
|
|
208
247
|
r('label', null,
|
|
209
248
|
r('span', null, t`Fallback`),
|
|
210
249
|
r('input', {
|
|
250
|
+
name: 'fallback',
|
|
211
251
|
type: 'url',
|
|
212
252
|
autocomplete: 'none',
|
|
213
253
|
placeholder: t`Type backend address`,
|
|
@@ -221,6 +261,7 @@ function SaveProxiedCheckbox(ref) {
|
|
|
221
261
|
return (
|
|
222
262
|
r('label', className(CSS.SaveProxiedCheckbox),
|
|
223
263
|
r('input', {
|
|
264
|
+
name: 'save-proxied',
|
|
224
265
|
ref,
|
|
225
266
|
type: 'checkbox',
|
|
226
267
|
disabled: !store.canProxy,
|
|
@@ -268,6 +309,7 @@ function SettingsMenu(id) {
|
|
|
268
309
|
r('div', null,
|
|
269
310
|
r('label', className(CSS.GroupByMethod),
|
|
270
311
|
r('input', {
|
|
312
|
+
name: 'group-by-method',
|
|
271
313
|
ref: firstInputRef,
|
|
272
314
|
type: 'checkbox',
|
|
273
315
|
checked: store.groupByMethod,
|
package/src/client/styles.css
CHANGED
|
@@ -137,7 +137,7 @@ header {
|
|
|
137
137
|
align-self: end;
|
|
138
138
|
margin-right: 22px;
|
|
139
139
|
margin-bottom: 3px;
|
|
140
|
-
|
|
140
|
+
|
|
141
141
|
object {
|
|
142
142
|
pointer-events: none;
|
|
143
143
|
}
|
|
@@ -151,10 +151,10 @@ header {
|
|
|
151
151
|
gap: 16px 8px;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
@media (max-width:
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
align-self:
|
|
154
|
+
@media (max-width: 820px) {
|
|
155
|
+
.Logo {
|
|
156
|
+
margin-top: 16px;
|
|
157
|
+
align-self: start;
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
> div {
|
|
@@ -170,6 +170,10 @@ header {
|
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
.GlobalDelayWrap {
|
|
174
|
+
display: flex;
|
|
175
|
+
}
|
|
176
|
+
|
|
173
177
|
.Field {
|
|
174
178
|
width: 116px;
|
|
175
179
|
|
|
@@ -202,10 +206,13 @@ header {
|
|
|
202
206
|
}
|
|
203
207
|
|
|
204
208
|
&.GlobalDelayField {
|
|
209
|
+
position: relative;
|
|
205
210
|
width: 76px;
|
|
206
211
|
|
|
207
|
-
input
|
|
212
|
+
input {
|
|
208
213
|
padding-right: 6px;
|
|
214
|
+
border-bottom-right-radius: 0;
|
|
215
|
+
border-top-right-radius: 0;
|
|
209
216
|
}
|
|
210
217
|
|
|
211
218
|
svg {
|
|
@@ -215,6 +222,25 @@ header {
|
|
|
215
222
|
stroke-width: 3px;
|
|
216
223
|
border-radius: 50%;
|
|
217
224
|
}
|
|
225
|
+
|
|
226
|
+
&:focus-within {
|
|
227
|
+
z-index: 100;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
&.GlobalDelayJitterField {
|
|
232
|
+
width: 70px;
|
|
233
|
+
span {
|
|
234
|
+
margin-left: 0;
|
|
235
|
+
}
|
|
236
|
+
input {
|
|
237
|
+
border-left: 2px solid transparent;
|
|
238
|
+
border-bottom-left-radius: 0;
|
|
239
|
+
border-top-left-radius: 0;
|
|
240
|
+
}
|
|
241
|
+
&:focus-within {
|
|
242
|
+
z-index: 100;
|
|
243
|
+
}
|
|
218
244
|
}
|
|
219
245
|
|
|
220
246
|
&.CookieSelector {
|
|
@@ -223,7 +249,7 @@ header {
|
|
|
223
249
|
|
|
224
250
|
&.FallbackBackend {
|
|
225
251
|
position: relative;
|
|
226
|
-
width:
|
|
252
|
+
width: 150px;
|
|
227
253
|
|
|
228
254
|
.SaveProxiedCheckbox {
|
|
229
255
|
position: absolute;
|
package/src/server/Api.js
CHANGED
|
@@ -39,6 +39,7 @@ export const apiPatchReqs = new Map([
|
|
|
39
39
|
[API.reset, reinitialize],
|
|
40
40
|
[API.cookies, selectCookie],
|
|
41
41
|
[API.globalDelay, setGlobalDelay],
|
|
42
|
+
[API.globalDelayJitter, setGlobalDelayJitter],
|
|
42
43
|
|
|
43
44
|
[API.fallback, setProxyFallback],
|
|
44
45
|
[API.collectProxied, setCollectProxied],
|
|
@@ -117,6 +118,17 @@ async function setGlobalDelay(req, response) {
|
|
|
117
118
|
}
|
|
118
119
|
}
|
|
119
120
|
|
|
121
|
+
async function setGlobalDelayJitter(req, response) {
|
|
122
|
+
const jitter = await req.json()
|
|
123
|
+
|
|
124
|
+
if (!ConfigValidator.delayJitter(jitter))
|
|
125
|
+
response.unprocessable(`Expected 0 to 3 float for "delayJitter"`)
|
|
126
|
+
else {
|
|
127
|
+
config.delayJitter = jitter
|
|
128
|
+
response.ok()
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
120
132
|
|
|
121
133
|
async function selectCookie(req, response) {
|
|
122
134
|
const cookieKey = await req.json()
|
|
@@ -12,6 +12,7 @@ export const API = {
|
|
|
12
12
|
delayStatic: MOUNT + '/delay-static',
|
|
13
13
|
fallback: MOUNT + '/fallback',
|
|
14
14
|
globalDelay: MOUNT + '/global-delay',
|
|
15
|
+
globalDelayJitter: MOUNT + '/global-delay-jitter',
|
|
15
16
|
proxied: MOUNT + '/proxied',
|
|
16
17
|
reset: MOUNT + '/reset',
|
|
17
18
|
select: MOUNT + '/select',
|
|
@@ -309,7 +309,7 @@ describe('Cookie', () => {
|
|
|
309
309
|
|
|
310
310
|
describe('Delay', () => {
|
|
311
311
|
describe('Set Global Delay', () => {
|
|
312
|
-
test('422 for invalid
|
|
312
|
+
test('422 for invalid value', async () => {
|
|
313
313
|
const r = await api.setGlobalDelay('not-a-number')
|
|
314
314
|
equal(r.status, 422)
|
|
315
315
|
equal(await r.text(), 'Expected non-negative integer for "delay"')
|
|
@@ -321,6 +321,19 @@ describe('Delay', () => {
|
|
|
321
321
|
})
|
|
322
322
|
})
|
|
323
323
|
|
|
324
|
+
describe('Set Global Delay Jitter', () => {
|
|
325
|
+
test('422 for invalid value', async () => {
|
|
326
|
+
const r = await api.setGlobalDelayJitter('not-a-number')
|
|
327
|
+
equal(r.status, 422)
|
|
328
|
+
equal(await r.text(), 'Expected 0 to 3 float for "delayJitter"')
|
|
329
|
+
})
|
|
330
|
+
test('200 for valid value', async () => {
|
|
331
|
+
const r = await api.setGlobalDelayJitter(0.1)
|
|
332
|
+
equal(r.status, 200)
|
|
333
|
+
equal((await fetchState()).delayJitter, 0.1)
|
|
334
|
+
})
|
|
335
|
+
})
|
|
336
|
+
|
|
324
337
|
test('updates route delay', async () => {
|
|
325
338
|
const fx = new Fixture('route-delay.GET.200.json')
|
|
326
339
|
await fx.sync()
|