mockaton 7.2.1 → 7.3.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.
Binary file
Binary file
package/README.md CHANGED
@@ -12,21 +12,41 @@ my-mocks-dir/api/user/[user-id].GET.200.json
12
12
  [This browser extension](https://github.com/ericfortis/devtools-ext-tar-http-requests)
13
13
  can be used for downloading a TAR of your XHR requests following that convention.
14
14
 
15
- ## Benefits
15
+
16
+ ## Getting Started Demo
17
+ Checkout this repo and run `npm run demo`, which will open the following
18
+ dashboard. Then, explore the [sample-mocks/](./sample-mocks) directory.
19
+
20
+ <picture>
21
+ <source media="(prefers-color-scheme: light)" srcset="./README-dashboard-light.png">
22
+ <source media="(prefers-color-scheme: dark)" srcset="./README-dashboard-dark.png">
23
+ <img alt="Mockaton Dashboard Demo" src="./README-dashboard-light.png" style="max-width: 860px">
24
+ </picture>
25
+
26
+ Then, pick a mock variant from the Mock dropdown (we’ll discuss
27
+ them later). At its right, note the _Delay_ toggler, and the button
28
+ for sending _500 - Internal Server Error_ on that endpoint.
29
+
30
+ Then edit a mock file. You don’t need to restart Mockaton for that, the
31
+ _Reset_ button is for registering newly added, removed, or renamed mocks.
32
+
33
+
34
+ ## Use Cases
35
+ - Test empty responses
36
+ - Test spinners by delaying responses
37
+ - Test errors such as _Bad Request_ and _Internal Server Error_
38
+ - Trigger notifications and alerts
39
+ - Prototyping before the backend API is developed
40
+ - Setting up tests
41
+ - As API documentation
42
+ - If you commit the mocks in the repo, when bisecting a bug, you don’t
43
+ have to sync the frontend with many backend repos
44
+ - Similarly, I can check out long-lived branches that have old API contracts
45
+
46
+ ## Motivation
16
47
  - Avoids having to spin up and maintain hefty or complex backends when developing UIs.
17
48
  - For a deterministic and comprehensive backend state. For example, having all the possible
18
- state variants of a particular collection helps for spotting inadvertent bugs. And having those
19
- assorted responses are not easy to trigger from the backend.
20
- - Testing empty responses.
21
- - Testing spinners by delaying responses.
22
- - Testing errors such as _Bad Request_ and _Internal Server Error_.
23
- - Triggering notifications and alerts.
24
- - Prototyping before the backend API is developed.
25
- - Setting up tests.
26
- - If you commit the mocks in the repo, when bisecting a bug, you don’t
27
- have to sync the frontend with many backend repos.
28
- - Similarly, I can check out long-lived branches that have old API contracts.
29
- - As API documentation.
49
+ state variants of a collection helps for spotting inadvertent bugs.
30
50
 
31
51
  ## Alternatives
32
52
  - Chrome DevTools allows for [overriding responses](https://developer.chrome.com/docs/devtools/overrides)
@@ -37,19 +57,6 @@ can be used for downloading a TAR of your XHR requests following that convention
37
57
  - Syncing the mocks, but the browser extension mentioned above helps.
38
58
 
39
59
 
40
- ## Getting Started
41
- The best way to learn _Mockaton_ is by checking out this repo and
42
- exploring its [sample-mocks/](./sample-mocks) directory. Then, run
43
- [`./_usage_example.js`](./_usage_example.js) and you’ll see the dashboard.
44
-
45
- You can select mock files without resetting Mockaton. The _Reset_
46
- button is for when you add, remove, or rename a mock file.
47
-
48
- The dropdown lets you pick a mock variant, details in the next section. Next to it is a
49
- _Delay_ toggler, and a button for sending _500 - Internal Server Error_ on that endpoint.
50
-
51
- <img src="./README-dashboard.png" style="max-width:820px"/>
52
-
53
60
  ## Basic Usage
54
61
  ```
55
62
  npm install mockaton
@@ -89,7 +96,7 @@ interface Config {
89
96
  extraHeaders?: []
90
97
 
91
98
  corsAllowed?: boolean, // Defaults to false
92
- // The options for customizing CORS are listed below
99
+ // cors* customization options are explained below
93
100
 
94
101
  onReady?: (dashboardUrl: string) => void // Defaults to trying to open macOS and Win default browser.
95
102
  }
@@ -342,9 +349,9 @@ await mockaton.setProxyFallback('http://example.com')
342
349
  Pass an empty string to disable it.
343
350
 
344
351
  ### Reset
345
- Re-initialize the collection. So if you added or removed mocks they
346
- will be considered. The selected mocks, cookies, and delays go
347
- back to default, but `Config.proxyFallback` is not affected.
352
+ Re-initialize the collection. So if you added or removed mocks they will
353
+ be considered. The selected mocks, cookies, and delays go back to default,
354
+ but `Config.proxyFallback` and `Config.corsAllowed` are not affected.
348
355
  ```js
349
356
  await mockaton.reset()
350
357
  ```
package/index.d.ts CHANGED
@@ -36,19 +36,29 @@ export function jwtCookie(cookieName: string, payload: any): string
36
36
  export class Commander {
37
37
  constructor(addr: string)
38
38
 
39
+ listMocks(): Promise<Response>
40
+
39
41
  select(file: string): Promise<Response>
40
42
 
41
43
  bulkSelectByComment(comment: string): Promise<Response>
42
44
 
45
+
43
46
  setRouteIsDelayed(routeMethod: string, routeUrlMask: string, delayed: boolean): Promise<Response>
44
47
 
48
+
49
+ listCookies(): Promise<Response>
50
+
45
51
  selectCookie(cookieKey: string): Promise<Response>
46
52
 
53
+
54
+ listComments(): Promise<Response>
55
+
47
56
  setProxyFallback(proxyAddr: string): Promise<Response>
48
57
 
49
58
  reset(): Promise<Response>
50
59
 
51
- listCookies(): Promise<Response>
52
60
 
53
- listComments(): Promise<Response>
61
+ getCorsAllowed(): Promise<Response>
62
+
63
+ setCorsAllowed(value: boolean): Promise<Response>
54
64
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "mockaton",
3
3
  "description": "A deterministic server-side for developing and testing frontend clients",
4
4
  "type": "module",
5
- "version": "7.2.1",
5
+ "version": "7.3.1",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "license": "MIT",
@@ -0,0 +1,3 @@
1
+ {
2
+ "msg": "Validation Error"
3
+ }
package/src/Api.js CHANGED
@@ -18,10 +18,12 @@ export const apiGetRequests = new Map([
18
18
  ['/Dashboard.js', serveDashboardAsset],
19
19
  ['/Dashboard.css', serveDashboardAsset],
20
20
  ['/ApiConstants.js', serveDashboardAsset],
21
+ ['/Commander.js', serveDashboardAsset],
21
22
  ['/mockaton-logo.svg', serveDashboardAsset],
22
23
  [API.mocks, listMockBrokers],
23
24
  [API.cookies, listCookies],
24
- [API.comments, listComments]
25
+ [API.comments, listComments],
26
+ [API.cors, getIsCorsAllowed]
25
27
  ])
26
28
 
27
29
  export const apiPatchRequests = new Map([
@@ -30,7 +32,8 @@ export const apiPatchRequests = new Map([
30
32
  [API.reset, reinitialize],
31
33
  [API.cookies, selectCookie],
32
34
  [API.fallback, updateProxyFallback],
33
- [API.bulkSelect, bulkUpdateBrokersByCommentTag]
35
+ [API.bulkSelect, bulkUpdateBrokersByCommentTag],
36
+ [API.cors, setCorsAllowed]
34
37
  ])
35
38
 
36
39
  function serveDashboard(_, response) { sendFile(response, join(import.meta.dirname, 'Dashboard.html')) }
@@ -39,6 +42,7 @@ function serveDashboardAsset(req, response) { sendFile(response, join(import.met
39
42
  function listCookies(_, response) { sendJSON(response, cookie.list()) }
40
43
  function listComments(_, response) { sendJSON(response, mockBrokersCollection.extractAllComments()) }
41
44
  function listMockBrokers(_, response) { sendJSON(response, mockBrokersCollection.getAll()) }
45
+ function getIsCorsAllowed(_, response) { sendJSON(response, Config.corsAllowed) }
42
46
 
43
47
 
44
48
  function reinitialize(_, response) {
@@ -113,3 +117,14 @@ async function bulkUpdateBrokersByCommentTag(req, response) {
113
117
  sendBadRequest(response, error)
114
118
  }
115
119
  }
120
+
121
+
122
+ async function setCorsAllowed(req, response) {
123
+ try {
124
+ Config.corsAllowed = await parseJSON(req)
125
+ sendOK(response)
126
+ }
127
+ catch (error) {
128
+ sendBadRequest(response, error)
129
+ }
130
+ }
@@ -8,7 +8,8 @@ export const API = {
8
8
  mocks: MOUNT + '/mocks',
9
9
  reset: MOUNT + '/reset',
10
10
  cookies: MOUNT + '/cookies',
11
- fallback: MOUNT + '/fallback'
11
+ fallback: MOUNT + '/fallback',
12
+ cors: MOUNT + '/cors'
12
13
  }
13
14
 
14
15
  export const DF = { // Dashboard Fields (XHR)
package/src/Commander.js CHANGED
@@ -7,6 +7,10 @@ export class Commander {
7
7
  this.#addr = addr
8
8
  }
9
9
 
10
+ listMocks() {
11
+ return this.#get(API.mocks)
12
+ }
13
+
10
14
  select(file) {
11
15
  return this.#patch(API.select, file)
12
16
  }
@@ -41,6 +45,13 @@ export class Commander {
41
45
  return this.#patch(API.reset)
42
46
  }
43
47
 
48
+ getCorsAllowed() {
49
+ return this.#get(API.cors)
50
+ }
51
+ setCorsAllowed(value) {
52
+ return this.#patch(API.cors, value)
53
+ }
54
+
44
55
 
45
56
  #get(api) {
46
57
  return fetch(this.#addr + api)
package/src/Config.js CHANGED
@@ -58,9 +58,6 @@ export function setup(options) {
58
58
 
59
59
  onReady: is(Function)
60
60
  })
61
-
62
- if (!Config.corsAllowed) // TESTME
63
- Config.corsOrigins = []
64
61
  }
65
62
 
66
63
 
package/src/Dashboard.css CHANGED
@@ -1,17 +1,48 @@
1
1
  :root {
2
- --colorAccent: #0069d0;
3
- --colorHover: #dfefff;
4
- --colorRed: #da0f00;
5
- --colorLightRed: #ffe4ee;
6
- --colorLightOrange: #ffedd1;
7
- --colorLightGrey: rgba(0, 0, 0, 0.02);
2
+ --boxShadow1: 0 2px 1px -1px rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 1px 3px 0 rgba(0, 0, 0, 0.12);
8
3
  }
4
+
5
+ @media (prefers-color-scheme: light) {
6
+ :root {
7
+ --color4xxBackground: #ffedd1;
8
+ --colorAccent: #0171dd;
9
+ --colorBackground: #fff;
10
+ --colorCodeBackground: #fafafa;
11
+ --colorComboBoxBackground: #fafafa;
12
+ --colorDisabled: #222;
13
+ --colorHover: #dfefff;
14
+ --colorLabel: #777;
15
+ --colorLightRed: #ffe4ee;
16
+ --colorRed: #da0f00;
17
+ --colorSecondaryButtonBackground: #f0f0f0;
18
+ --colorText: #000;
19
+ }
20
+ }
21
+ @media (prefers-color-scheme: dark) {
22
+ :root {
23
+ --color4xxBackground: #403630;
24
+ --colorAccent: #0682fa;
25
+ --colorBackground: #141414;
26
+ --colorCodeBackground: #333;
27
+ --colorComboBoxBackground: #252525;
28
+ --colorDisabled: #aaa;
29
+ --colorHover: #023661;
30
+ --colorLabel: #aaa;
31
+ --colorLightRed: #ffe4ee;
32
+ --colorRed: #f41606;
33
+ --colorSecondaryButtonBackground: #444;
34
+ --colorText: #fff;
35
+ }
36
+ }
37
+
9
38
  html, body {
10
39
  margin: 0;
11
40
  font-size: 12px;
12
41
  }
13
42
  body {
14
43
  padding: 16px;
44
+ background: var(--colorBackground);
45
+ color: var(--colorText);
15
46
  }
16
47
  * {
17
48
  padding: 0;
@@ -21,19 +52,24 @@ body {
21
52
  font-size: 100%;
22
53
  }
23
54
 
55
+ select {
56
+ background: var(--colorComboBoxBackground);
57
+ color: var(--colorText);
58
+ cursor: pointer;
59
+ border-radius: 4px;
60
+ outline: 0;
24
61
 
25
- fieldset {
26
- width: 120px;
27
- border: 1px solid #ccc;
28
-
29
- label {
30
- display: flex;
31
- align-items: center;
32
- padding: 4px 0;
33
-
34
- input {
35
- margin-right: 6px;
36
- }
62
+ &:enabled {
63
+ box-shadow: var(--boxShadow1);
64
+ }
65
+ &:enabled:hover {
66
+ cursor: pointer;
67
+ background: var(--colorHover);
68
+ }
69
+ &:disabled {
70
+ background: transparent;
71
+ cursor: not-allowed;
72
+ color: var(--colorDisabled);
37
73
  }
38
74
  }
39
75
 
@@ -61,26 +97,25 @@ menu {
61
97
  display: flex;
62
98
  align-items: flex-end;
63
99
  margin-bottom: 12px;
64
- gap: 14px;
100
+ gap: 16px;
65
101
 
66
102
  img {
67
- margin-right: 16px;
103
+ width: 140px;
104
+ margin-right: 24px;
68
105
  }
69
106
 
70
107
  label {
71
108
  span {
72
109
  display: block;
73
- color: #555;
110
+ padding-left: 7px;
111
+ color: var(--colorLabel);
74
112
  font-size: 11px;
75
113
  }
76
114
 
77
115
  select {
78
- width: 144px;
79
- padding: 3px 0;
80
- border: 1px solid #bbb;
81
- margin-top: 1px;
82
- cursor: pointer;
83
- border-radius: 4px;
116
+ width: 150px;
117
+ padding: 4px;
118
+ margin-top: 2px;
84
119
  font-size: 11px;
85
120
  }
86
121
  }
@@ -98,6 +133,13 @@ menu {
98
133
  color: white;
99
134
  }
100
135
  }
136
+
137
+ .CorsCheckbox {
138
+ display: flex;
139
+ align-items: center;
140
+ margin-bottom: 4px;
141
+ gap: 4px;
142
+ }
101
143
  }
102
144
 
103
145
  .PayloadViewer {
@@ -118,7 +160,7 @@ menu {
118
160
  max-height: calc(100vh - 160px);
119
161
  padding: 12px;
120
162
  margin-top: 6px;
121
- background: var(--colorLightGrey);
163
+ background: var(--colorCodeBackground);
122
164
  font-family: monospace;
123
165
  }
124
166
  }
@@ -147,23 +189,13 @@ menu {
147
189
  padding: 8px 1px;
148
190
  border: 0;
149
191
  border-radius: 4px;
150
- background: #eee;
151
192
  text-align: right;
152
193
  direction: rtl;
153
194
  text-overflow: ellipsis;
154
195
  font-size: 12px;
155
196
 
156
- &:disabled {
157
- background: transparent;
158
- color: #222;
159
- cursor: not-allowed
160
- }
161
- &:enabled:hover {
162
- cursor: pointer;
163
- background: var(--colorHover);
164
- }
165
197
  &.status4xx {
166
- background: var(--colorLightOrange);
198
+ background: var(--color4xxBackground);
167
199
  }
168
200
  }
169
201
 
@@ -176,23 +208,22 @@ menu {
176
208
  display: none;
177
209
 
178
210
  &:checked ~ svg {
179
- border-color: white;
180
- filter: invert();
211
+ background: var(--colorAccent);
212
+ fill: white;
181
213
  }
182
214
  }
183
215
 
184
216
  > svg {
185
- width: 14px;
186
- height: 14px;
187
- border: 1px solid #000;
217
+ width: 16px;
218
+ height: 16px;
188
219
  vertical-align: bottom;
189
- fill: #000;
220
+ fill: var(--colorText);
190
221
  border-radius: 50%;
191
- background: white;
222
+ background: var(--colorSecondaryButtonBackground);
192
223
 
193
224
  &:hover {
194
- background: #bce5ff;
195
- fill: #00318b;
225
+ background: var(--colorHover);
226
+ fill: var(--colorText);
196
227
  }
197
228
  }
198
229
  }
@@ -214,9 +245,9 @@ menu {
214
245
  > span {
215
246
  padding: 4px;
216
247
  font-size: 10px;
217
- color: #333;
248
+ color: var(--colorText);
218
249
  border-radius: 2px;
219
- background: white;
250
+ background: var(--colorSecondaryButtonBackground);
220
251
 
221
252
  &:hover {
222
253
  background: var(--colorLightRed);
@@ -1,12 +1,12 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en-US">
3
3
  <head>
4
- <link rel="stylesheet" href="../Dashboard.css">
5
- <link rel="icon" href="data:">
4
+ <link rel="stylesheet" href="/Dashboard.css">
5
+ <link rel="icon" href="data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='m235 33.7v202c0 9.19-5.81 14-17.4 14-11.6 0-17.4-4.83-17.4-14v-151c-0.115-4.49-6.72-5.88-8.46-0.87l-48.3 155c-2.22 7.01-7.72 10.1-16 9.9-3.63-0.191-7.01-1.14-9.66-2.89-2.89-1.72-4.83-4.34-5.57-7.72-11.1-37-22.6-74.3-34.1-111-4.34-14-8.95-31.4-14-48.3-1.82-4.83-8.16-5.32-8.46 1.16v156c0 9.19-5.81 14-17.4 14-11.6 0-17.4-4.83-17.4-14v-207c0-5.74 2.62-13.2 9.39-16.3 7.5-3.14 15-4.05 21.8-3.8 3.14 0 6.03 0.686 8.95 1.46 3.14 0.797 6.03 1.98 8.7 3.63 2.65 1.38 5.32 3.14 7.5 5.57 2.22 2.22 3.87 4.83 5.07 7.72l45.8 157c4.63-15.9 32.4-117 33.3-121 4.12-13.8 7.72-26.5 10.9-38.7 1.16-2.65 2.89-5.32 5.07-7.5 2.15-2.15 4.58-4.12 7.5-5.32 2.65-1.57 5.57-2.89 8.46-3.63 3.14-0.797 9.44-0.988 12.1-0.988 11.6 1.07 29.4 9.14 29.4 27z' fill='%23808080'/%3E%3C/svg%3E">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
7
7
  <title>Mock Server</title>
8
8
  </head>
9
9
  <body>
10
- <script src="../Dashboard.js" type="module"></script>
10
+ <script src="/Dashboard.js" type="module"></script>
11
11
  </body>
12
12
  </html>
package/src/Dashboard.js CHANGED
@@ -1,8 +1,10 @@
1
- import { parseFilename } from '../Filename.js'
2
- import { API, DF, DEFAULT_500_COMMENT } from '../ApiConstants.js'
1
+ import { parseFilename } from '/Filename.js'
2
+ import { Commander } from '/Commander.js'
3
+ import { DEFAULT_500_COMMENT } from '/ApiConstants.js'
3
4
 
4
5
 
5
6
  const Strings = {
7
+ allow_cors: 'Allow CORS',
6
8
  bulk_select_by_comment: 'Bulk Select by Comment',
7
9
  click_link_to_preview: 'Click a link to preview it',
8
10
  cookie: 'Cookie',
@@ -17,6 +19,7 @@ const Strings = {
17
19
  }
18
20
 
19
21
  const CSS = {
22
+ CorsCheckbox: 'CorsCheckbox',
20
23
  DelayToggler: 'DelayToggler',
21
24
  InternalServerErrorToggler: 'InternalServerErrorToggler',
22
25
  MockSelector: 'MockSelector',
@@ -32,24 +35,27 @@ const r = createElement
32
35
  const refPayloadViewer = useRef()
33
36
  const refPayloadFile = useRef()
34
37
 
38
+ const mockaton = new Commander(window.location.origin)
39
+
35
40
  function init() {
36
41
  Promise.all([
37
- API.mocks,
38
- API.cookies,
39
- API.comments
40
- ].map(api => fetch(api).then(res => res.ok && res.json())))
42
+ mockaton.listMocks(),
43
+ mockaton.listCookies(),
44
+ mockaton.listComments(),
45
+ mockaton.getCorsAllowed()
46
+ ].map(api => api.then(response => response.ok && response.json())))
41
47
  .then(App)
42
48
  .catch(console.error)
43
49
  }
44
50
  init()
45
51
 
46
- function App([brokersByMethod, cookies, comments]) {
52
+ function App([brokersByMethod, cookies, comments, corsAllowed]) {
47
53
  empty(document.body)
48
54
  createRoot(document.body).render(
49
- DevPanel(brokersByMethod, cookies, comments))
55
+ DevPanel(brokersByMethod, cookies, comments, corsAllowed))
50
56
  }
51
57
 
52
- function DevPanel(brokersByMethod, cookies, comments) {
58
+ function DevPanel(brokersByMethod, cookies, comments, corsAllowed) {
53
59
  document.title = Strings.title
54
60
  return (
55
61
  r('div', null,
@@ -57,6 +63,7 @@ function DevPanel(brokersByMethod, cookies, comments) {
57
63
  r('img', { src: 'mockaton-logo.svg', width: 160 }),
58
64
  r(CookieSelector, { list: cookies }),
59
65
  r(BulkSelector, { comments }),
66
+ r(CorsCheckbox, { corsAllowed }),
60
67
  r(ResetButton)),
61
68
  r('main', null,
62
69
  r('table', null, Object.entries(brokersByMethod).map(([method, brokers]) =>
@@ -66,19 +73,6 @@ function DevPanel(brokersByMethod, cookies, comments) {
66
73
  r('pre', { ref: refPayloadViewer }, Strings.click_link_to_preview)))))
67
74
  }
68
75
 
69
-
70
- function ResetButton() {
71
- return (
72
- r('button', {
73
- onClick() {
74
- fetch(API.reset, { method: 'PATCH' })
75
- .then(init)
76
- .catch(console.error)
77
- }
78
- }, Strings.reset)
79
- )
80
- }
81
-
82
76
  function CookieSelector({ list }) {
83
77
  return (
84
78
  r('label', null,
@@ -87,10 +81,7 @@ function CookieSelector({ list }) {
87
81
  autocomplete: 'off',
88
82
  disabled: list.length <= 1,
89
83
  onChange() {
90
- fetch(API.cookies, {
91
- method: 'PATCH',
92
- body: JSON.stringify(this.value)
93
- })
84
+ mockaton.selectCookie(this.value)
94
85
  .catch(console.error)
95
86
  }
96
87
  }, list.map(([key, selected]) =>
@@ -100,7 +91,6 @@ function CookieSelector({ list }) {
100
91
  }, key)))))
101
92
  }
102
93
 
103
-
104
94
  function BulkSelector({ comments }) {
105
95
  return (
106
96
  r('label', null,
@@ -109,10 +99,7 @@ function BulkSelector({ comments }) {
109
99
  autocomplete: 'off',
110
100
  disabled: comments.length <= 1,
111
101
  onChange() {
112
- fetch(API.bulkSelect, {
113
- method: 'PATCH',
114
- body: JSON.stringify(this.value)
115
- })
102
+ mockaton.bulkSelectByComment(this.value)
116
103
  .then(init)
117
104
  .catch(console.error)
118
105
  }
@@ -122,6 +109,33 @@ function BulkSelector({ comments }) {
122
109
  }, item)))))
123
110
  }
124
111
 
112
+ function CorsCheckbox({ corsAllowed }) {
113
+ return (
114
+ r('label', { className: CSS.CorsCheckbox },
115
+ r('input', {
116
+ type: 'checkbox',
117
+ checked: corsAllowed,
118
+ onChange(event) {
119
+ mockaton.setCorsAllowed(event.currentTarget.checked)
120
+ .catch(console.error)
121
+ }
122
+ }),
123
+ Strings.allow_cors))
124
+ }
125
+
126
+ function ResetButton() {
127
+ return (
128
+ r('button', {
129
+ onClick() {
130
+ mockaton.reset()
131
+ .then(init)
132
+ .catch(console.error)
133
+ }
134
+ }, Strings.reset)
135
+ )
136
+ }
137
+
138
+
125
139
 
126
140
  function SectionByMethod({ method, brokers }) {
127
141
  return (
@@ -188,10 +202,7 @@ function MockSelector({ broker }) {
188
202
  this.style.fontWeight = this.value === this.options[0].value // default is selected
189
203
  ? 'normal'
190
204
  : 'bold'
191
- fetch(API.select, {
192
- method: 'PATCH',
193
- body: JSON.stringify(this.value)
194
- })
205
+ mockaton.select(this.value)
195
206
  .then(() => {
196
207
  this.closest('tr').querySelector('a').click()
197
208
  this.closest('tr').querySelector(`.${CSS.InternalServerErrorToggler}>[type=checkbox]`).checked = status === 500
@@ -220,14 +231,8 @@ function DelayRouteToggler({ broker }) {
220
231
  checked,
221
232
  onChange(event) {
222
233
  const { method, urlMask } = parseFilename(this.name)
223
- fetch(API.delay, {
224
- method: 'PATCH',
225
- body: JSON.stringify({
226
- [DF.routeMethod]: method,
227
- [DF.routeUrlMask]: urlMask,
228
- [DF.delayed]: event.currentTarget.checked
229
- })
230
- })
234
+ mockaton.setRouteIsDelayed(method, urlMask, event.currentTarget.checked)
235
+ .catch(console.error)
231
236
  }
232
237
  }),
233
238
  TimerIcon()))
@@ -254,12 +259,9 @@ function InternalServerErrorToggler({ broker }) {
254
259
  name,
255
260
  checked,
256
261
  onChange(event) {
257
- fetch(API.select, {
258
- method: 'PATCH',
259
- body: JSON.stringify(event.currentTarget.checked
260
- ? items.find(f => parseFilename(f).status === 500)
261
- : items[0])
262
- })
262
+ mockaton.select(event.currentTarget.checked
263
+ ? items.find(f => parseFilename(f).status === 500)
264
+ : items[0])
263
265
  .then(init)
264
266
  .catch(console.error)
265
267
  }
@@ -157,7 +157,6 @@ const server = Mockaton({
157
157
  extraMimes: {
158
158
  my_custom_extension: 'my_custom_mime'
159
159
  },
160
- corsAllowed: true,
161
160
  corsOrigins: ['http://example.com']
162
161
  })
163
162
  server.on('listening', runTests)
@@ -224,11 +223,11 @@ async function runTests() {
224
223
  await testMockDispatching(...fixtureCustomMime, 'my_custom_mime')
225
224
  await testJsFunctionMocks()
226
225
 
227
- await testCorsAllowed()
228
226
  await testItUpdatesUserRole()
229
227
  await testStaticFileServing()
230
228
  await testInvalidFilenamesAreIgnored()
231
229
  await testEnableFallbackSoRoutesWithoutMocksGetRelayed()
230
+ await testCorsAllowed()
232
231
 
233
232
  server.close()
234
233
  }
@@ -438,9 +437,9 @@ async function testEnableFallbackSoRoutesWithoutMocksGetRelayed() {
438
437
  })
439
438
  }
440
439
 
441
- // TODO make API for changing CORS? so we can automate testing?
442
440
  async function testCorsAllowed() {
443
441
  await it('cors', async () => {
442
+ await commander.setCorsAllowed(true)
444
443
  const res = await request('/does-not-matter', {
445
444
  method: 'OPTIONS',
446
445
  headers: {
@@ -1,4 +1,12 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <svg version="1.1" viewBox="0 0 570 100" xmlns="http://www.w3.org/2000/svg">
3
- <path d="m77 0.27c2.7 0 6 1.3 9.1 2.6 2.9 1.1 4.2 3.3 4.2 6.5v84c0 3.8-2.4 5.8-7.2 5.8s-7.2-2-7.2-5.8v-63l-3.5-0.36-20 64c-0.92 2.9-3.2 4.2-6.6 4.1-1.5-0.079-2.9-0.47-4-1.2-1.2-0.71-2-1.8-2.3-3.2l-8.8-29-5.3-17c-1.8-5.8-3.7-13-5.8-20l-3.5 0.48v63c0 3.8-2.4 5.8-7.2 5.8s-7.2-2-7.2-5.8v-84c0-3.1 1.4-5.2 4.2-6.5 3.1-1.3 5.9-1.8 8.7-1.7 1.3 0 2.5 0.16 3.7 0.48 1.3 0.33 2.5 0.82 3.6 1.5 1.1 0.57 2.2 1.3 3.1 2.3 0.92 0.92 1.6 2 2.1 3.2l19 65c1.4-4.8 2.9-9.9 4.4-16 1.6-5.9 3.2-11 4.7-17 1.6-5.9 3.2-11 4.7-17 1.7-5.7 3.2-11 4.5-16 0.48-1.1 1.2-2.2 2.1-3.1 0.89-0.89 1.9-1.7 3.1-2.2 1.1-0.65 2.3-1.2 3.5-1.5 1.3-0.33 2.6-0.48 3.7-0.48m35 30h-0.12c2.1-1.4 4.2-2.6 6.5-3.5 2.3-0.89 4.5-1.4 6.6-1.4h20c2.1 0 4.2 0.46 6.5 1.4 2.3 0.92 4.5 2.1 6.6 3.5h-0.12c2.1 1.5 3.7 3.5 4.8 6.1 1.1 2.5 1.7 5.3 1.7 8.6v35c0 6.6-2.2 12-6.6 15-4.3 3.1-8.6 4.6-13 4.6h-20c-2.1 0-4.2-0.36-6.5-1.1-2.3-0.72-4.4-1.9-6.5-3.5-4.4-3.1-6.6-8-6.6-15v-35c0-3.3 0.56-6.1 1.7-8.6 1.1-2.5 2.8-4.5 4.8-6.1m31 57c3.1 0 5.1-0.86 6.3-2.6 1.3-1.7 2-3.5 2-5.5v-35c0-2.1-0.66-3.8-2-5.5-1.3-1.7-3.4-2.6-6.3-2.6h-15c-3.1 0-5.2 0.86-6.5 2.6-1.3 1.7-1.9 3.5-1.9 5.5v35c0 2 0.62 3.8 1.9 5.5 1.3 1.7 3.5 2.6 6.5 2.6zm96-7.9c0 6.6-2.2 12-6.6 15-4.3 3.1-8.6 4.6-13 4.6h-21c-4.3 0-8.6-1.6-13-4.6-2-1.7-3.5-3.6-4.5-6.1s-1.6-5.4-1.6-8.7v-35c0-6.6 2.1-12 6.1-15 2.1-1.5 4.1-2.6 6.2-3.5 2.2-0.92 4.2-1.4 6.3-1.4h21c2 0 4.1 0.39 6.5 1.2 2.4 0.72 4.5 1.8 6.6 3.1 2 1.4 3.5 3.3 4.6 5.7 1.3 2.5 1.9 5.3 1.9 8.7v6.1c0 3.8-2.3 5.8-6.7 5.8-4.4 0-6.7-2-6.7-5.8v-5.2c0-2.1-0.66-3.8-2-5.5-1.3-1.7-3.4-2.6-6.3-2.6h-15c-3.1 0-5.2 0.86-6.5 2.6-1.3 1.7-1.9 3.5-1.9 5.5v35c0 2 0.62 3.8 1.9 5.5 1.3 1.7 3.5 2.6 6.5 2.6h15c3.1 0 5.1-0.86 6.3-2.6 1.3-1.7 2-3.5 2-5.5v-5.6c0-3.8 2.3-5.7 6.7-5.7 4.4 0 6.7 1.9 6.7 5.7zm57-53v0.12c1.5-1.7 3-2.6 4.4-2.6 0.79 0 1.6 0.21 2.3 0.61 0.79 0.33 1.7 0.82 2.6 1.5h-0.12c2 1.7 3 3.3 3 4.8 0 0.57-0.12 1.2-0.36 2-0.25 0.65-0.64 1.2-1.2 1.7l-38 44v16c0 3.8-2.3 5.7-6.7 5.7-4.4 0-6.7-1.9-6.7-5.7v-87c0-3.8 2.3-5.8 6.7-5.8 4.4 0 6.7 2 6.7 5.8v51c2.1-2.5 4.2-5 6.7-7.8 2.5-2.9 4.9-5.7 7.4-8.6 2.5-3 4.9-5.8 7.4-8.6 2.5-2.9 4.7-5.4 6.8-7.9m12 64c0.57 1.1 0.86 2.2 0.86 3.3 0 2.1-1.2 3.6-3.6 4.7-1.7 0.99-3.2 1.5-4.4 1.5-0.92 0-1.8-0.33-2.6-0.98-0.79-0.57-1.5-1.3-2-2.2l-12-24c-0.72-1.3-1.1-2.5-1.1-3.6 0-2.1 1.1-3.7 3.2-5.1 0.57-0.4 1.1-0.77 1.7-1.1 0.65-0.33 1.4-0.56 2.1-0.73 0.92-0.17 1.8-0.0033 2.6 0.48 0.79 0.48 1.5 1.2 2.1 2zm30 8.2c-2.5 0-4.9-0.33-7.2-0.98-2.3-0.72-4.5-1.8-6.6-3.1v0.12c-4-2.5-6-7.1-6-14v-6c0-3.4 0.56-6.2 1.7-8.7 1.3-2.5 3-4.5 5-6h-0.12c2.1-1.4 4.2-2.4 6.5-3.1 2.3-0.72 4.5-1.1 6.6-1.1h27v-11c0-2.1-0.66-3.8-2-5.5-1.3-1.7-3.4-2.6-6.3-2.6h-14c-3.1 0-5.2 0.76-6.5 2.3-1.1 1.5-1.7 3.2-1.7 5.2v0.98c0 4.2-2.3 6.3-6.8 6.3-4.5 0-6.8-2.1-6.8-6.3v-1.1c0-3.4 0.56-6.1 1.7-8.4 1.3-2.3 2.9-4.2 4.8-5.7h-0.12c2.1-1.4 4.3-2.6 6.6-3.5 2.4-0.92 4.6-1.4 6.7-1.4h19c2.1 0 4.2 0.46 6.5 1.4 2.4 0.92 4.5 2.1 6.6 3.5h-0.12c2.1 1.5 3.7 3.5 4.8 6.1 1.1 2.5 1.7 5.3 1.7 8.6v49c0 3.8-2.3 5.8-6.7 5.8-0.92 0-1.8-0.04-2.6-0.12-0.72-0.079-1.4-0.29-2.1-0.61-0.57-0.4-1.1-0.94-1.5-1.6-0.33-0.72-0.48-1.7-0.48-2.8l-0.12-27h-25c-1.8 0-3.2 0.21-4.1 0.61s-1.8 1.1-2.3 2c-0.65 1.4-1.2 2.5-1.5 3.3-0.25 0.72-0.36 1.6-0.36 2.6v4.7c0 2.1 0.62 3.7 1.9 4.8 1.3 1.1 3.5 1.6 6.6 1.6h14c3.1 0 4.5 1.9 4.5 5.7 0 1.7-0.36 3.1-1.1 4.1-0.72 1.1-1.9 1.6-3.5 1.6zm72-62v44c0 2.1 0.46 3.7 1.4 4.8 0.92 1.1 2.9 1.7 5.7 1.7h3.2c3.2 0 4.6 1.9 4.5 5.6 0 3.8-1.5 5.7-4.5 5.7h-4c-2.7 0-5-0.33-7.3-0.98-2.3-0.72-4.5-1.8-6.6-3.1v0.12c-4-2.7-6-7.2-6-14v-44h-4.7c-3 0-4.5-1.9-4.6-5.7 0-3.8 1.6-5.7 4.6-5.7h4.7v-13c0-3.8 2.3-5.8 6.9-5.8 4.4 0 6.7 2 6.7 5.8v13h9.9c3.2 0 4.6 1.9 4.5 5.7 0 3.8-1.5 5.7-4.5 5.7zm32-7h-0.12c2.1-1.4 4.2-2.6 6.5-3.5 2.3-0.89 4.5-1.4 6.6-1.4h20c2.1 0 4.2 0.46 6.5 1.4 2.3 0.92 4.5 2.1 6.6 3.5h-0.12c2.1 1.5 3.7 3.5 4.8 6.1 1.1 2.5 1.7 5.3 1.7 8.6v35c0 6.6-2.2 12-6.6 15-4.3 3.1-8.6 4.6-13 4.6h-20c-2.1 0-4.2-0.36-6.5-1.1-2.3-0.72-4.4-1.9-6.5-3.5-4.4-3.1-6.6-8-6.6-15v-35c0-3.3 0.56-6.1 1.7-8.6 1.1-2.5 2.8-4.5 4.8-6.1m31 57c3.1 0 5.1-0.86 6.3-2.6 1.3-1.7 2-3.5 2-5.5v-35c0-2.1-0.66-3.8-2-5.5-1.3-1.7-3.4-2.6-6.3-2.6h-15c-3.1 0-5.2 0.86-6.5 2.6-1.3 1.7-1.9 3.5-1.9 5.5v35c0 2 0.62 3.8 1.9 5.5 1.3 1.7 3.5 2.6 6.5 2.6zm80-48 0.12 0.12c-1.1-2-3.3-3-6.5-3h-15c-3.4 0-5.5 0.99-6.6 3-1.1 1.7-1.7 3.7-1.7 6l-0.32 48c0 3.8-2.3 5.8-6.7 5.8-4.4 0-6.7-2-6.7-5.8v-49c0-3.4 0.52-6.2 1.6-8.7 1.1-2.5 2.8-4.4 5-6 4.3-3.1 8.6-4.6 13-4.6h20c4.1 0 8.4 1.6 13 4.6 4.4 3.1 6.6 8 6.6 15v49c0 3.8-2.3 5.8-6.7 5.8s-6.7-2-6.7-5.8v-48c0-2.1-0.66-4.1-2-6.1" aria-label="Mockaton"/>
3
+ <style>
4
+ :root { --color: #000000; }
5
+ @media (prefers-color-scheme: light) { :root { --color: #000000 } }
6
+ @media (prefers-color-scheme: dark) { :root { --color: #fff } }
7
+ path { fill: var(--color) }
8
+ </style>
9
+ <path
10
+ d="m88.6 11.5v82.2c0 3.75-2.37 5.72-7.1 5.72s-7.1-1.97-7.1-5.72v-61.5c-0.0468-1.83-2.74-2.4-3.45-0.355l-19.7 63.1c-0.907 2.86-3.15 4.14-6.51 4.04-1.48-0.0779-2.86-0.463-3.94-1.18-1.18-0.7-1.97-1.77-2.27-3.15-4.54-15.1-9.2-30.3-13.9-45.4-1.77-5.72-3.65-12.8-5.72-19.7-0.741-1.97-3.33-2.17-3.45 0.473v63.6c0 3.75-2.37 5.72-7.1 5.72-4.73 0-7.1-1.97-7.1-5.72v-84.3c0-2.34 1.07-5.37 3.83-6.65 3.06-1.28 6.12-1.65 8.88-1.55 1.28 0 2.46 0.28 3.65 0.596 1.28 0.325 2.46 0.808 3.55 1.48 1.08 0.562 2.17 1.28 3.06 2.27 0.907 0.907 1.58 1.97 2.07 3.15l18.7 64.1c1.89-6.49 13.2-47.7 13.6-49.3 1.68-5.62 3.15-10.8 4.44-15.8 0.473-1.08 1.18-2.17 2.07-3.06 0.877-0.877 1.87-1.68 3.06-2.17 1.08-0.641 2.27-1.18 3.45-1.48 1.28-0.325 3.85-0.403 4.94-0.403 4.75 0.438 12 3.73 12 11zm21.1 18.6c2.07-1.38 4.14-2.56 6.41-3.45 2.27-0.877 4.44-1.38 6.51-1.38h19.7c2.07 0 4.14 0.454 6.41 1.38 2.27 0.907 4.44 2.07 6.45 3.5 2.01 1.43 3.59 3.4 4.67 5.96 1.08 2.46 1.68 5.23 1.68 8.48v34.5c0 6.51-2.17 11.8-6.51 14.8-4.24 3.06-8.48 4.54-12.8 4.54h-19.7c-2.07 0-4.14-0.355-6.41-1.08-2.27-0.71-4.34-1.87-6.41-3.45-4.34-3.06-6.51-7.89-6.51-14.8v-34.5c0-3.25 0.552-6.01 1.68-8.48 1.08-2.46 2.76-4.44 4.85-6.01zm30.4 56.2c3.06 0 5.03-0.848 6.21-2.56 1.28-1.68 1.97-3.45 1.97-5.42v-34.5c0-2.07-0.651-3.75-1.97-5.42-1.28-1.68-3.35-2.56-6.21-2.56h-14.8c-3.06 0-5.13 0.848-6.41 2.56-1.28 1.68-1.87 3.45-1.87 5.42v34.5c0 1.97 0.611 3.75 1.87 5.42 1.28 1.68 3.45 2.56 6.41 2.56zm94.6-7.79c0 6.51-2.17 11.8-6.51 14.8-4.24 3.06-8.48 4.54-12.8 4.54h-20.7c-4.24 0-8.48-1.58-12.8-4.54-1.97-1.68-3.45-3.55-4.44-6.01-0.986-2.46-1.58-5.32-1.58-8.58v-34.5c0-6.51 2.07-11.8 6.01-14.8 2.07-1.48 4.04-2.56 6.11-3.45 2.17-0.907 4.14-1.38 6.21-1.38h20.7c1.97 0 4.04 0.384 6.41 1.18 2.37 0.71 4.44 1.77 6.51 3.06 1.97 1.38 3.45 3.25 4.54 5.62 1.28 2.46 1.87 5.23 1.87 8.58v6.01c0 3.75-2.27 5.72-6.61 5.72s-6.61-1.97-6.61-5.72v-5.13c0-2.07-0.651-3.75-1.97-5.42-1.28-1.68-3.35-2.56-6.21-2.56h-14.8c-3.06 0-5.13 0.848-6.41 2.56-1.28 1.68-1.87 3.45-1.87 5.42v34.5c0 1.97 0.611 3.75 1.87 5.42 1.28 1.68 3.45 2.56 6.41 2.56h14.8c3.06 0 5.03-0.848 6.21-2.56 1.28-1.68 1.97-3.45 1.97-5.42v-5.52c0-3.75 2.27-5.62 6.61-5.62s6.61 1.87 6.61 5.62zm60.5-54.7c0.779 0 1.58 0.207 2.27 0.601 0.779 0.325 1.68 0.808 3.05 1.98s2.36 2.75 2.36 4.23c0 0.562-0.118 1.18-0.355 1.97-0.246 0.641-0.631 1.18-1.18 1.68l-37.5 43.4v15.8c0 3.75-2.27 5.62-6.61 5.62s-6.61-1.87-6.61-5.62v-85.8c0-3.75 2.27-5.72 6.61-5.72s6.61 1.97 6.61 5.72v50.3c2.07-2.46 4.14-4.93 6.61-7.69 2.46-2.86 4.83-5.62 7.3-8.48 2.46-2.96 4.83-5.72 7.3-8.48 2.46-2.86 4.63-5.32 6.62-7.8 0.656-0.789 2.13-1.68 3.51-1.68zm8.4 64.8c0.562 1.08 0.848 2.17 0.848 3.25 0 2.07-1.18 3.55-3.55 4.63-1.68 0.976-3.15 1.48-4.34 1.48-0.907 0-1.77-0.325-2.56-0.966-0.779-0.562-1.48-1.28-1.97-2.17l-11.8-23.7c-0.71-1.28-1.08-2.46-1.08-3.55 0-2.07 1.08-3.65 3.15-5.03 0.562-0.394 1.08-0.759 1.68-1.08 0.641-0.325 1.38-0.552 2.07-0.72 0.907-0.168 1.77-0.0033 2.56 0.473 0.779 0.473 1.48 1.18 2.07 1.97zm29.6 8.08c-2.46 0-4.83-0.325-7.1-0.966-2.27-0.71-4.44-1.77-7.44-3.59-3.01-1.81-4.98-6.35-4.98-13.2v-5.92c0-3.35 0.552-6.11 1.68-8.58 1.28-2.46 2.96-4.44 4.92-5.87 1.96-1.43 4.03-2.42 6.3-3.11 2.27-0.71 4.44-1.08 6.51-1.08h26.6v-10.8c0-2.07-0.651-3.75-1.97-5.42-1.28-1.68-3.35-2.56-6.21-2.56h-13.8c-3.06 0-5.13 0.749-6.41 2.27-1.08 1.48-1.68 3.15-1.68 5.13v0.966c0 4.14-2.27 6.21-6.7 6.21s-6.7-2.07-6.7-6.21v-1.08c0-3.35 0.552-6.01 1.68-8.28 1.28-2.27 2.86-4.14 4.73-5.62h-0.118c2.07-1.38 4.24-2.56 6.51-3.45 2.37-0.907 4.54-1.38 6.61-1.38h18.7c2.07 0 4.14 0.454 6.41 1.38 2.37 0.907 4.44 2.07 6.51 3.45h-0.118c2.07 1.48 3.65 3.45 4.73 6.01 1.08 2.46 1.68 5.23 1.68 8.48v48.3c0 3.75-2.27 5.72-6.61 5.72-0.907 0-1.77-0.0394-2.56-0.118-0.71-0.0779-1.38-0.286-2.07-0.601-0.562-0.394-1.08-0.927-1.48-1.58-0.325-0.71-0.473-1.68-0.473-2.76l-0.118-26.6h-24.6c-1.77 0-3.15 0.207-4.04 0.601-4.09 1.83-4.1 7.7-4.1 7.79v4.63c0 2.07 0.611 3.65 1.87 4.73 1.28 1.08 3.45 1.58 6.51 1.58h13.8c3.06 0 4.44 1.87 4.44 5.62 0 1.68-0.355 3.06-1.08 4.04-0.71 1.08-1.87 1.58-3.45 1.58zm71-61.1v43.4c0 2.07 0.454 3.65 1.38 4.73 0.907 1.08 2.86 1.68 5.62 1.68h3.15c3.15 0 4.54 1.87 4.44 5.52 0 3.75-1.48 5.62-4.44 5.62h-3.94c-2.66 0-4.93-0.325-7.2-0.966-2.27-0.71-4.44-1.77-6.51-3.06v0.118c-3.94-2.66-5.92-7.1-5.92-13.8v-43.4h-4.63c-2.96 0-4.44-1.87-4.54-5.62 0-3.75 1.58-5.62 4.54-5.62h4.63v-12.8c0-3.75 2.27-5.72 6.8-5.72 4.34 0 6.61 1.97 6.61 5.72v12.8h9.76c3.15 0 4.54 1.87 4.44 5.62 0 3.75-1.48 5.62-4.44 5.62zm37.8-10.4c2.27-0.877 4.44-1.38 6.51-1.38h19.7c2.07 0 4.14 0.454 6.41 1.38 2.27 0.907 4.44 2.07 6.45 3.5 2.01 1.43 3.59 3.4 4.67 5.96 1.08 2.46 1.68 5.23 1.68 8.48v34.5c0 6.51-2.17 11.8-6.51 14.8-4.24 3.06-8.48 4.54-12.8 4.54h-19.7c-2.07 0-4.14-0.355-6.41-1.08-2.27-0.71-4.34-1.87-6.41-3.45-4.34-3.06-6.51-7.89-6.51-14.8v-34.5c0-3.25 0.552-6.01 1.68-8.48 1.08-2.46 2.76-4.44 4.84-5.92s4.15-2.66 6.42-3.55zm24 59.6c3.06 0 5.03-0.848 6.21-2.56 1.28-1.68 1.97-3.45 1.97-5.42v-34.5c0-2.07-0.651-3.75-1.97-5.42-1.28-1.68-3.35-2.56-6.21-2.56h-14.8c-3.06 0-5.13 0.848-6.41 2.56-1.28 1.68-1.87 3.45-1.87 5.42v34.5c0 1.97 0.611 3.75 1.87 5.42 1.28 1.68 3.45 2.56 6.41 2.56zm72.6-50.2h-14.8c-3.35 0-5.42 0.976-6.51 2.96-1.08 1.68-1.68 3.65-1.68 5.92l-0.315 47.3c0 3.75-2.27 5.72-6.61 5.72-4.34 0-6.61-1.97-6.61-5.72v-48.3c0-3.35 0.513-6.11 1.58-8.58 1.08-2.46 2.76-4.34 4.93-5.92 4.24-3.06 8.48-4.54 12.8-4.54h19.7c4.04 0 8.28 1.58 12.8 4.54 4.34 3.06 6.51 7.89 6.51 14.8v48.3c0 3.75-2.27 5.72-6.61 5.72s-6.61-1.97-6.61-5.72v-47.3c0-2.07-0.651-4.04-1.99-6.11-1.34-2.07-3.51-3.06-6.66-3.06z"
11
+ aria-label="Mockaton"/>
4
12
  </svg>
@@ -55,11 +55,10 @@ function setPreflightSpecificHeaders(req, response, methods, headers, maxAge) {
55
55
  if (!methods.includes(methodAskingFor))
56
56
  return
57
57
 
58
+ response.setHeader(CH.AccessControlMaxAge, maxAge)
58
59
  response.setHeader(CH.AccessControlAllowMethods, methodAskingFor)
59
60
  if (headers.length)
60
61
  response.setHeader(CH.AccessControlAllowHeaders, headers.join(','))
61
-
62
- response.setHeader(CH.AccessControlMaxAge, maxAge)
63
62
  }
64
63
 
65
64
 
@@ -2,7 +2,7 @@ import { equal } from 'node:assert/strict'
2
2
  import { promisify } from 'node:util'
3
3
  import { createServer } from 'node:http'
4
4
  import { describe, it, after } from 'node:test'
5
- import { isPreflight, setCorsHeaders, CorsHeader as PH } from './http-cors.js'
5
+ import { isPreflight, setCorsHeaders, CorsHeader as CH } from './http-cors.js'
6
6
 
7
7
 
8
8
  function headerIs(response, header, value) {
@@ -40,8 +40,8 @@ await describe('CORS', async () => {
40
40
 
41
41
  await describe('Identifies Preflight Requests', async () => {
42
42
  const requiredRequestHeaders = {
43
- [PH.Origin]: 'http://locahost:9999',
44
- [PH.AccessControlRequestMethod]: 'POST'
43
+ [CH.Origin]: 'http://locahost:9999',
44
+ [CH.AccessControlRequestMethod]: 'POST'
45
45
  }
46
46
 
47
47
  await it('Ignores non-OPTIONS requests', async () => {
@@ -49,26 +49,26 @@ await describe('CORS', async () => {
49
49
  equal(await res.text(), 'NON_PREFLIGHT')
50
50
  })
51
51
 
52
- await it(`Ignores non-parseable req ${PH.Origin} header`, async () => {
52
+ await it(`Ignores non-parseable req ${CH.Origin} header`, async () => {
53
53
  const headers = {
54
54
  ...requiredRequestHeaders,
55
- [PH.Origin]: 'non-url'
55
+ [CH.Origin]: 'non-url'
56
56
  }
57
57
  const res = await preflight(headers)
58
58
  equal(await res.text(), 'NON_PREFLIGHT')
59
59
  })
60
60
 
61
- await it(`Ignores missing method in ${PH.AccessControlRequestMethod} header`, async () => {
61
+ await it(`Ignores missing method in ${CH.AccessControlRequestMethod} header`, async () => {
62
62
  const headers = { ...requiredRequestHeaders }
63
- delete headers[PH.AccessControlRequestMethod]
63
+ delete headers[CH.AccessControlRequestMethod]
64
64
  const res = await preflight(headers)
65
65
  equal(await res.text(), 'NON_PREFLIGHT')
66
66
  })
67
67
 
68
- await it(`Ignores non-standard method in ${PH.AccessControlRequestMethod} header`, async () => {
68
+ await it(`Ignores non-standard method in ${CH.AccessControlRequestMethod} header`, async () => {
69
69
  const headers = {
70
70
  ...requiredRequestHeaders,
71
- [PH.AccessControlRequestMethod]: 'NON_STANDARD'
71
+ [CH.AccessControlRequestMethod]: 'NON_STANDARD'
72
72
  }
73
73
  const res = await preflight(headers)
74
74
  equal(await res.text(), 'NON_PREFLIGHT')
@@ -87,14 +87,14 @@ await describe('CORS', async () => {
87
87
  methods: ['GET']
88
88
  }
89
89
  const p = await preflight({
90
- [PH.Origin]: FooDotCom,
91
- [PH.AccessControlRequestMethod]: 'GET'
90
+ [CH.Origin]: FooDotCom,
91
+ [CH.AccessControlRequestMethod]: 'GET'
92
92
  })
93
- headerIs(p, PH.AccessControlAllowOrigin, null)
94
- headerIs(p, PH.AccessControlAllowMethods, null)
95
- headerIs(p, PH.AccessControlAllowCredentials, null)
96
- headerIs(p, PH.AccessControlAllowHeaders, null)
97
- headerIs(p, PH.AccessControlMaxAge, null)
93
+ headerIs(p, CH.AccessControlAllowOrigin, null)
94
+ headerIs(p, CH.AccessControlAllowMethods, null)
95
+ headerIs(p, CH.AccessControlAllowCredentials, null)
96
+ headerIs(p, CH.AccessControlAllowHeaders, null)
97
+ headerIs(p, CH.AccessControlMaxAge, null)
98
98
  })
99
99
 
100
100
  await it('not in allowed origins', async () => {
@@ -103,13 +103,13 @@ await describe('CORS', async () => {
103
103
  methods: ['GET']
104
104
  }
105
105
  const p = await preflight({
106
- [PH.Origin]: NotAllowedDotCom,
107
- [PH.AccessControlRequestMethod]: 'GET'
106
+ [CH.Origin]: NotAllowedDotCom,
107
+ [CH.AccessControlRequestMethod]: 'GET'
108
108
  })
109
- headerIs(p, PH.AccessControlAllowOrigin, null)
110
- headerIs(p, PH.AccessControlAllowMethods, null)
111
- headerIs(p, PH.AccessControlAllowCredentials, null)
112
- headerIs(p, PH.AccessControlAllowHeaders, null)
109
+ headerIs(p, CH.AccessControlAllowOrigin, null)
110
+ headerIs(p, CH.AccessControlAllowMethods, null)
111
+ headerIs(p, CH.AccessControlAllowCredentials, null)
112
+ headerIs(p, CH.AccessControlAllowHeaders, null)
113
113
  })
114
114
 
115
115
  await it('origin and method match', async () => {
@@ -118,13 +118,13 @@ await describe('CORS', async () => {
118
118
  methods: ['GET']
119
119
  }
120
120
  const p = await preflight({
121
- [PH.Origin]: AllowedDotCom,
122
- [PH.AccessControlRequestMethod]: 'GET'
121
+ [CH.Origin]: AllowedDotCom,
122
+ [CH.AccessControlRequestMethod]: 'GET'
123
123
  })
124
- headerIs(p, PH.AccessControlAllowOrigin, AllowedDotCom)
125
- headerIs(p, PH.AccessControlAllowMethods, 'GET')
126
- headerIs(p, PH.AccessControlAllowCredentials, null)
127
- headerIs(p, PH.AccessControlAllowHeaders, null)
124
+ headerIs(p, CH.AccessControlAllowOrigin, AllowedDotCom)
125
+ headerIs(p, CH.AccessControlAllowMethods, 'GET')
126
+ headerIs(p, CH.AccessControlAllowCredentials, null)
127
+ headerIs(p, CH.AccessControlAllowHeaders, null)
128
128
  })
129
129
 
130
130
  await it('origin matches from multiple', async () => {
@@ -133,13 +133,13 @@ await describe('CORS', async () => {
133
133
  methods: ['GET']
134
134
  }
135
135
  const p = await preflight({
136
- [PH.Origin]: AllowedDotCom,
137
- [PH.AccessControlRequestMethod]: 'GET'
136
+ [CH.Origin]: AllowedDotCom,
137
+ [CH.AccessControlRequestMethod]: 'GET'
138
138
  })
139
- headerIs(p, PH.AccessControlAllowOrigin, AllowedDotCom)
140
- headerIs(p, PH.AccessControlAllowMethods, 'GET')
141
- headerIs(p, PH.AccessControlAllowCredentials, null)
142
- headerIs(p, PH.AccessControlAllowHeaders, null)
139
+ headerIs(p, CH.AccessControlAllowOrigin, AllowedDotCom)
140
+ headerIs(p, CH.AccessControlAllowMethods, 'GET')
141
+ headerIs(p, CH.AccessControlAllowCredentials, null)
142
+ headerIs(p, CH.AccessControlAllowHeaders, null)
143
143
  })
144
144
 
145
145
  await it('wildcard origin', async () => {
@@ -148,13 +148,13 @@ await describe('CORS', async () => {
148
148
  methods: ['GET']
149
149
  }
150
150
  const p = await preflight({
151
- [PH.Origin]: FooDotCom,
152
- [PH.AccessControlRequestMethod]: 'GET'
151
+ [CH.Origin]: FooDotCom,
152
+ [CH.AccessControlRequestMethod]: 'GET'
153
153
  })
154
- headerIs(p, PH.AccessControlAllowOrigin, FooDotCom)
155
- headerIs(p, PH.AccessControlAllowMethods, 'GET')
156
- headerIs(p, PH.AccessControlAllowCredentials, null)
157
- headerIs(p, PH.AccessControlAllowHeaders, null)
154
+ headerIs(p, CH.AccessControlAllowOrigin, FooDotCom)
155
+ headerIs(p, CH.AccessControlAllowMethods, 'GET')
156
+ headerIs(p, CH.AccessControlAllowCredentials, null)
157
+ headerIs(p, CH.AccessControlAllowHeaders, null)
158
158
  })
159
159
 
160
160
  await it(`wildcard and credentials`, async () => {
@@ -164,13 +164,13 @@ await describe('CORS', async () => {
164
164
  credentials: true
165
165
  }
166
166
  const p = await preflight({
167
- [PH.Origin]: FooDotCom,
168
- [PH.AccessControlRequestMethod]: 'GET'
167
+ [CH.Origin]: FooDotCom,
168
+ [CH.AccessControlRequestMethod]: 'GET'
169
169
  })
170
- headerIs(p, PH.AccessControlAllowOrigin, FooDotCom)
171
- headerIs(p, PH.AccessControlAllowMethods, 'GET')
172
- headerIs(p, PH.AccessControlAllowCredentials, 'true')
173
- headerIs(p, PH.AccessControlAllowHeaders, null)
170
+ headerIs(p, CH.AccessControlAllowOrigin, FooDotCom)
171
+ headerIs(p, CH.AccessControlAllowMethods, 'GET')
172
+ headerIs(p, CH.AccessControlAllowCredentials, 'true')
173
+ headerIs(p, CH.AccessControlAllowHeaders, null)
174
174
  })
175
175
 
176
176
  await it(`wildcard, credentials, and headers`, async () => {
@@ -181,13 +181,13 @@ await describe('CORS', async () => {
181
181
  headers: ['content-type', 'my-header']
182
182
  }
183
183
  const p = await preflight({
184
- [PH.Origin]: FooDotCom,
185
- [PH.AccessControlRequestMethod]: 'GET'
184
+ [CH.Origin]: FooDotCom,
185
+ [CH.AccessControlRequestMethod]: 'GET'
186
186
  })
187
- headerIs(p, PH.AccessControlAllowOrigin, FooDotCom)
188
- headerIs(p, PH.AccessControlAllowMethods, 'GET')
189
- headerIs(p, PH.AccessControlAllowCredentials, 'true')
190
- headerIs(p, PH.AccessControlAllowHeaders, 'content-type,my-header')
187
+ headerIs(p, CH.AccessControlAllowOrigin, FooDotCom)
188
+ headerIs(p, CH.AccessControlAllowMethods, 'GET')
189
+ headerIs(p, CH.AccessControlAllowCredentials, 'true')
190
+ headerIs(p, CH.AccessControlAllowHeaders, 'content-type,my-header')
191
191
  })
192
192
  })
193
193
 
@@ -198,12 +198,12 @@ await describe('CORS', async () => {
198
198
  methods: ['GET']
199
199
  }
200
200
  const p = await request({
201
- [PH.Origin]: NotAllowedDotCom
201
+ [CH.Origin]: NotAllowedDotCom
202
202
  })
203
203
  equal(p.status, 200)
204
- headerIs(p, PH.AccessControlAllowOrigin, null)
205
- headerIs(p, PH.AccessControlAllowCredentials, null)
206
- headerIs(p, PH.AccessControlExposeHeaders, null)
204
+ headerIs(p, CH.AccessControlAllowOrigin, null)
205
+ headerIs(p, CH.AccessControlAllowCredentials, null)
206
+ headerIs(p, CH.AccessControlExposeHeaders, null)
207
207
  })
208
208
 
209
209
  await it('origin allowed', async () => {
@@ -214,12 +214,12 @@ await describe('CORS', async () => {
214
214
  exposedHeaders: ['x-h1', 'x-h2']
215
215
  }
216
216
  const p = await request({
217
- [PH.Origin]: AllowedDotCom
217
+ [CH.Origin]: AllowedDotCom
218
218
  })
219
219
  equal(p.status, 200)
220
- headerIs(p, PH.AccessControlAllowOrigin, AllowedDotCom)
221
- headerIs(p, PH.AccessControlAllowCredentials, 'true')
222
- headerIs(p, PH.AccessControlExposeHeaders, 'x-h1,x-h2')
220
+ headerIs(p, CH.AccessControlAllowOrigin, AllowedDotCom)
221
+ headerIs(p, CH.AccessControlAllowCredentials, 'true')
222
+ headerIs(p, CH.AccessControlExposeHeaders, 'x-h1,x-h2')
223
223
  })
224
224
  })
225
225
  })
@@ -1,7 +1,7 @@
1
1
  export function validate(obj, shape) {
2
2
  for (const [field, value] of Object.entries(obj))
3
3
  if (!shape[field](value))
4
- throw new TypeError(`${field} ${value}`)
4
+ throw new TypeError(`Config.${field}=${JSON.stringify(value)} is invalid`)
5
5
  }
6
6
 
7
7
  export const is = ctor => val => val.constructor === ctor
Binary file