mockaton 10.2.0 → 10.3.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
@@ -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
@@ -2,7 +2,7 @@
2
2
  "name": "mockaton",
3
3
  "description": "HTTP Mock Server",
4
4
  "type": "module",
5
- "version": "10.2.0",
5
+ "version": "10.3.0",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "license": "MIT",
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]
@@ -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
  }
@@ -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 DEFAULT_500_COMMENT = '(Mockaton 500)'
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.2);
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: 18px;
530
- height: 18px;
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-visible {
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 { DEFAULT_500_COMMENT, HEADER_FOR_502 } from './ApiConstants.js'
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].concat(comments)
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 }, 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(DEFAULT_500_COMMENT))
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
- return groupByMethod
438
- ? `${status} ${ext} ${extractComments(file).join(' ')}`
439
- : `${method} ${status} ${ext} ${extractComments(file).join(' ')}`
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 { urlMask, method } = parseFilename(broker.mocks[0])
478
- mockaton.select(
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 { DEFAULT_500_COMMENT, DEFAULT_MOCK_COMMENT } from './ApiConstants.js'
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, DEFAULT_500_COMMENT)
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}${DEFAULT_500_COMMENT}.${method}.500.empty`)
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
@@ -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, Number(broker?.delayed && calcDelay()))
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, logger.sanitizeURL(response.req.url), error?.message || error, error?.stack || '')
57
+ logger.error(500, response.req.url, error?.message || error, error?.stack || '')
58
58
  response.statusCode = 500
59
59
  response.end()
60
60
  }
@@ -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', this.sanitizeURL(url), ...msg))
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
- this.sanitizeURL(response.req.url),
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
- sanitizeURL(url) {
45
+ #sanitize(url) {
46
46
  try {
47
47
  const decoded = decode(url)
48
48
  if (!decoded)
49
- return '__MULTI_ENCODED_URL__'
49
+ return '__MULTI_ENCODED__'
50
50
  return decoded
51
51
  .replace(reControlAndDelChars, '')
52
52
  .slice(0, 200)
53
53
  }
54
54
  catch {
55
- return '__NON_DECODABLE_URL__'
55
+ return '__NON_DECODABLE__'
56
56
  }
57
57
  }
58
58
  }