mockaton 10.2.0 → 10.2.1
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 +7 -0
- package/package.json +1 -1
- package/src/Api.js +14 -0
- package/src/ApiCommander.js +8 -1
- package/src/ApiConstants.js +3 -3
- package/src/Dashboard.css +5 -5
- package/src/Dashboard.js +20 -14
- package/src/MockBroker.js +9 -3
- package/src/MockDispatcher.js +1 -1
- package/src/utils/http-response.js +1 -1
- package/src/utils/logger.js +7 -7
package/README.md
CHANGED
|
@@ -754,6 +754,13 @@ const mockaton = new Commander(myMockatonAddr)
|
|
|
754
754
|
await mockaton.select('api/foo.200.GET.json')
|
|
755
755
|
```
|
|
756
756
|
|
|
757
|
+
### Toggle 500
|
|
758
|
+
Either selects the first found 500, which could be
|
|
759
|
+
the autogenerated one, or selects the default file.
|
|
760
|
+
```js
|
|
761
|
+
await mockaton.toggle500('GET', '/api/foo')
|
|
762
|
+
```
|
|
763
|
+
|
|
757
764
|
### Select all mocks that have a particular comment
|
|
758
765
|
```js
|
|
759
766
|
await mockaton.bulkSelectByComment('(demo-a)')
|
package/package.json
CHANGED
package/src/Api.js
CHANGED
|
@@ -38,6 +38,7 @@ export const apiPatchRequests = new Map([
|
|
|
38
38
|
[API.proxied, setRouteIsProxied],
|
|
39
39
|
[API.cookies, selectCookie],
|
|
40
40
|
[API.fallback, updateProxyFallback],
|
|
41
|
+
[API.toggle500, toggle500],
|
|
41
42
|
[API.bulkSelect, bulkUpdateBrokersByCommentTag],
|
|
42
43
|
[API.globalDelay, setGlobalDelay],
|
|
43
44
|
[API.collectProxied, setCollectProxied],
|
|
@@ -120,6 +121,19 @@ async function selectMock(req, response) {
|
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
123
|
|
|
124
|
+
async function toggle500(req, response) {
|
|
125
|
+
const body = await parseJSON(req)
|
|
126
|
+
const broker = mockBrokersCollection.brokerByRoute(
|
|
127
|
+
body[DF.routeMethod],
|
|
128
|
+
body[DF.routeUrlMask])
|
|
129
|
+
if (!broker)
|
|
130
|
+
sendUnprocessableContent(response, `Route does not exist: ${body[DF.routeMethod]} ${body[DF.routeUrlMask]}`)
|
|
131
|
+
else {
|
|
132
|
+
broker.toggle500()
|
|
133
|
+
sendOK(response)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
123
137
|
async function setRouteIsDelayed(req, response) {
|
|
124
138
|
const body = await parseJSON(req)
|
|
125
139
|
const delayed = body[DF.delayed]
|
package/src/ApiCommander.js
CHANGED
|
@@ -19,7 +19,7 @@ export class Commander {
|
|
|
19
19
|
getState() {
|
|
20
20
|
return fetch(this.#addr + API.state)
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
/** @returns {JsonPromise<number>} */
|
|
24
24
|
getSyncVersion(currentSyncVersion, abortSignal) {
|
|
25
25
|
return fetch(this.#addr + API.syncVersion, {
|
|
@@ -39,6 +39,13 @@ export class Commander {
|
|
|
39
39
|
return this.#patch(API.select, file)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
toggle500(routeMethod, routeUrlMask) {
|
|
43
|
+
return this.#patch(API.toggle500, {
|
|
44
|
+
[DF.routeMethod]: routeMethod,
|
|
45
|
+
[DF.routeUrlMask]: routeUrlMask,
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
42
49
|
bulkSelectByComment(comment) {
|
|
43
50
|
return this.#patch(API.bulkSelect, comment)
|
|
44
51
|
}
|
package/src/ApiConstants.js
CHANGED
|
@@ -16,6 +16,7 @@ export const API = {
|
|
|
16
16
|
staticStatus: MOUNT + '/static-status',
|
|
17
17
|
syncVersion: MOUNT + '/sync-version',
|
|
18
18
|
throws: MOUNT + '/throws',
|
|
19
|
+
toggle500: MOUNT + '/toggle500'
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export const DF = { // Dashboard Fields (XHR)
|
|
@@ -27,10 +28,9 @@ export const DF = { // Dashboard Fields (XHR)
|
|
|
27
28
|
syncVersion: 'last_received_sync_version'
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
export const
|
|
31
|
+
export const AUTOGENERATED_500_COMMENT = '(Mockaton 500)'
|
|
31
32
|
export const DEFAULT_MOCK_COMMENT = '(default)'
|
|
32
33
|
export const EXT_FOR_UNKNOWN_MIME = 'unknown'
|
|
33
34
|
export const LONG_POLL_SERVER_TIMEOUT = 8_000
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
export const HEADER_FOR_502 = 'mockaton502'
|
|
36
|
+
export const HEADER_FOR_502 = 'Mockaton502'
|
package/src/Dashboard.css
CHANGED
|
@@ -485,7 +485,6 @@ table {
|
|
|
485
485
|
}
|
|
486
486
|
|
|
487
487
|
.ProxyToggler {
|
|
488
|
-
padding: 1px 3px;
|
|
489
488
|
border: 1px solid var(--colorSecondaryActionBorder);
|
|
490
489
|
margin-right: 8px;
|
|
491
490
|
border-radius: var(--radius);
|
|
@@ -504,7 +503,7 @@ table {
|
|
|
504
503
|
path:last-of-type { /* inner cloud curve */
|
|
505
504
|
stroke: var(--colorBackground);
|
|
506
505
|
}
|
|
507
|
-
transform: scale(1.
|
|
506
|
+
transform: scale(1.1);
|
|
508
507
|
}
|
|
509
508
|
|
|
510
509
|
&:enabled:hover:not(:checked) ~ svg {
|
|
@@ -526,8 +525,9 @@ table {
|
|
|
526
525
|
}
|
|
527
526
|
|
|
528
527
|
> svg {
|
|
529
|
-
width:
|
|
530
|
-
height:
|
|
528
|
+
width: 22px;
|
|
529
|
+
height: 22px;
|
|
530
|
+
padding: 1px 3px;
|
|
531
531
|
stroke-width: 2px;
|
|
532
532
|
border-radius: var(--radius);
|
|
533
533
|
}
|
|
@@ -543,7 +543,7 @@ table {
|
|
|
543
543
|
> input {
|
|
544
544
|
appearance: none;
|
|
545
545
|
|
|
546
|
-
&:focus
|
|
546
|
+
&:focus {
|
|
547
547
|
outline: 0;
|
|
548
548
|
& ~ span {
|
|
549
549
|
outline: 2px solid var(--colorAccent)
|
package/src/Dashboard.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AUTOGENERATED_500_COMMENT, HEADER_FOR_502, DEFAULT_MOCK_COMMENT } from './ApiConstants.js'
|
|
2
2
|
import { parseFilename, extractComments } from './Filename.js'
|
|
3
3
|
import { Commander } from './ApiCommander.js'
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
const Strings = {
|
|
7
|
+
auto500: 'Auto500',
|
|
7
8
|
bulk_select: 'Bulk Select',
|
|
8
9
|
bulk_select_disabled_title: 'No mock files have comments, which are anything within parentheses on the filename.',
|
|
9
10
|
click_link_to_preview: 'Click a link to preview it',
|
|
@@ -89,7 +90,7 @@ const state = {
|
|
|
89
90
|
cookies: [],
|
|
90
91
|
comments: [],
|
|
91
92
|
delay: 0,
|
|
92
|
-
|
|
93
|
+
|
|
93
94
|
collectProxied: false,
|
|
94
95
|
proxyFallback: '',
|
|
95
96
|
get canProxy() {
|
|
@@ -229,7 +230,10 @@ function BulkSelector() {
|
|
|
229
230
|
const disabled = !comments.length
|
|
230
231
|
const list = disabled
|
|
231
232
|
? []
|
|
232
|
-
: [firstOption].
|
|
233
|
+
: [firstOption, ...comments].map(c => [
|
|
234
|
+
c,
|
|
235
|
+
c === AUTOGENERATED_500_COMMENT ? Strings.auto500 : c
|
|
236
|
+
])
|
|
233
237
|
return (
|
|
234
238
|
r('label', className(CSS.Field),
|
|
235
239
|
r('span', null, Strings.bulk_select),
|
|
@@ -240,8 +244,8 @@ function BulkSelector() {
|
|
|
240
244
|
disabled,
|
|
241
245
|
title: disabled ? Strings.bulk_select_disabled_title : '',
|
|
242
246
|
onChange
|
|
243
|
-
}, list.map(value =>
|
|
244
|
-
r('option', { value },
|
|
247
|
+
}, list.map(([value, name]) =>
|
|
248
|
+
r('option', { value }, name)))))
|
|
245
249
|
}
|
|
246
250
|
|
|
247
251
|
function GlobalDelayField() {
|
|
@@ -424,7 +428,7 @@ function MockSelector(broker) {
|
|
|
424
428
|
const { status, urlMask } = parseFilename(selected)
|
|
425
429
|
const files = broker.mocks.filter(item =>
|
|
426
430
|
status === 500 ||
|
|
427
|
-
!item.includes(
|
|
431
|
+
!item.includes(AUTOGENERATED_500_COMMENT))
|
|
428
432
|
if (!selected) {
|
|
429
433
|
selected = Strings.proxied
|
|
430
434
|
files.push(selected)
|
|
@@ -434,9 +438,14 @@ function MockSelector(broker) {
|
|
|
434
438
|
if (file === Strings.proxied)
|
|
435
439
|
return Strings.proxied
|
|
436
440
|
const { status, ext, method } = parseFilename(file)
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
441
|
+
const comments = extractComments(file)
|
|
442
|
+
const isAutogen500 = comments.includes(AUTOGENERATED_500_COMMENT)
|
|
443
|
+
return [
|
|
444
|
+
groupByMethod ? '' : method,
|
|
445
|
+
isAutogen500 ? '' : status,
|
|
446
|
+
ext === 'empty' || ext === 'unknown' ? '' : ext,
|
|
447
|
+
isAutogen500 ? Strings.auto500 : comments.join(' ')
|
|
448
|
+
].filter(Boolean).join(' ')
|
|
440
449
|
}
|
|
441
450
|
|
|
442
451
|
return (
|
|
@@ -474,11 +483,8 @@ function DelayRouteToggler(broker) {
|
|
|
474
483
|
/** @param {ClientMockBroker} broker */
|
|
475
484
|
function InternalServerErrorToggler(broker) {
|
|
476
485
|
function onChange() {
|
|
477
|
-
const {
|
|
478
|
-
mockaton.
|
|
479
|
-
this.checked
|
|
480
|
-
? broker.mocks.find(f => parseFilename(f).status === 500)
|
|
481
|
-
: broker.mocks[0])
|
|
486
|
+
const { method, urlMask } = parseFilename(broker.mocks[0])
|
|
487
|
+
mockaton.toggle500(method, urlMask)
|
|
482
488
|
.then(parseError)
|
|
483
489
|
.then(updateState)
|
|
484
490
|
.then(() => linkFor(method, urlMask)?.click())
|
package/src/MockBroker.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { includesComment, extractComments, parseFilename } from './Filename.js'
|
|
2
|
-
import {
|
|
2
|
+
import { AUTOGENERATED_500_COMMENT, DEFAULT_MOCK_COMMENT } from './ApiConstants.js'
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
/** MockBroker is a state for a particular route. It knows the available mock files
|
|
@@ -42,7 +42,7 @@ export class MockBroker {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
#isTemp500(file) {
|
|
45
|
-
return includesComment(file,
|
|
45
|
+
return includesComment(file, AUTOGENERATED_500_COMMENT)
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
#sortMocks() {
|
|
@@ -63,7 +63,7 @@ export class MockBroker {
|
|
|
63
63
|
#registerTemp500() {
|
|
64
64
|
const { urlMask, method } = parseFilename(this.mocks[0])
|
|
65
65
|
const file = urlMask.replace(/^\//, '') // Removes leading slash
|
|
66
|
-
this.mocks.push(`${file}${
|
|
66
|
+
this.mocks.push(`${file}${AUTOGENERATED_500_COMMENT}.${method}.500.empty`)
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
unregister(file) {
|
|
@@ -82,6 +82,12 @@ export class MockBroker {
|
|
|
82
82
|
selectFile(filename) {
|
|
83
83
|
this.currentMock.file = filename
|
|
84
84
|
}
|
|
85
|
+
|
|
86
|
+
toggle500() {
|
|
87
|
+
this.#is500(this.currentMock.file)
|
|
88
|
+
? this.selectDefaultFile()
|
|
89
|
+
: this.selectFile(this.mocks.find(this.#is500))
|
|
90
|
+
}
|
|
85
91
|
|
|
86
92
|
setDelayed(delayed) {
|
|
87
93
|
this.currentMock.delayed = delayed
|
package/src/MockDispatcher.js
CHANGED
|
@@ -19,7 +19,7 @@ export async function dispatchMock(req, response) {
|
|
|
19
19
|
broker = mockBrokerCollection.brokerByRoute('GET', req.url)
|
|
20
20
|
if (!broker || broker.proxied) {
|
|
21
21
|
if (config.proxyFallback)
|
|
22
|
-
await proxy(req, response,
|
|
22
|
+
await proxy(req, response, broker?.delayed ? calcDelay() : 0)
|
|
23
23
|
else
|
|
24
24
|
sendNotFound(response)
|
|
25
25
|
return
|
|
@@ -54,7 +54,7 @@ export function sendUnprocessableContent(response, error) {
|
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
export function sendInternalServerError(response, error) {
|
|
57
|
-
logger.error(500,
|
|
57
|
+
logger.error(500, response.req.url, error?.message || error, error?.stack || '')
|
|
58
58
|
response.statusCode = 500
|
|
59
59
|
response.end()
|
|
60
60
|
}
|
package/src/utils/logger.js
CHANGED
|
@@ -15,16 +15,16 @@ export const logger = new class {
|
|
|
15
15
|
|
|
16
16
|
accessMock(url, ...msg) {
|
|
17
17
|
if (this.#level !== 'quiet')
|
|
18
|
-
console.log(this.#msg('MOCK',
|
|
18
|
+
console.log(this.#msg('MOCK', url, ...msg))
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
access(response, error) {
|
|
21
|
+
access(response, error = '') {
|
|
22
22
|
if (this.#level === 'verbose')
|
|
23
23
|
console.log(this.#msg(
|
|
24
24
|
'ACCESS',
|
|
25
25
|
response.req.method,
|
|
26
26
|
response.statusCode,
|
|
27
|
-
|
|
27
|
+
response.req.url,
|
|
28
28
|
error))
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -39,20 +39,20 @@ export const logger = new class {
|
|
|
39
39
|
#msg(...msg) {
|
|
40
40
|
if (!msg.at(-1))
|
|
41
41
|
msg.pop()
|
|
42
|
-
return [new Date().toISOString(), ...msg].join('::')
|
|
42
|
+
return [new Date().toISOString(), ...msg.map(this.#sanitize)].join('::')
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
#sanitize(url) {
|
|
46
46
|
try {
|
|
47
47
|
const decoded = decode(url)
|
|
48
48
|
if (!decoded)
|
|
49
|
-
return '
|
|
49
|
+
return '__MULTI_ENCODED__'
|
|
50
50
|
return decoded
|
|
51
51
|
.replace(reControlAndDelChars, '')
|
|
52
52
|
.slice(0, 200)
|
|
53
53
|
}
|
|
54
54
|
catch {
|
|
55
|
-
return '
|
|
55
|
+
return '__NON_DECODABLE__'
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
}
|