mockaton 6.3.12 → 6.4.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/.editorconfig +3 -0
- package/README.md +51 -42
- package/Tests.js +26 -6
- package/package.json +1 -1
- package/sample-mocks/api/user/{videos(entirely unverified).GET.200.json → videos(default).GET.200.json} +1 -1
- package/src/Api.js +3 -3
- package/src/ApiConstants.js +1 -0
- package/src/MockBroker.js +16 -3
- package/src/mockBrokersCollection.js +4 -1
- /package/sample-mocks/api/user/{videos(assorted).GET.200.json → videos(all variants).GET.200.json} +0 -0
- /package/sample-mocks/api/user/{videos(entirely verified)(another comment).GET.200.json → videos(verified)(another comment).GET.200.json} +0 -0
package/.editorconfig
CHANGED
package/README.md
CHANGED
|
@@ -32,8 +32,8 @@ import { Mockaton } from 'mockaton'
|
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
Mockaton({
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
48
|
-
|
|
47
|
+
mocksDir: string
|
|
48
|
+
ignore?: RegExp // defaults to /(\.DS_Store|~)$/
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
staticDir?: string
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
delay?: number // defaults to 1200 (ms)
|
|
57
|
+
cookies?: { [label: string]: string }
|
|
58
|
+
extraMimes?: { [fileExt: string]: string }
|
|
59
|
+
extraHeaders?: []
|
|
60
60
|
|
|
61
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
99
|
-
|
|
107
|
+
globalThis.myDatabase ??= { count: 0 }
|
|
108
|
+
globalThis.myDatabase.count++
|
|
100
109
|
|
|
101
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
-
|
|
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
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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
|
-
|
|
232
|
-
|
|
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
|
-
|
|
247
|
-
|
|
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
|
-
|
|
255
|
-
|
|
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
|
-
|
|
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(
|
|
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
package/src/Api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* API for controlling
|
|
3
|
-
*
|
|
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:
|
|
63
|
+
sendUnprocessableContent(response, `Missing Mock: ${file}`)
|
|
64
64
|
return
|
|
65
65
|
}
|
|
66
66
|
if (DF.delayed in body)
|
package/src/ApiConstants.js
CHANGED
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,21 @@ 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
|
+
const userSpecifiedDefault = this.#findMockWithDefaultComment()
|
|
45
|
+
if (userSpecifiedDefault)
|
|
46
|
+
this.mocks = [ // sort for dashboard list TESTME
|
|
47
|
+
userSpecifiedDefault,
|
|
48
|
+
...this.mocks.filter(m => m !== userSpecifiedDefault)
|
|
49
|
+
]
|
|
50
|
+
this.updateFile(userSpecifiedDefault || this.mocks[0])
|
|
51
|
+
}
|
|
52
|
+
#findMockWithDefaultComment() {
|
|
53
|
+
for (const f of this.mocks)
|
|
54
|
+
if (includesComment(f, DEFAULT_MOCK_COMMENT))
|
|
55
|
+
return f
|
|
56
|
+
}
|
|
57
|
+
|
|
45
58
|
mockExists(file) {
|
|
46
59
|
return this.mocks.includes(file)
|
|
47
60
|
}
|
/package/sample-mocks/api/user/{videos(assorted).GET.200.json → videos(all variants).GET.200.json}
RENAMED
|
File without changes
|