mockaton 8.26.0 → 8.27.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 +31 -8
- package/index.js +1 -2
- package/mockup.svg +1037 -0
- package/package.json +4 -4
- package/src/Dashboard.css +28 -15
- package/src/Dashboard.js +105 -37
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "mockaton",
|
|
3
3
|
"description": "HTTP Mock Server",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "8.
|
|
5
|
+
"version": "8.27.0",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"types": "index.d.ts",
|
|
8
8
|
"license": "MIT",
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
"mockaton": "src/cli.js"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
|
-
"test": "node --test
|
|
22
|
-
"coverage": "node --test --test-reporter=lcov --test-reporter-destination=.coverage/lcov.info --experimental-test-coverage
|
|
21
|
+
"test": "node --test 'src/**/*.test.js'",
|
|
22
|
+
"coverage": "node --test --test-reporter=lcov --test-reporter-destination=.coverage/lcov.info --experimental-test-coverage 'src/**/*.test.js'",
|
|
23
23
|
"start": "node --watch src/cli.js",
|
|
24
|
-
"pixaton": "node --test --import=./pixaton-tests/_setup.js --experimental-test-isolation=none
|
|
24
|
+
"pixaton": "node --test --import=./pixaton-tests/_setup.js --experimental-test-isolation=none 'pixaton-tests/**/*.test.js'",
|
|
25
25
|
"outdated": "npm outdated --parseable | awk -F: '{ printf \"npm i %-30s ;# %s\\n\", $4, $2 }'"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
package/src/Dashboard.css
CHANGED
|
@@ -87,8 +87,8 @@ body {
|
|
|
87
87
|
box-sizing: border-box;
|
|
88
88
|
padding: 0;
|
|
89
89
|
border: 0;
|
|
90
|
-
font-family: inherit;
|
|
91
90
|
margin: 0;
|
|
91
|
+
font-family: inherit;
|
|
92
92
|
font-size: 100%;
|
|
93
93
|
outline: 0;
|
|
94
94
|
scrollbar-width: thin;
|
|
@@ -150,19 +150,20 @@ header {
|
|
|
150
150
|
align-items: flex-end;
|
|
151
151
|
gap: 16px 10px;
|
|
152
152
|
|
|
153
|
-
@media (max-width:
|
|
153
|
+
@media (max-width: 800px) {
|
|
154
154
|
max-width: 400px;
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
img {
|
|
159
|
-
width:
|
|
160
|
-
align-self:
|
|
159
|
+
width: 120px;
|
|
160
|
+
align-self: end;
|
|
161
161
|
margin-right: 22px;
|
|
162
|
+
margin-bottom: 5px;
|
|
162
163
|
}
|
|
163
164
|
|
|
164
165
|
.Field {
|
|
165
|
-
width:
|
|
166
|
+
width: 116px;
|
|
166
167
|
|
|
167
168
|
span {
|
|
168
169
|
display: flex;
|
|
@@ -219,7 +220,7 @@ header {
|
|
|
219
220
|
|
|
220
221
|
&.FallbackBackend {
|
|
221
222
|
position: relative;
|
|
222
|
-
width:
|
|
223
|
+
width: 160px;
|
|
223
224
|
|
|
224
225
|
.SaveProxiedCheckbox {
|
|
225
226
|
position: absolute;
|
|
@@ -258,19 +259,35 @@ header {
|
|
|
258
259
|
}
|
|
259
260
|
}
|
|
260
261
|
|
|
261
|
-
.
|
|
262
|
+
.MenuTrigger {
|
|
262
263
|
min-width: 24px;
|
|
263
264
|
align-self: end;
|
|
264
265
|
margin-left: auto;
|
|
265
266
|
fill: var(--colorSecondaryAction);
|
|
267
|
+
background: transparent;
|
|
266
268
|
|
|
267
269
|
&:hover {
|
|
268
270
|
fill: var(--colorAccent);
|
|
269
271
|
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
270
274
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
275
|
+
#Menu {
|
|
276
|
+
position: absolute;
|
|
277
|
+
top: 62px;
|
|
278
|
+
right: 10px;
|
|
279
|
+
left: auto;
|
|
280
|
+
padding: 20px;
|
|
281
|
+
border: 1px solid var(--colorSecondaryActionBorder);
|
|
282
|
+
border-radius: var(--radius);
|
|
283
|
+
box-shadow: var(--boxShadow1);
|
|
284
|
+
background: var(--colorHeaderBackground);
|
|
285
|
+
|
|
286
|
+
.GroupByMethod {
|
|
287
|
+
display: flex;
|
|
288
|
+
align-items: center;
|
|
289
|
+
margin-bottom: 12px;
|
|
290
|
+
gap: 4px;
|
|
274
291
|
}
|
|
275
292
|
}
|
|
276
293
|
|
|
@@ -280,11 +297,7 @@ main {
|
|
|
280
297
|
min-height: 0;
|
|
281
298
|
grid-template-columns: minmax(min-content, max-content) 1fr;
|
|
282
299
|
|
|
283
|
-
@media (max-width:
|
|
284
|
-
grid-template-columns: min(580px) 1fr;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
@media (max-width: 879px) {
|
|
300
|
+
@media (max-width: 800px) {
|
|
288
301
|
grid-template-columns: 100%;
|
|
289
302
|
grid-template-rows: 1fr 1fr;
|
|
290
303
|
}
|
package/src/Dashboard.js
CHANGED
|
@@ -12,11 +12,12 @@ const Strings = {
|
|
|
12
12
|
delay: 'Delay',
|
|
13
13
|
delay_ms: 'Delay (ms)',
|
|
14
14
|
empty_response_body: '/* Empty Response Body */',
|
|
15
|
-
fallback_server: 'Fallback
|
|
15
|
+
fallback_server: 'Fallback',
|
|
16
16
|
fallback_server_error: '⛔ Fallback Backend Error',
|
|
17
|
-
fallback_server_placeholder: 'Type
|
|
17
|
+
fallback_server_placeholder: 'Type Backend Address',
|
|
18
18
|
fetching: 'Fetching…',
|
|
19
19
|
got: 'Got',
|
|
20
|
+
group_by_method: 'Group by Method',
|
|
20
21
|
internal_server_error: 'Internal Server Error',
|
|
21
22
|
no_mocks_found: 'No mocks found',
|
|
22
23
|
not_found: 'Not Found',
|
|
@@ -37,8 +38,9 @@ const CSS = {
|
|
|
37
38
|
FallbackBackend: null,
|
|
38
39
|
Field: null,
|
|
39
40
|
GlobalDelayField: null,
|
|
40
|
-
|
|
41
|
+
GroupByMethod: null,
|
|
41
42
|
InternalServerErrorToggler: null,
|
|
43
|
+
MenuTrigger: null,
|
|
42
44
|
MockList: null,
|
|
43
45
|
MockSelector: null,
|
|
44
46
|
NotFoundToggler: null,
|
|
@@ -92,6 +94,8 @@ const state = {
|
|
|
92
94
|
|
|
93
95
|
fallbackAddress: '',
|
|
94
96
|
|
|
97
|
+
groupByMethod: true, // TODO read from localstorage
|
|
98
|
+
|
|
95
99
|
get canProxy() {
|
|
96
100
|
return Boolean(this.fallbackAddress)
|
|
97
101
|
}
|
|
@@ -129,6 +133,7 @@ const s = createSvgElement
|
|
|
129
133
|
function App() {
|
|
130
134
|
return [
|
|
131
135
|
r(Header),
|
|
136
|
+
r(Menu),
|
|
132
137
|
r('main', null,
|
|
133
138
|
r('div', className(CSS.leftSide),
|
|
134
139
|
r(MockList),
|
|
@@ -148,17 +153,42 @@ function Header() {
|
|
|
148
153
|
width: 160
|
|
149
154
|
}),
|
|
150
155
|
r('div', null,
|
|
156
|
+
r(GlobalDelayField),
|
|
151
157
|
r(CookieSelector),
|
|
152
158
|
r(BulkSelector),
|
|
153
|
-
r(GlobalDelayField),
|
|
154
159
|
r(ProxyFallbackField),
|
|
155
160
|
r(ResetButton)),
|
|
161
|
+
r('button', {
|
|
162
|
+
className: CSS.MenuTrigger,
|
|
163
|
+
popovertarget: 'Menu'
|
|
164
|
+
}, r(MenuIcon))
|
|
165
|
+
))
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function Menu() {
|
|
169
|
+
return (
|
|
170
|
+
r('menu', {
|
|
171
|
+
id: 'Menu',
|
|
172
|
+
popover: ''
|
|
173
|
+
},
|
|
174
|
+
r('label', className(CSS.GroupByMethod),
|
|
175
|
+
r('input', {
|
|
176
|
+
type: 'checkbox',
|
|
177
|
+
checked: state.groupByMethod,
|
|
178
|
+
onChange() {
|
|
179
|
+
state.groupByMethod = !state.groupByMethod
|
|
180
|
+
updateState()
|
|
181
|
+
// TODO localstorage
|
|
182
|
+
}
|
|
183
|
+
}),
|
|
184
|
+
r('span', null, Strings.group_by_method)),
|
|
185
|
+
|
|
156
186
|
r('a', {
|
|
157
|
-
className: CSS.Help,
|
|
158
187
|
href: 'https://github.com/ericfortis/mockaton',
|
|
159
188
|
target: '_blank',
|
|
160
189
|
rel: 'noopener noreferrer'
|
|
161
|
-
},
|
|
190
|
+
}, 'Documentation')
|
|
191
|
+
))
|
|
162
192
|
}
|
|
163
193
|
|
|
164
194
|
|
|
@@ -306,38 +336,69 @@ function ResetButton() {
|
|
|
306
336
|
/** # MockList */
|
|
307
337
|
|
|
308
338
|
function MockList() {
|
|
309
|
-
const { brokersByMethod } = state
|
|
339
|
+
const { brokersByMethod, groupByMethod } = state
|
|
310
340
|
if (!Object.keys(brokersByMethod).length)
|
|
311
341
|
return (
|
|
312
342
|
r('div', className(CSS.empty),
|
|
313
343
|
Strings.no_mocks_found))
|
|
344
|
+
|
|
345
|
+
if (groupByMethod)
|
|
346
|
+
return (
|
|
347
|
+
r('div', null,
|
|
348
|
+
r('table', null, Object.entries(brokersByMethod).map(([method, brokers]) =>
|
|
349
|
+
r(RowsByMethod, { method, brokers })))))
|
|
350
|
+
|
|
314
351
|
return (
|
|
315
352
|
r('div', null,
|
|
316
|
-
r('table', null,
|
|
317
|
-
r(
|
|
353
|
+
r('table', null,
|
|
354
|
+
r(RowsUngrouped))))
|
|
318
355
|
}
|
|
319
356
|
|
|
320
|
-
function
|
|
357
|
+
function RowsByMethod({ method, brokers }) {
|
|
321
358
|
const canProxy = state.canProxy
|
|
322
|
-
const
|
|
323
|
-
.filter(([, broker]) => broker.mocks.length > 1) // >1 because of autogen500
|
|
324
|
-
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
325
|
-
|
|
326
|
-
const urlMasks = brokersSorted.map(([urlMask]) => urlMask)
|
|
327
|
-
const urlMasksDittoed = dittoSplitPaths(urlMasks)
|
|
359
|
+
const rawRows = Object.entries(brokers).map(([urlMask, broker]) => [urlMask, broker, method])
|
|
328
360
|
return (
|
|
329
361
|
r('tbody', null,
|
|
330
362
|
r('tr', null,
|
|
331
363
|
r('th', { colspan: 2 + Number(canProxy) }),
|
|
332
364
|
r('th', null, method)),
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
365
|
+
Rows(rawRows)))
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function RowsUngrouped() {
|
|
369
|
+
const { brokersByMethod } = state
|
|
370
|
+
const rawRows = []
|
|
371
|
+
for (const [method, brokers] of Object.entries(brokersByMethod))
|
|
372
|
+
for (const [urlMask, broker] of Object.entries(brokers))
|
|
373
|
+
rawRows.push([urlMask, broker, method])
|
|
374
|
+
|
|
375
|
+
return r('tbody', null, Rows(rawRows))
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function Rows(rawRows) {
|
|
379
|
+
const sorted = rawRows
|
|
380
|
+
.filter(([, broker]) => broker.mocks.length > 1) // >1 because of autogen500
|
|
381
|
+
.sort(([aUrl], [bUrl]) => aUrl.localeCompare(bUrl))
|
|
382
|
+
const urlMasksDittoed = dittoSplitPaths(sorted.map(([urlMask]) => urlMask))
|
|
383
|
+
return sorted.map(([urlMask, broker, method], i) =>
|
|
384
|
+
r(Row, {
|
|
385
|
+
broker,
|
|
386
|
+
method,
|
|
387
|
+
urlMask,
|
|
388
|
+
urlMaskDittoed: urlMasksDittoed[i]
|
|
389
|
+
}))
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function Row({ method, urlMask, urlMaskDittoed, broker }) {
|
|
393
|
+
const canProxy = state.canProxy
|
|
394
|
+
return (
|
|
395
|
+
r('tr', { 'data-method': method, 'data-urlMask': urlMask },
|
|
396
|
+
canProxy && r('td', null, r(ProxyToggler, { broker })),
|
|
397
|
+
r('td', null, r(DelayRouteToggler, { broker })),
|
|
398
|
+
r('td', null, r(InternalServerErrorToggler, { broker })),
|
|
399
|
+
r('td', null, r(PreviewLink, { method, urlMask, urlMaskDittoed })),
|
|
400
|
+
r('td', null, r(MockSelector, { broker }))
|
|
401
|
+
))
|
|
341
402
|
}
|
|
342
403
|
|
|
343
404
|
function PreviewLink({ method, urlMask, urlMaskDittoed }) {
|
|
@@ -365,6 +426,8 @@ function PreviewLink({ method, urlMask, urlMaskDittoed }) {
|
|
|
365
426
|
|
|
366
427
|
/** @param {{ broker: ClientMockBroker }} props */
|
|
367
428
|
function MockSelector({ broker }) {
|
|
429
|
+
const { groupByMethod } = state
|
|
430
|
+
|
|
368
431
|
function onChange() {
|
|
369
432
|
const { urlMask, method } = parseFilename(this.value)
|
|
370
433
|
mockaton.select(this.value)
|
|
@@ -384,6 +447,15 @@ function MockSelector({ broker }) {
|
|
|
384
447
|
files.push(selected)
|
|
385
448
|
}
|
|
386
449
|
|
|
450
|
+
function nameFor(file) {
|
|
451
|
+
if (file === Strings.proxied)
|
|
452
|
+
return Strings.proxied
|
|
453
|
+
const { status, ext, method } = parseFilename(file)
|
|
454
|
+
return groupByMethod
|
|
455
|
+
? `${status} ${ext} ${extractComments(file).join(' ')}`
|
|
456
|
+
: `${method} ${status} ${ext} ${extractComments(file).join(' ')}`
|
|
457
|
+
}
|
|
458
|
+
|
|
387
459
|
return (
|
|
388
460
|
r('select', {
|
|
389
461
|
onChange,
|
|
@@ -394,15 +466,11 @@ function MockSelector({ broker }) {
|
|
|
394
466
|
CSS.MockSelector,
|
|
395
467
|
selected !== files[0] && CSS.nonDefault,
|
|
396
468
|
status >= 400 && status < 500 && CSS.status4xx)
|
|
397
|
-
}, files.map(file =>
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
selected: file === selected
|
|
403
|
-
}, `${status} ${ext} ${extractComments(file).join(' ')}`)
|
|
404
|
-
)
|
|
405
|
-
})))
|
|
469
|
+
}, files.map(file => (
|
|
470
|
+
r('option', {
|
|
471
|
+
value: file,
|
|
472
|
+
selected: file === selected
|
|
473
|
+
}, nameFor(file))))))
|
|
406
474
|
}
|
|
407
475
|
|
|
408
476
|
/** @param {{ broker: ClientMockBroker }} props */
|
|
@@ -710,10 +778,10 @@ function CloudIcon() {
|
|
|
710
778
|
s('path', { d: 'm6.1 9.1c2.8 0 5 2.3 5 5' })))
|
|
711
779
|
}
|
|
712
780
|
|
|
713
|
-
function
|
|
781
|
+
function MenuIcon() {
|
|
714
782
|
return (
|
|
715
783
|
s('svg', { viewBox: '0 0 24 24' },
|
|
716
|
-
s('path', { d: '
|
|
784
|
+
s('path', { d: 'M3 18h18v-2H3zm0-5h18v-2H3zm0-7v2h18V6z' })))
|
|
717
785
|
}
|
|
718
786
|
|
|
719
787
|
/**
|
|
@@ -878,7 +946,7 @@ function syntaxJSON(json) {
|
|
|
878
946
|
while ((match = syntaxJSON.regex.exec(json)) !== null) {
|
|
879
947
|
if (nNodes > MAX_NODES)
|
|
880
948
|
break
|
|
881
|
-
|
|
949
|
+
|
|
882
950
|
if (match.index > lastIndex)
|
|
883
951
|
text(json.slice(lastIndex, match.index))
|
|
884
952
|
|
|
@@ -926,7 +994,7 @@ function syntaxXML(xml) {
|
|
|
926
994
|
while ((match = syntaxXML.regex.exec(xml)) !== null) {
|
|
927
995
|
if (nNodes > MAX_NODES)
|
|
928
996
|
break
|
|
929
|
-
|
|
997
|
+
|
|
930
998
|
if (match.index > lastIndex)
|
|
931
999
|
text(xml.slice(lastIndex, match.index))
|
|
932
1000
|
|