mockaton 0.10.10 → 1.1.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 +54 -39
- package/Tests.js +12 -5
- package/package.json +1 -1
- package/sample-mocks/api/user/likes.GET.200.js +7 -0
- package/sample-mocks/api/user/likes.GET.500.txt +0 -0
- package/src/Api.js +5 -7
- package/src/ApiConstants.js +1 -3
- package/src/Config.js +3 -3
- package/src/Dashboard.js +3 -3
- package/src/MockDispatcher.js +8 -4
- package/src/ProxyRelay.js +1 -1
- package/src/mockBrokersCollection.js +1 -1
package/README.md
CHANGED
|
@@ -26,6 +26,17 @@ UI, or programmatically, for instance, for setting up tests.
|
|
|
26
26
|
|
|
27
27
|
The first file in **alphabetical order** becomes the default mock.
|
|
28
28
|
|
|
29
|
+
### Optionally, you can write mocks in JavaScript
|
|
30
|
+
An Object, Array, or String is sent as JSON.
|
|
31
|
+
|
|
32
|
+
`api/user/likes.GET.200.js`
|
|
33
|
+
```js
|
|
34
|
+
export default [
|
|
35
|
+
{ id: 0 }
|
|
36
|
+
]
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
|
|
29
40
|
### Proxying Routes
|
|
30
41
|
`Config.proxyFallback` lets you specify a target
|
|
31
42
|
server for serving routes you don’t have mocks for.
|
|
@@ -78,7 +89,7 @@ interface Config {
|
|
|
78
89
|
database?: object // for "Transforms"
|
|
79
90
|
skipOpen?: boolean // Prevents opening the dashboard in a browser
|
|
80
91
|
proxyFallback?: string // e.g. http://localhost:9999 Target for relaying routes without mocks
|
|
81
|
-
allowedExt?: RegExp // /\.(json|txt|md|mjs)$/ Just for excluding temporary editor files (e.g. JetBrains appends a ~)
|
|
92
|
+
allowedExt?: RegExp // /\.(json|txt|md|js|mjs)$/ Just for excluding temporary editor files (e.g. JetBrains appends a ~)
|
|
82
93
|
}
|
|
83
94
|
```
|
|
84
95
|
|
|
@@ -177,60 +188,64 @@ export default function capitalizeAllText(mockAsText, requestBody, config) {
|
|
|
177
188
|
}
|
|
178
189
|
```
|
|
179
190
|
|
|
180
|
-
---
|
|
181
191
|
|
|
182
192
|
## API
|
|
183
193
|
|
|
184
|
-
###
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
194
|
+
### Select a mock for a route
|
|
195
|
+
```js
|
|
196
|
+
fetch(addr + '/mockaton/edit', {
|
|
197
|
+
method: 'PATCH',
|
|
198
|
+
body: JSON.stringify({
|
|
199
|
+
file: 'api/foo.200.GET.json',
|
|
200
|
+
delayed: true // optional
|
|
201
|
+
})
|
|
202
|
+
})
|
|
191
203
|
```
|
|
192
|
-
---
|
|
193
|
-
|
|
194
|
-
### `/mockaton/bulk-select` Select all mocks that have a particular comment
|
|
195
204
|
|
|
205
|
+
### Select all mocks that have a particular comment
|
|
206
|
+
```js
|
|
207
|
+
fetch(addr + '/mockaton/bulk-select-by-comment', {
|
|
208
|
+
method: 'PATCH',
|
|
209
|
+
body: JSON.stringify('(demo-a)')
|
|
210
|
+
})
|
|
196
211
|
```
|
|
197
|
-
PATCH /mockaton/bulk-select
|
|
198
|
-
{
|
|
199
|
-
"comment": "(demo-a)"
|
|
200
|
-
}
|
|
201
|
-
```
|
|
202
|
-
---
|
|
203
212
|
|
|
204
|
-
###
|
|
213
|
+
### Reset
|
|
205
214
|
Re-Initialize the collection and its states (selected mocks and cookies, delays, etc.).
|
|
215
|
+
```js
|
|
216
|
+
fetch(add + '/mockaton/reset', {
|
|
217
|
+
method: 'PATCH'
|
|
218
|
+
})
|
|
206
219
|
```
|
|
207
|
-
PATCH /mockaton/reset
|
|
208
|
-
```
|
|
209
|
-
---
|
|
210
220
|
|
|
211
|
-
###
|
|
221
|
+
### Select a cookie
|
|
212
222
|
In `Config.cookies`, each key is the label used
|
|
213
223
|
for changing it. Only one cookie can be set.
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
224
|
+
```js
|
|
225
|
+
fetch(addr + '/mockaton/cookies', {
|
|
226
|
+
method: 'PATCH',
|
|
227
|
+
body: JSON.stringify('My Normal User')
|
|
228
|
+
})
|
|
219
229
|
```
|
|
220
230
|
|
|
221
|
-
###
|
|
231
|
+
### List Cookies
|
|
222
232
|
Sends a list of the available cookies along with a flag indicated if it’s the selected.
|
|
223
|
-
```
|
|
224
|
-
|
|
233
|
+
```js
|
|
234
|
+
fetch(addr + '/mockaton/cookies')
|
|
225
235
|
```
|
|
226
236
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
237
|
+
### Select a Transform
|
|
238
|
+
```js
|
|
239
|
+
fetch(addr + '/mockaton/transform', {
|
|
240
|
+
method: 'PATCH',
|
|
241
|
+
body: JSON.stringify('api/video/list(concat newly uploaded).GET.200.mjs')
|
|
242
|
+
})
|
|
230
243
|
```
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
244
|
+
|
|
245
|
+
### Update Fallback Proxy
|
|
246
|
+
```js
|
|
247
|
+
fetch(addr + '/mockaton/fallback', {
|
|
248
|
+
method: 'PATCH',
|
|
249
|
+
body: JSON.stringify('http://example.com')
|
|
250
|
+
})
|
|
235
251
|
```
|
|
236
|
-
---
|
package/Tests.js
CHANGED
|
@@ -96,6 +96,9 @@ write('api/.GET.500.txt', 'keeps non-autogenerated 500')
|
|
|
96
96
|
write('api/alternative(comment-2).GET.200.json', JSON.stringify({ comment: 2 }))
|
|
97
97
|
write('api/my-route(comment-2).GET.200.json', JSON.stringify({ comment: 2 }))
|
|
98
98
|
|
|
99
|
+
// JavaScript to JSON
|
|
100
|
+
write('/api/object.GET.200.js', 'export default { JSON_FROM_JS: true }')
|
|
101
|
+
|
|
99
102
|
writeStatic('index.html', '<h1>Static</h1>')
|
|
100
103
|
writeStatic('assets/app.js', 'const app = 1')
|
|
101
104
|
writeStatic('another-entry/index.html', '<h1>Another</h1>')
|
|
@@ -118,6 +121,8 @@ async function runTests() {
|
|
|
118
121
|
for (const [url, file, body] of fixtures)
|
|
119
122
|
await testMockDispatching(url, file, body)
|
|
120
123
|
|
|
124
|
+
await testMockDispatching('/api/object', 'api/object.GET.200.js', { JSON_FROM_JS: true }, undefined, mimeFor('.json'))
|
|
125
|
+
|
|
121
126
|
await testItUpdatesDelayAndFile(
|
|
122
127
|
'/api/alternative',
|
|
123
128
|
'api/alternative(comment-2).GET.200.json',
|
|
@@ -185,9 +190,9 @@ async function test404() {
|
|
|
185
190
|
})
|
|
186
191
|
}
|
|
187
192
|
|
|
188
|
-
async function testMockDispatching(url, file, expectedBody, reqBody = void 0) {
|
|
193
|
+
async function testMockDispatching(url, file, expectedBody, reqBody = void 0, forcedMime = void 0) {
|
|
189
194
|
const { urlMask, method, status } = Route.parseFilename(file)
|
|
190
|
-
const mime = mimeFor(file)
|
|
195
|
+
const mime = forcedMime || mimeFor(file)
|
|
191
196
|
const now = new Date()
|
|
192
197
|
const res = await request(url, { method, body: reqBody })
|
|
193
198
|
const body = mime === 'application/json'
|
|
@@ -269,7 +274,7 @@ async function testExtractsAllComments(expected) {
|
|
|
269
274
|
async function testItBulkSelectsByComment(comment, tests) {
|
|
270
275
|
await request(API.bulkSelect, {
|
|
271
276
|
method: 'PATCH',
|
|
272
|
-
body: JSON.stringify(
|
|
277
|
+
body: JSON.stringify(comment)
|
|
273
278
|
})
|
|
274
279
|
for (const [url, file, body] of tests)
|
|
275
280
|
await testMockDispatching(url, file, body)
|
|
@@ -289,7 +294,7 @@ async function testItUpdatesUserRole() {
|
|
|
289
294
|
it('Update the selected cookie', async () => {
|
|
290
295
|
await request(API.cookies, {
|
|
291
296
|
method: 'PATCH',
|
|
292
|
-
body: JSON.stringify(
|
|
297
|
+
body: JSON.stringify('userB')
|
|
293
298
|
})
|
|
294
299
|
const res = await request(API.cookies)
|
|
295
300
|
deepEqual(await res.json(), [
|
|
@@ -313,7 +318,7 @@ export default function (mock, reqBody, config) {
|
|
|
313
318
|
await reset() // for registering the files
|
|
314
319
|
await request(API.transform, {
|
|
315
320
|
method: 'PATCH',
|
|
316
|
-
body: JSON.stringify(
|
|
321
|
+
body: JSON.stringify('api/transform.POST.200.mjs')
|
|
317
322
|
})
|
|
318
323
|
await testMockDispatching('/api/transform',
|
|
319
324
|
'api/transform.POST.200.json',
|
|
@@ -367,6 +372,7 @@ async function testInvalidFilenamesAreIgnored() {
|
|
|
367
372
|
async function testEnableFallbackSoRoutesWithoutMocksGetRelayed() {
|
|
368
373
|
await describe('Fallback', async () => {
|
|
369
374
|
const fallbackServer = createServer((_, response) => {
|
|
375
|
+
response.setHeader('custom_header', 'my_custom_header')
|
|
370
376
|
response.statusCode = 423
|
|
371
377
|
response.end('From_Fallback_Server')
|
|
372
378
|
})
|
|
@@ -378,6 +384,7 @@ async function testEnableFallbackSoRoutesWithoutMocksGetRelayed() {
|
|
|
378
384
|
})
|
|
379
385
|
await it('Relays to fallback server', async () => {
|
|
380
386
|
const res = await request('/non-existing-mock')
|
|
387
|
+
equal(res.headers.get('custom_header'), 'my_custom_header')
|
|
381
388
|
equal(res.status, 423)
|
|
382
389
|
equal(await res.text(), 'From_Fallback_Server')
|
|
383
390
|
fallbackServer.close()
|
package/package.json
CHANGED
|
File without changes
|
package/src/Api.js
CHANGED
|
@@ -51,8 +51,7 @@ function listMockBrokers(_, response) {
|
|
|
51
51
|
|
|
52
52
|
async function selectCookie(req, response) {
|
|
53
53
|
try {
|
|
54
|
-
|
|
55
|
-
cookie.setCurrent(body[DF.currentCookieKey])
|
|
54
|
+
cookie.setCurrent(await parseJSON(req))
|
|
56
55
|
sendOK(response)
|
|
57
56
|
}
|
|
58
57
|
catch (error) {
|
|
@@ -84,8 +83,7 @@ async function updateBroker(req, response) {
|
|
|
84
83
|
|
|
85
84
|
async function bulkUpdateBrokersByCommentTag(req, response) {
|
|
86
85
|
try {
|
|
87
|
-
|
|
88
|
-
mockBrokersCollection.setMocksMatchingComment(body[DF.comment])
|
|
86
|
+
mockBrokersCollection.setMocksMatchingComment(await parseJSON(req))
|
|
89
87
|
sendOK(response)
|
|
90
88
|
}
|
|
91
89
|
catch (error) {
|
|
@@ -96,9 +94,9 @@ async function bulkUpdateBrokersByCommentTag(req, response) {
|
|
|
96
94
|
|
|
97
95
|
async function updateBrokerTransform(req, response) {
|
|
98
96
|
try {
|
|
99
|
-
const
|
|
100
|
-
const broker = mockBrokersCollection.getBrokerByFilename(
|
|
101
|
-
broker.updateTransform(
|
|
97
|
+
const file = await parseJSON(req)
|
|
98
|
+
const broker = mockBrokersCollection.getBrokerByFilename(file)
|
|
99
|
+
broker.updateTransform(file)
|
|
102
100
|
sendOK(response)
|
|
103
101
|
}
|
|
104
102
|
catch (error) {
|
package/src/ApiConstants.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const MOUNT = '/mockaton'
|
|
2
2
|
export const API = {
|
|
3
3
|
dashboard: MOUNT,
|
|
4
|
-
bulkSelect: MOUNT + '/bulk-select',
|
|
4
|
+
bulkSelect: MOUNT + '/bulk-select-by-comment',
|
|
5
5
|
comments: MOUNT + '/comments',
|
|
6
6
|
edit: MOUNT + '/edit',
|
|
7
7
|
mocks: MOUNT + '/mocks',
|
|
@@ -12,9 +12,7 @@ export const API = {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export const DF = { // Dashboard Fields (XHR)
|
|
15
|
-
comment: 'comment',
|
|
16
15
|
delayed: 'delayed',
|
|
17
16
|
file: 'file',
|
|
18
|
-
currentCookieKey: 'current_cookie_key',
|
|
19
17
|
isForDashboard: 'mock_request_payload'
|
|
20
18
|
}
|
package/src/Config.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, lstatSync } from 'node:fs'
|
|
1
|
+
import { existsSync as exists, lstatSync } from 'node:fs'
|
|
2
2
|
import { validate, is, optional } from './utils/validate.js'
|
|
3
3
|
|
|
4
4
|
|
|
@@ -12,7 +12,7 @@ export const Config = {
|
|
|
12
12
|
database: {},
|
|
13
13
|
skipOpen: false,
|
|
14
14
|
proxyFallback: '', // e.g. http://localhost:9999
|
|
15
|
-
allowedExt: /\.(json|txt|md|mjs)$/ // Just for excluding temporary editor files (e.g. JetBrains appends a ~)
|
|
15
|
+
allowedExt: /\.(json|txt|md|js|mjs)$/ // Just for excluding temporary editor files (e.g. JetBrains appends a ~)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function setup(options) {
|
|
@@ -32,7 +32,7 @@ export function setup(options) {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
function isDirectory(dir) {
|
|
35
|
-
return
|
|
35
|
+
return exists(dir) && lstatSync(dir).isDirectory()
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
|
package/src/Dashboard.js
CHANGED
|
@@ -103,7 +103,7 @@ function CookieSelector({ list }) {
|
|
|
103
103
|
onChange() {
|
|
104
104
|
fetch(API.cookies, {
|
|
105
105
|
method: 'PATCH',
|
|
106
|
-
body: JSON.stringify(
|
|
106
|
+
body: JSON.stringify(this.value)
|
|
107
107
|
})
|
|
108
108
|
.then(init)
|
|
109
109
|
.catch(console.error)
|
|
@@ -124,7 +124,7 @@ function BulkSelector({ comments }) {
|
|
|
124
124
|
onChange() {
|
|
125
125
|
fetch(API.bulkSelect, {
|
|
126
126
|
method: 'PATCH',
|
|
127
|
-
body: JSON.stringify(
|
|
127
|
+
body: JSON.stringify(this.value)
|
|
128
128
|
})
|
|
129
129
|
.then(init)
|
|
130
130
|
.catch(console.error)
|
|
@@ -274,7 +274,7 @@ function TransformSelector({ items, selected }) {
|
|
|
274
274
|
onChange() {
|
|
275
275
|
fetch(API.transform, {
|
|
276
276
|
method: 'PATCH',
|
|
277
|
-
body: JSON.stringify(
|
|
277
|
+
body: JSON.stringify(this.value)
|
|
278
278
|
}).then(() => {
|
|
279
279
|
this.closest('tr').querySelector('a').click()
|
|
280
280
|
this.className = className(this.value === this.options[0].value)
|
package/src/MockDispatcher.js
CHANGED
|
@@ -31,15 +31,19 @@ export async function dispatchMock(req, response) {
|
|
|
31
31
|
const { file, status, delay, currentTransform } = broker
|
|
32
32
|
console.log('\n', req.url, '→\n ', file)
|
|
33
33
|
|
|
34
|
+
const shouldJavaScriptToJSON = file.endsWith('.js')
|
|
34
35
|
response.statusCode = status
|
|
35
|
-
response.setHeader('content-type', mimeFor(file))
|
|
36
|
+
response.setHeader('content-type', mimeFor(shouldJavaScriptToJSON ? '.json' : file))
|
|
36
37
|
if (cookie.getCurrent())
|
|
37
38
|
response.setHeader('set-cookie', cookie.getCurrent())
|
|
38
39
|
|
|
39
|
-
let mockAsText =
|
|
40
|
+
let mockAsText = shouldJavaScriptToJSON
|
|
41
|
+
? JSON.stringify(await importDefault(file))
|
|
42
|
+
: readMock(file)
|
|
43
|
+
|
|
40
44
|
if (broker.currentTransform) {
|
|
41
45
|
const body = await requestBodyForTransform(req, mockAsText)
|
|
42
|
-
const transformFunc = await
|
|
46
|
+
const transformFunc = await importDefault(currentTransform)
|
|
43
47
|
mockAsText = transformFunc(mockAsText, body, Config)
|
|
44
48
|
}
|
|
45
49
|
setTimeout(() => response.end(mockAsText), delay)
|
|
@@ -69,7 +73,7 @@ function readMock(file) {
|
|
|
69
73
|
return readFileSync(join(Config.mocksDir, file), 'utf8')
|
|
70
74
|
}
|
|
71
75
|
|
|
72
|
-
async function
|
|
76
|
+
async function importDefault(file) {
|
|
73
77
|
// The date param is just for cache busting
|
|
74
78
|
return (await import(join(Config.mocksDir, file) + '?' + Date.now())).default
|
|
75
79
|
}
|
package/src/ProxyRelay.js
CHANGED
|
@@ -6,6 +6,6 @@ export async function proxy(req, response) {
|
|
|
6
6
|
method: req.method,
|
|
7
7
|
headers: req.headers
|
|
8
8
|
})
|
|
9
|
-
response.writeHead(proxyResponse.status, proxyResponse.headers)
|
|
9
|
+
response.writeHead(proxyResponse.status, Object.fromEntries(proxyResponse.headers))
|
|
10
10
|
response.end(await proxyResponse.text())
|
|
11
11
|
}
|