mockaton 6.3.12 → 6.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/.editorconfig CHANGED
@@ -6,3 +6,6 @@ end_of_line = lf
6
6
  indent_size = 2
7
7
  indent_style = tab
8
8
  insert_final_newline = true
9
+
10
+ [*.md]
11
+ indent_style = space
package/README.md CHANGED
@@ -32,8 +32,8 @@ import { Mockaton } from 'mockaton'
32
32
 
33
33
 
34
34
  Mockaton({
35
- mocksDir: resolve('my-mocks-dir'),
36
- port: 2345
35
+ mocksDir: resolve('my-mocks-dir'),
36
+ port: 2345
37
37
  })
38
38
  ```
39
39
 
@@ -44,21 +44,21 @@ node my-mockaton.js
44
44
  ## Config Options
45
45
  ```ts
46
46
  interface Config {
47
- mocksDir: string
48
- ignore?: RegExp // defaults to /(\.DS_Store|~)$/
47
+ mocksDir: string
48
+ ignore?: RegExp // defaults to /(\.DS_Store|~)$/
49
49
 
50
- staticDir?: string
50
+ staticDir?: string
51
51
 
52
- host?: string, // defaults to 'localhost'
53
- port?: number // defaults to 0, which means auto-assigned
54
- proxyFallback?: string // e.g. http://localhost:9999 Target for relaying routes without mocks
52
+ host?: string, // defaults to 'localhost'
53
+ port?: number // defaults to 0, which means auto-assigned
54
+ proxyFallback?: string // e.g. http://localhost:9999 Target for relaying routes without mocks
55
55
 
56
- delay?: number // defaults to 1200 (ms)
57
- cookies?: { [label: string]: string }
58
- extraMimes?: { [fileExt: string]: string }
59
- extraHeaders?: []
56
+ delay?: number // defaults to 1200 (ms)
57
+ cookies?: { [label: string]: string }
58
+ extraMimes?: { [fileExt: string]: string }
59
+ extraHeaders?: []
60
60
 
61
- onReady?: (dashboardUrl: string) => void // defaults to trying to open macOS default browser. pass a noop to prevent opening the dashboard
61
+ onReady?: (dashboardUrl: string) => void // defaults to trying to open macOS default browser. pass a noop to prevent opening the dashboard
62
62
  }
63
63
  ```
64
64
 
@@ -68,12 +68,21 @@ interface Config {
68
68
  Each route can have many mocks, which could either be:
69
69
  - Different response __status code__. For example, for testing error responses.
70
70
  - __Comment__ on the filename, which is anything within parentheses.
71
- - e.g. `api/user(my-comment).POST.201.json`
71
+ - e.g. `api/user(my-comment).POST.201.json`
72
72
 
73
73
  Those alternatives can be manually selected in the dashboard
74
74
  UI, or programmatically, for instance, for setting up tests.
75
75
 
76
- The first file in **alphabetical order** becomes the default mock.
76
+ ### Default Mock for a Route
77
+ You can add the comment: `(default)` to a filename.
78
+ Otherwise, the first file in **alphabetical order** wins.
79
+
80
+ ```
81
+ api/user(some comment).GET.200.json
82
+ api/user(default).GET.200.json
83
+ ```
84
+
85
+ ---
77
86
 
78
87
  ## You can write JSON mocks in JavaScript
79
88
  An Object, Array, or String is sent as JSON.
@@ -81,7 +90,7 @@ An Object, Array, or String is sent as JSON.
81
90
  `api/foo.GET.200.js`
82
91
  ```js
83
92
  export default [
84
- { id: 0 }
93
+ { id: 0 }
85
94
  ]
86
95
  ```
87
96
 
@@ -95,10 +104,10 @@ database, or pull data from a backend. The `request` is of type
95
104
  `response` a [ServerResponse](https://nodejs.org/api/http.html#class-httpserverresponse).
96
105
  ```js
97
106
  export default function optionalName(request, response) {
98
- globalThis.myDatabase ??= { count: 0 }
99
- globalThis.myDatabase.count++
107
+ globalThis.myDatabase ??= { count: 0 }
108
+ globalThis.myDatabase.count++
100
109
 
101
- return JSON.stringify({ a: 1 })
110
+ return JSON.stringify({ a: 1 })
102
111
  }
103
112
  ```
104
113
 
@@ -150,7 +159,7 @@ permitted](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file)
150
159
  but since that’s part of the query string, it’s ignored anyway.
151
160
 
152
161
 
153
- ### Default (index-like) route
162
+ ### Index-like route
154
163
  For instance, let's say you have `api/foo/bar`, and
155
164
  `api/foo`. For the latter you have two options:
156
165
 
@@ -181,12 +190,12 @@ import { jwtCookie } from 'mockaton'
181
190
 
182
191
 
183
192
  Config.cookies = {
184
- 'My Admin User': 'my-cookie=1;Path=/;SameSite=strict',
185
- 'My Normal User': 'my-cookie=0;Path=/;SameSite=strict',
186
- 'My JWT': jwtCookie('my-cookie', {
187
- email: 'john.doe@example.com',
188
- picture: 'https://cdn.auth0.com/avatars/jd.png'
189
- })
193
+ 'My Admin User': 'my-cookie=1;Path=/;SameSite=strict',
194
+ 'My Normal User': 'my-cookie=0;Path=/;SameSite=strict',
195
+ 'My JWT': jwtCookie('my-cookie', {
196
+ email: 'john.doe@example.com',
197
+ picture: 'https://cdn.auth0.com/avatars/jd.png'
198
+ })
190
199
  }
191
200
  ```
192
201
 
@@ -197,16 +206,16 @@ that it's an array and the header name goes in even indices.
197
206
 
198
207
  ```js
199
208
  Config.extraHeaders = [
200
- 'Server', 'Mockaton',
201
- 'Set-Cookie', 'foo=FOO;Path=/;SameSite=strict',
202
- 'Set-Cookie', 'bar=BAR;Path=/;SameSite=strict'
209
+ 'Server', 'Mockaton',
210
+ 'Set-Cookie', 'foo=FOO;Path=/;SameSite=strict',
211
+ 'Set-Cookie', 'bar=BAR;Path=/;SameSite=strict'
203
212
  ]
204
213
  ```
205
214
 
206
215
  ## `Config.extraMimes`
207
216
  ```js
208
217
  Config.extraMimes = {
209
- jpg: 'application/jpeg'
218
+ jpg: 'application/jpeg'
210
219
  }
211
220
  ```
212
221
 
@@ -217,19 +226,19 @@ Config.extraMimes = {
217
226
  ### Select a mock for a route
218
227
  ```js
219
228
  fetch(addr + '/mockaton/edit', {
220
- method: 'PATCH',
221
- body: JSON.stringify({
222
- file: 'api/foo.200.GET.json',
223
- delayed: true // optional
224
- })
229
+ method: 'PATCH',
230
+ body: JSON.stringify({
231
+ file: 'api/foo.200.GET.json',
232
+ delayed: true // optional
233
+ })
225
234
  })
226
235
  ```
227
236
 
228
237
  ### Select all mocks that have a particular comment
229
238
  ```js
230
239
  fetch(addr + '/mockaton/bulk-select-by-comment', {
231
- method: 'PATCH',
232
- body: JSON.stringify('(demo-a)')
240
+ method: 'PATCH',
241
+ body: JSON.stringify('(demo-a)')
233
242
  })
234
243
  ```
235
244
 
@@ -243,16 +252,16 @@ fetch(addr + '/mockaton/cookies')
243
252
  In `Config.cookies`, each key is the label used for changing it.
244
253
  ```js
245
254
  fetch(addr + '/mockaton/cookies', {
246
- method: 'PATCH',
247
- body: JSON.stringify('My Normal User')
255
+ method: 'PATCH',
256
+ body: JSON.stringify('My Normal User')
248
257
  })
249
258
  ```
250
259
 
251
260
  ### Update Fallback Proxy
252
261
  ```js
253
262
  fetch(addr + '/mockaton/fallback', {
254
- method: 'PATCH',
255
- body: JSON.stringify('http://example.com')
263
+ method: 'PATCH',
264
+ body: JSON.stringify('http://example.com')
256
265
  })
257
266
  ```
258
267
 
@@ -262,6 +271,6 @@ will be considered. The selected mocks, cookies, and delays are
262
271
  back to default. But the `Config.proxyFalllback` is not affected.
263
272
  ```js
264
273
  fetch(addr + '/mockaton/reset', {
265
- method: 'PATCH'
274
+ method: 'PATCH'
266
275
  })
267
276
  ```
package/Tests.js CHANGED
@@ -12,7 +12,7 @@ import { Config } from './src/Config.js'
12
12
  import { mimeFor } from './src/utils/mime.js'
13
13
  import { Mockaton } from './src/Mockaton.js'
14
14
  import { parseFilename } from './src/Filename.js'
15
- import { API, DF, DEFAULT_500_COMMENT } from './src/ApiConstants.js'
15
+ import { API, DF, DEFAULT_500_COMMENT, DEFAULT_MOCK_COMMENT } from './src/ApiConstants.js'
16
16
 
17
17
 
18
18
  const tmpDir = mkdtempSync(tmpdir()) + '/'
@@ -25,6 +25,17 @@ const fixtureCustomMime = [
25
25
  'Custom Extension and MIME'
26
26
  ]
27
27
 
28
+ const fixtureNonDefaultInName = [
29
+ '/api/the-route',
30
+ 'api/the-route(default).GET.200.json',
31
+ 'default my route body content'
32
+ ]
33
+ const fixtureDefaultInName = [
34
+ '/api/the-route',
35
+ 'api/the-route(default).GET.200.json',
36
+ 'default my route body content'
37
+ ]
38
+
28
39
  const fixtures = [
29
40
  [
30
41
  '/api',
@@ -33,11 +44,13 @@ const fixtures = [
33
44
  ],
34
45
 
35
46
  // Exact route paths
47
+ fixtureDefaultInName,
36
48
  [
37
49
  '/api/the-route',
38
- 'api/the-route(comment-1).GET.200.json',
39
- 'my route body content'
40
- ], [
50
+ 'api/the-route(default).GET.200.json',
51
+ 'default my route body content'
52
+ ],
53
+ [
41
54
  '/api/the-mime',
42
55
  'api/the-mime.GET.200.txt',
43
56
  'determines the content type'
@@ -107,7 +120,7 @@ const fixtures = [
107
120
  ],
108
121
  fixtureCustomMime
109
122
  ]
110
- for (const [, file, body] of fixtures)
123
+ for (const [, file, body] of [fixtureNonDefaultInName, ...fixtures])
111
124
  write(file, file.endsWith('.json') ? JSON.stringify(body) : body)
112
125
 
113
126
  write('api/.GET.500.txt', 'keeps non-autogenerated 500')
@@ -145,6 +158,8 @@ async function runTests() {
145
158
  for (const [url, file, body] of fixtures)
146
159
  await testMockDispatching(url, file, body)
147
160
 
161
+ await testDefaultMock()
162
+
148
163
  await testItUpdatesDelayAndFile(
149
164
  '/api/alternative',
150
165
  'api/alternative(comment-2).GET.200.json',
@@ -174,7 +189,8 @@ async function runTests() {
174
189
  '(comment-2)',
175
190
  DEFAULT_500_COMMENT,
176
191
  '(this is the actual comment)',
177
- '(another comment)'
192
+ '(another comment)',
193
+ DEFAULT_MOCK_COMMENT
178
194
  ])
179
195
  await testItBulkSelectsByComment('(comment-2)', [
180
196
  ['/api/alternative', 'api/alternative(comment-2).GET.200.json', { comment: 2 }],
@@ -238,6 +254,10 @@ async function testMockDispatching(url, file, expectedBody, forcedMime = undefin
238
254
  })
239
255
  }
240
256
 
257
+ async function testDefaultMock() {
258
+ await testMockDispatching(...fixtureDefaultInName)
259
+ }
260
+
241
261
  async function testItUpdatesTheCurrentSelectedMock(url, file, expectedStatus, expectedBody) {
242
262
  await request(API.edit, {
243
263
  method: 'PATCH',
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": "6.3.12",
5
+ "version": "6.4.0",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "license": "MIT",
package/src/Api.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
- * API for controlling the mock server. For example,
3
- * setting a specific mock-file for a particular route.
2
+ * API for controlling Mockaton. For example, for
3
+ * selecting a specific mock-file for a particular route.
4
4
  */
5
5
 
6
6
  import { join } from 'node:path'
@@ -60,7 +60,7 @@ async function updateBroker(req, response) {
60
60
  const file = body[DF.file]
61
61
  const broker = mockBrokersCollection.getBrokerByFilename(file)
62
62
  if (!broker || !broker.mockExists(file)) {
63
- sendUnprocessableContent(response, `Missing Mock: "${file}`)
63
+ sendUnprocessableContent(response, `Missing Mock: ${file}`)
64
64
  return
65
65
  }
66
66
  if (DF.delayed in body)
@@ -16,3 +16,4 @@ export const DF = { // Dashboard Fields (XHR)
16
16
  }
17
17
 
18
18
  export const DEFAULT_500_COMMENT = '(Mockaton Temp 500)'
19
+ export const DEFAULT_MOCK_COMMENT = '(default)'
package/src/MockBroker.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Config } from './Config.js'
2
- import { DEFAULT_500_COMMENT } from './ApiConstants.js'
2
+ import { DEFAULT_500_COMMENT, DEFAULT_MOCK_COMMENT } from './ApiConstants.js'
3
3
  import { includesComment, extractComments, parseFilename } from './Filename.js'
4
4
 
5
5
 
@@ -22,8 +22,6 @@ export class MockBroker {
22
22
  }
23
23
 
24
24
  register(file) {
25
- if (!this.mocks.length)
26
- this.currentMock.file = file // The first mock file option for a particular route becomes the default
27
25
  this.mocks.push(file)
28
26
  }
29
27
 
@@ -42,6 +40,15 @@ export class MockBroker {
42
40
  get delay() { return this.currentMock.delay }
43
41
  get status() { return parseFilename(this.file).status }
44
42
 
43
+ selectDefaultFile() {
44
+ this.updateFile(this.#findMockWithDefaultComment() || this.mocks[0])
45
+ }
46
+ #findMockWithDefaultComment() {
47
+ for (const f of this.mocks)
48
+ if (includesComment(f, DEFAULT_MOCK_COMMENT))
49
+ return f
50
+ }
51
+
45
52
  mockExists(file) {
46
53
  return this.mocks.includes(file)
47
54
  }
@@ -34,7 +34,10 @@ export function init() {
34
34
  collection[method][urlMask].register(file)
35
35
  }
36
36
 
37
- forEachBroker(broker => broker.ensureItHas500())
37
+ forEachBroker(broker => {
38
+ broker.selectDefaultFile()
39
+ broker.ensureItHas500()
40
+ })
38
41
  }
39
42
 
40
43