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 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.vp761x740.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.vp761x740.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.vp761x740.dark.gold.png">
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
@@ -99,6 +99,7 @@ export interface State {
99
99
  comments: string[]
100
100
 
101
101
  delay: number
102
+ delayJitter: number
102
103
 
103
104
  collectProxied: boolean
104
105
  proxyFallback: string
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "mockaton",
3
3
  "description": "HTTP Mock Server",
4
4
  "type": "module",
5
- "version": "11.3.1",
5
+ "version": "11.4.0",
6
6
  "exports": {
7
7
  ".": {
8
8
  "import": "./index.js",
@@ -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',
@@ -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
- GlobalDelayField(),
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,
@@ -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: 760px) {
155
- > img {
156
- width: 100px;
157
- align-self: center;
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[type=number] {
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: 160px;
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 global delay value', async () => {
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()