mockaton 6.4.7 → 7.0.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 +25 -33
- package/Tests.js +43 -59
- package/index.d.ts +23 -0
- package/index.js +1 -0
- package/package.json +1 -1
- package/src/Api.js +27 -6
- package/src/ApiConstants.js +5 -3
- package/src/Commander.js +54 -0
- package/src/Dashboard.js +12 -12
- package/src/Mockaton.js +24 -22
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ The best way to learn _Mockaton_ is by checking out this repo and
|
|
|
42
42
|
exploring its [sample-mocks/](./sample-mocks) directory. Then, run
|
|
43
43
|
[`./_usage_example.js`](./_usage_example.js) and you’ll see the dashboard.
|
|
44
44
|
|
|
45
|
-
You can
|
|
45
|
+
You can select mock files without resetting Mockaton. The _Reset_
|
|
46
46
|
button is for when you add, remove, or rename a mock file.
|
|
47
47
|
|
|
48
48
|
The dropdown lets you pick a mock variant, details in the next section. Next to it is a
|
|
@@ -288,60 +288,52 @@ Config.onReady = open
|
|
|
288
288
|
|
|
289
289
|
---
|
|
290
290
|
|
|
291
|
-
## API
|
|
292
|
-
|
|
293
|
-
|
|
291
|
+
## HTTP API
|
|
292
|
+
`Commander` is a wrapper for the Mockaton HTTP API.
|
|
293
|
+
All of its methods return their `fetch` response promise.
|
|
294
294
|
```js
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
})
|
|
301
|
-
})
|
|
295
|
+
import { Commander } from 'mockaton'
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
const myMockatonAddr = 'http://localhost:2345'
|
|
299
|
+
const commander = new Commander(myMockatonAddr)
|
|
302
300
|
```
|
|
303
301
|
|
|
302
|
+
### Select a mock file for a route
|
|
303
|
+
```js
|
|
304
|
+
await commander.select('api/foo.200.GET.json')
|
|
305
|
+
```
|
|
304
306
|
### Select all mocks that have a particular comment
|
|
305
307
|
```js
|
|
306
|
-
|
|
307
|
-
method: 'PATCH',
|
|
308
|
-
body: JSON.stringify('(demo-a)')
|
|
309
|
-
})
|
|
308
|
+
await commander.bulkSelectByComment('(demo-a)')
|
|
310
309
|
```
|
|
311
310
|
|
|
312
|
-
###
|
|
313
|
-
Sends a list of the available cookies along with an "is selected" boolean flag.
|
|
311
|
+
### Set Route is Delayed Flag
|
|
314
312
|
```js
|
|
315
|
-
|
|
313
|
+
await commander.setRouteIsDelayed('GET', '/api/foo', true)
|
|
316
314
|
```
|
|
317
315
|
|
|
318
316
|
### Select a cookie
|
|
319
|
-
In `Config.cookies`, each key is the label used for
|
|
317
|
+
In `Config.cookies`, each key is the label used for selecting it.
|
|
320
318
|
```js
|
|
321
|
-
|
|
322
|
-
method: 'PATCH',
|
|
323
|
-
body: JSON.stringify('My Normal User')
|
|
324
|
-
})
|
|
319
|
+
await commander.selectCookie('My Normal User')
|
|
325
320
|
```
|
|
326
321
|
|
|
327
|
-
###
|
|
322
|
+
### Set Fallback Proxy
|
|
328
323
|
```js
|
|
329
|
-
|
|
330
|
-
method: 'PATCH',
|
|
331
|
-
body: JSON.stringify('http://example.com')
|
|
332
|
-
})
|
|
324
|
+
await commander.setProxyFallback('http://example.com')
|
|
333
325
|
```
|
|
326
|
+
Pass an empty string to disable it.
|
|
334
327
|
|
|
335
328
|
### Reset
|
|
336
329
|
Re-initialize the collection. So if you added or removed mocks they
|
|
337
330
|
will be considered. The selected mocks, cookies, and delays go
|
|
338
|
-
back to default, but `Config.
|
|
331
|
+
back to default, but `Config.proxyFallback` is not affected.
|
|
339
332
|
```js
|
|
340
|
-
|
|
341
|
-
method: 'PATCH'
|
|
342
|
-
})
|
|
333
|
+
await commander.reset()
|
|
343
334
|
```
|
|
344
335
|
|
|
336
|
+
|
|
345
337
|
## TODO
|
|
346
|
-
- Dashboard. List `staticDir` and indicate if it’s overriding some mock.
|
|
347
338
|
- Refactor Tests
|
|
339
|
+
- Dashboard. List `staticDir` and indicate if it’s overriding some mock.
|
package/Tests.js
CHANGED
|
@@ -11,8 +11,9 @@ import { writeFileSync, mkdtempSync, mkdirSync } from 'node:fs'
|
|
|
11
11
|
import { Config } from './src/Config.js'
|
|
12
12
|
import { mimeFor } from './src/utils/mime.js'
|
|
13
13
|
import { Mockaton } from './src/Mockaton.js'
|
|
14
|
+
import { Commander } from './src/Commander.js'
|
|
14
15
|
import { parseFilename } from './src/Filename.js'
|
|
15
|
-
import { API,
|
|
16
|
+
import { API, DEFAULT_500_COMMENT, DEFAULT_MOCK_COMMENT } from './src/ApiConstants.js'
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
const tmpDir = mkdtempSync(tmpdir()) + '/'
|
|
@@ -36,6 +37,12 @@ const fixtureDefaultInName = [
|
|
|
36
37
|
'default my route body content'
|
|
37
38
|
]
|
|
38
39
|
|
|
40
|
+
const fixtureDelayed = [
|
|
41
|
+
'/api/delayed',
|
|
42
|
+
'api/delayed.GET.200.json',
|
|
43
|
+
'Route_To_Be_Delayed'
|
|
44
|
+
]
|
|
45
|
+
|
|
39
46
|
const fixtures = [
|
|
40
47
|
[
|
|
41
48
|
'/api',
|
|
@@ -45,6 +52,7 @@ const fixtures = [
|
|
|
45
52
|
|
|
46
53
|
// Exact route paths
|
|
47
54
|
fixtureDefaultInName,
|
|
55
|
+
fixtureDelayed,
|
|
48
56
|
[
|
|
49
57
|
'/api/the-route',
|
|
50
58
|
'api/the-route(default).GET.200.json',
|
|
@@ -135,6 +143,8 @@ writeStatic('index.html', '<h1>Static</h1>')
|
|
|
135
143
|
writeStatic('assets/app.js', 'const app = 1')
|
|
136
144
|
writeStatic('another-entry/index.html', '<h1>Another</h1>')
|
|
137
145
|
|
|
146
|
+
|
|
147
|
+
|
|
138
148
|
const server = Mockaton({
|
|
139
149
|
mocksDir: tmpDir,
|
|
140
150
|
staticDir: staticTmpDir,
|
|
@@ -151,7 +161,19 @@ const server = Mockaton({
|
|
|
151
161
|
})
|
|
152
162
|
server.on('listening', runTests)
|
|
153
163
|
|
|
164
|
+
function mockatonAddr() {
|
|
165
|
+
const { address, port } = server.address()
|
|
166
|
+
return `http://${address}:${port}`
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function request(path, options = {}) {
|
|
170
|
+
return fetch(`${mockatonAddr()}${path}`, options)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
let commander
|
|
154
174
|
async function runTests() {
|
|
175
|
+
commander = new Commander(mockatonAddr())
|
|
176
|
+
|
|
155
177
|
await testItRendersDashboard()
|
|
156
178
|
await test404()
|
|
157
179
|
|
|
@@ -160,11 +182,7 @@ async function runTests() {
|
|
|
160
182
|
|
|
161
183
|
await testDefaultMock()
|
|
162
184
|
|
|
163
|
-
await
|
|
164
|
-
'/api/alternative',
|
|
165
|
-
'api/alternative(comment-2).GET.200.json',
|
|
166
|
-
JSON.stringify({ comment: 2 }))
|
|
167
|
-
|
|
185
|
+
await testItUpdatesRouteDelay(...fixtureDelayed)
|
|
168
186
|
await testBadRequestWhenUpdatingNonExistingMockAlternative()
|
|
169
187
|
|
|
170
188
|
await testAutogenerates500(
|
|
@@ -176,14 +194,14 @@ async function runTests() {
|
|
|
176
194
|
'api/.GET.500.txt',
|
|
177
195
|
'keeps non-autogenerated 500')
|
|
178
196
|
|
|
179
|
-
await reset()
|
|
197
|
+
await commander.reset()
|
|
180
198
|
await testItUpdatesTheCurrentSelectedMock(
|
|
181
199
|
'/api/alternative',
|
|
182
200
|
'api/alternative(comment-2).GET.200.json',
|
|
183
201
|
200,
|
|
184
202
|
JSON.stringify({ comment: 2 }))
|
|
185
203
|
|
|
186
|
-
await reset()
|
|
204
|
+
await commander.reset()
|
|
187
205
|
await testExtractsAllComments([
|
|
188
206
|
'(comment-1)',
|
|
189
207
|
'(comment-2)',
|
|
@@ -197,7 +215,7 @@ async function runTests() {
|
|
|
197
215
|
['/api/my-route', 'api/my-route(comment-2).GET.200.json', { comment: 2 }]
|
|
198
216
|
])
|
|
199
217
|
|
|
200
|
-
await reset()
|
|
218
|
+
await commander.reset()
|
|
201
219
|
for (const [url, file, body] of fixtures)
|
|
202
220
|
await testMockDispatching(url, file, body)
|
|
203
221
|
|
|
@@ -212,9 +230,6 @@ async function runTests() {
|
|
|
212
230
|
server.close()
|
|
213
231
|
}
|
|
214
232
|
|
|
215
|
-
async function reset() {
|
|
216
|
-
await request(API.reset, { method: 'PATCH' })
|
|
217
|
-
}
|
|
218
233
|
|
|
219
234
|
async function testItRendersDashboard() {
|
|
220
235
|
const res = await request(API.dashboard)
|
|
@@ -259,10 +274,7 @@ async function testDefaultMock() {
|
|
|
259
274
|
}
|
|
260
275
|
|
|
261
276
|
async function testItUpdatesTheCurrentSelectedMock(url, file, expectedStatus, expectedBody) {
|
|
262
|
-
await
|
|
263
|
-
method: 'PATCH',
|
|
264
|
-
body: JSON.stringify({ [DF.file]: file })
|
|
265
|
-
})
|
|
277
|
+
await commander.select(file)
|
|
266
278
|
const res = await request(url)
|
|
267
279
|
const body = await res.text()
|
|
268
280
|
await describe('url: ' + url, () => {
|
|
@@ -271,19 +283,14 @@ async function testItUpdatesTheCurrentSelectedMock(url, file, expectedStatus, ex
|
|
|
271
283
|
})
|
|
272
284
|
}
|
|
273
285
|
|
|
274
|
-
async function
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
body: JSON.stringify({
|
|
278
|
-
[DF.file]: file,
|
|
279
|
-
[DF.delayed]: true
|
|
280
|
-
})
|
|
281
|
-
})
|
|
286
|
+
async function testItUpdatesRouteDelay(url, file, expectedBody) {
|
|
287
|
+
const { method } = parseFilename(file)
|
|
288
|
+
await commander.setRouteIsDelayed(method, url, true)
|
|
282
289
|
const now = new Date()
|
|
283
290
|
const res = await request(url)
|
|
284
291
|
const body = await res.text()
|
|
285
292
|
await describe('url: ' + url, () => {
|
|
286
|
-
it('body is: ' + expectedBody, () => equal(body, expectedBody))
|
|
293
|
+
it('body is: ' + expectedBody, () => equal(body, JSON.stringify(expectedBody)))
|
|
287
294
|
it('delay', () => equal((new Date()).getTime() - now.getTime() > Config.delay, true))
|
|
288
295
|
})
|
|
289
296
|
}
|
|
@@ -291,20 +298,14 @@ async function testItUpdatesDelayAndFile(url, file, expectedBody) {
|
|
|
291
298
|
async function testBadRequestWhenUpdatingNonExistingMockAlternative() {
|
|
292
299
|
await it('There are mocks for /api/the-route but not this one', async () => {
|
|
293
300
|
const missingFile = 'api/the-route(non-existing-variant).GET.200.json'
|
|
294
|
-
const res = await
|
|
295
|
-
method: 'PATCH',
|
|
296
|
-
body: JSON.stringify({ [DF.file]: missingFile })
|
|
297
|
-
})
|
|
301
|
+
const res = await commander.select(missingFile)
|
|
298
302
|
equal(res.status, 400)
|
|
299
303
|
equal(await res.text(), `Missing Mock: ${missingFile}`)
|
|
300
304
|
})
|
|
301
305
|
}
|
|
302
306
|
|
|
303
307
|
async function testAutogenerates500(url, file) {
|
|
304
|
-
await
|
|
305
|
-
method: 'PATCH',
|
|
306
|
-
body: JSON.stringify({ [DF.file]: file })
|
|
307
|
-
})
|
|
308
|
+
await commander.select(file)
|
|
308
309
|
const res = await request(url)
|
|
309
310
|
const body = await res.text()
|
|
310
311
|
await describe('autogenerated in-memory 500', () => {
|
|
@@ -314,10 +315,7 @@ async function testAutogenerates500(url, file) {
|
|
|
314
315
|
}
|
|
315
316
|
|
|
316
317
|
async function testPreservesExiting500(url, file, expectedBody) {
|
|
317
|
-
await
|
|
318
|
-
method: 'PATCH',
|
|
319
|
-
body: JSON.stringify({ [DF.file]: file })
|
|
320
|
-
})
|
|
318
|
+
await commander.select(file)
|
|
321
319
|
const res = await request(url)
|
|
322
320
|
const body = await res.text()
|
|
323
321
|
await describe('preserves existing 500', () => {
|
|
@@ -327,17 +325,14 @@ async function testPreservesExiting500(url, file, expectedBody) {
|
|
|
327
325
|
}
|
|
328
326
|
|
|
329
327
|
async function testExtractsAllComments(expected) {
|
|
330
|
-
const res = await
|
|
328
|
+
const res = await commander.listComments()
|
|
331
329
|
const body = await res.json()
|
|
332
330
|
await it('Extracts all comments without duplicates', () =>
|
|
333
331
|
deepEqual(body, expected))
|
|
334
332
|
}
|
|
335
333
|
|
|
336
334
|
async function testItBulkSelectsByComment(comment, tests) {
|
|
337
|
-
await
|
|
338
|
-
method: 'PATCH',
|
|
339
|
-
body: JSON.stringify(comment)
|
|
340
|
-
})
|
|
335
|
+
await commander.bulkSelectByComment(comment)
|
|
341
336
|
for (const [url, file, body] of tests)
|
|
342
337
|
await testMockDispatching(url, file, body)
|
|
343
338
|
}
|
|
@@ -346,7 +341,7 @@ async function testItBulkSelectsByComment(comment, tests) {
|
|
|
346
341
|
async function testItUpdatesUserRole() {
|
|
347
342
|
await describe('Cookie', () => {
|
|
348
343
|
it('Defaults to the first key:value', async () => {
|
|
349
|
-
const res = await
|
|
344
|
+
const res = await commander.listCookies()
|
|
350
345
|
deepEqual(await res.json(), [
|
|
351
346
|
['userA', true],
|
|
352
347
|
['userB', false]
|
|
@@ -354,11 +349,8 @@ async function testItUpdatesUserRole() {
|
|
|
354
349
|
})
|
|
355
350
|
|
|
356
351
|
it('Update the selected cookie', async () => {
|
|
357
|
-
await
|
|
358
|
-
|
|
359
|
-
body: JSON.stringify('userB')
|
|
360
|
-
})
|
|
361
|
-
const res = await request(API.cookies)
|
|
352
|
+
await commander.selectCookie('userB')
|
|
353
|
+
const res = await commander.listCookies()
|
|
362
354
|
deepEqual(await res.json(), [
|
|
363
355
|
['userA', false],
|
|
364
356
|
['userB', true]
|
|
@@ -374,7 +366,7 @@ export default function (req, response) {
|
|
|
374
366
|
response.setHeader('content-type', 'custom-mime')
|
|
375
367
|
return 'SOME_STRING'
|
|
376
368
|
}`)
|
|
377
|
-
await reset() // for registering the file
|
|
369
|
+
await commander.reset() // for registering the file
|
|
378
370
|
await testMockDispatching('/api/js-func',
|
|
379
371
|
'api/js-func.POST.200.js',
|
|
380
372
|
'SOME_STRING',
|
|
@@ -416,7 +408,7 @@ async function testInvalidFilenamesAreIgnored() {
|
|
|
416
408
|
write('api/_INVALID_FILENAME_CONVENTION_.json', '')
|
|
417
409
|
write('api/bad-filename-method._INVALID_METHOD_.200.json', '')
|
|
418
410
|
write('api/bad-filename-status.GET._INVALID_STATUS_.json', '')
|
|
419
|
-
await reset()
|
|
411
|
+
await commander.reset()
|
|
420
412
|
equal(consoleErrorSpy.mock.calls[0].arguments[0], 'Invalid Filename Convention')
|
|
421
413
|
equal(consoleErrorSpy.mock.calls[1].arguments[0], 'Unrecognized HTTP Method: "_INVALID_METHOD_"')
|
|
422
414
|
equal(consoleErrorSpy.mock.calls[2].arguments[0], 'Invalid HTTP Response Status: "NaN"')
|
|
@@ -432,10 +424,7 @@ async function testEnableFallbackSoRoutesWithoutMocksGetRelayed() {
|
|
|
432
424
|
})
|
|
433
425
|
await promisify(fallbackServer.listen).bind(fallbackServer, 0, '127.0.0.1')()
|
|
434
426
|
|
|
435
|
-
await
|
|
436
|
-
method: 'PATCH',
|
|
437
|
-
body: JSON.stringify(`http://localhost:${fallbackServer.address().port}`)
|
|
438
|
-
})
|
|
427
|
+
await commander.setProxyFallback(`http://localhost:${fallbackServer.address().port}`)
|
|
439
428
|
await it('Relays to fallback server', async () => {
|
|
440
429
|
const res = await request('/non-existing-mock')
|
|
441
430
|
equal(res.headers.get('custom_header'), 'my_custom_header')
|
|
@@ -461,8 +450,3 @@ function _write(absPath, data) {
|
|
|
461
450
|
writeFileSync(absPath, data, 'utf8')
|
|
462
451
|
}
|
|
463
452
|
|
|
464
|
-
function request(path, options = {}) {
|
|
465
|
-
const { address, port } = server.address()
|
|
466
|
-
return fetch(`http://${address}:${port}${path}`, options)
|
|
467
|
-
}
|
|
468
|
-
|
package/index.d.ts
CHANGED
|
@@ -18,6 +18,29 @@ interface Config {
|
|
|
18
18
|
onReady?: (address: string) => void
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
|
|
21
22
|
export function Mockaton(options: Config): Server
|
|
22
23
|
|
|
24
|
+
|
|
23
25
|
export function jwtCookie(cookieName: string, payload: any): string
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
export class Commander {
|
|
29
|
+
constructor(addr: string)
|
|
30
|
+
|
|
31
|
+
select(file: string): Promise<Response>
|
|
32
|
+
|
|
33
|
+
bulkSelectByComment(comment: string): Promise<Response>
|
|
34
|
+
|
|
35
|
+
setRouteIsDelayed(routeMethod: string, routeUrlMask: string, delayed: boolean): Promise<Response>
|
|
36
|
+
|
|
37
|
+
selectCookie(cookieKey: string): Promise<Response>
|
|
38
|
+
|
|
39
|
+
setProxyFallback(proxyAddr: string): Promise<Response>
|
|
40
|
+
|
|
41
|
+
reset(): Promise<Response>
|
|
42
|
+
|
|
43
|
+
listCookies(): Promise<Response>
|
|
44
|
+
|
|
45
|
+
listComments(): Promise<Response>
|
|
46
|
+
}
|
package/index.js
CHANGED
package/package.json
CHANGED
package/src/Api.js
CHANGED
|
@@ -25,7 +25,8 @@ export const apiGetRequests = new Map([
|
|
|
25
25
|
])
|
|
26
26
|
|
|
27
27
|
export const apiPatchRequests = new Map([
|
|
28
|
-
[API.
|
|
28
|
+
[API.select, selectMock],
|
|
29
|
+
[API.delay, setRouteIsDelayed],
|
|
29
30
|
[API.reset, reinitialize],
|
|
30
31
|
[API.cookies, selectCookie],
|
|
31
32
|
[API.fallback, updateProxyFallback],
|
|
@@ -45,6 +46,7 @@ function reinitialize(_, response) {
|
|
|
45
46
|
sendOK(response)
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
|
|
48
50
|
async function selectCookie(req, response) {
|
|
49
51
|
try {
|
|
50
52
|
cookie.setCurrent(await parseJSON(req))
|
|
@@ -55,16 +57,14 @@ async function selectCookie(req, response) {
|
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
|
|
60
|
+
|
|
61
|
+
async function selectMock(req, response) {
|
|
59
62
|
try {
|
|
60
|
-
const
|
|
61
|
-
const file = body[DF.file]
|
|
63
|
+
const file = await parseJSON(req)
|
|
62
64
|
const broker = mockBrokersCollection.getBrokerByFilename(file)
|
|
63
65
|
if (!broker || !broker.mockExists(file))
|
|
64
66
|
throw `Missing Mock: ${file}`
|
|
65
67
|
|
|
66
|
-
if (DF.delayed in body)
|
|
67
|
-
broker.updateDelay(body[DF.delayed])
|
|
68
68
|
broker.updateFile(file)
|
|
69
69
|
sendOK(response)
|
|
70
70
|
}
|
|
@@ -73,6 +73,26 @@ async function updateBroker(req, response) {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
|
|
77
|
+
async function setRouteIsDelayed(req, response) {
|
|
78
|
+
try {
|
|
79
|
+
const body = await parseJSON(req)
|
|
80
|
+
const broker = mockBrokersCollection.getBrokerForUrl(
|
|
81
|
+
body[DF.routeMethod],
|
|
82
|
+
body[DF.routeUrlMask])
|
|
83
|
+
|
|
84
|
+
if (!broker)
|
|
85
|
+
throw `Route does not exist: ${body[DF.routeUrlMask]} ${body[DF.routeUrlMask]}`
|
|
86
|
+
|
|
87
|
+
broker.updateDelay(body[DF.delayed])
|
|
88
|
+
sendOK(response)
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
sendBadRequest(response, error)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
76
96
|
async function updateProxyFallback(req, response) {
|
|
77
97
|
try {
|
|
78
98
|
Config.proxyFallback = await parseJSON(req)
|
|
@@ -83,6 +103,7 @@ async function updateProxyFallback(req, response) {
|
|
|
83
103
|
}
|
|
84
104
|
}
|
|
85
105
|
|
|
106
|
+
|
|
86
107
|
async function bulkUpdateBrokersByCommentTag(req, response) {
|
|
87
108
|
try {
|
|
88
109
|
mockBrokersCollection.setMocksMatchingComment(await parseJSON(req))
|
package/src/ApiConstants.js
CHANGED
|
@@ -3,7 +3,8 @@ export const API = {
|
|
|
3
3
|
dashboard: MOUNT,
|
|
4
4
|
bulkSelect: MOUNT + '/bulk-select-by-comment',
|
|
5
5
|
comments: MOUNT + '/comments',
|
|
6
|
-
|
|
6
|
+
select: MOUNT + '/select',
|
|
7
|
+
delay: MOUNT + '/delay',
|
|
7
8
|
mocks: MOUNT + '/mocks',
|
|
8
9
|
reset: MOUNT + '/reset',
|
|
9
10
|
cookies: MOUNT + '/cookies',
|
|
@@ -11,8 +12,9 @@ export const API = {
|
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export const DF = { // Dashboard Fields (XHR)
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
routeMethod: 'route_method',
|
|
16
|
+
routeUrlMask: 'route_url_mask',
|
|
17
|
+
delayed: 'delayed'
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
export const DEFAULT_500_COMMENT = '(Mockaton 500)'
|
package/src/Commander.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { API, DF } from './ApiConstants.js'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export class Commander {
|
|
5
|
+
#addr = ''
|
|
6
|
+
constructor(addr) {
|
|
7
|
+
this.#addr = addr
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
select(file) {
|
|
11
|
+
return this.#patch(API.select, file)
|
|
12
|
+
}
|
|
13
|
+
bulkSelectByComment(comment) {
|
|
14
|
+
return this.#patch(API.bulkSelect, comment)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
setRouteIsDelayed(routeMethod, routeUrlMask, delayed) {
|
|
18
|
+
return this.#patch(API.delay, {
|
|
19
|
+
[DF.routeMethod]: routeMethod,
|
|
20
|
+
[DF.routeUrlMask]: routeUrlMask,
|
|
21
|
+
[DF.delayed]: delayed
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
listCookies() {
|
|
26
|
+
return this.#get(API.cookies)
|
|
27
|
+
}
|
|
28
|
+
selectCookie(cookieKey) {
|
|
29
|
+
return this.#patch(API.cookies, cookieKey)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
listComments() {
|
|
33
|
+
return this.#get(API.comments)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
setProxyFallback(proxyAddr) {
|
|
37
|
+
return this.#patch(API.fallback, proxyAddr)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
reset() {
|
|
41
|
+
return this.#patch(API.reset)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
#get(api) {
|
|
46
|
+
return fetch(this.#addr + api)
|
|
47
|
+
}
|
|
48
|
+
#patch(api, body) {
|
|
49
|
+
return fetch(this.#addr + api, {
|
|
50
|
+
method: 'PATCH',
|
|
51
|
+
body: JSON.stringify(body)
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
}
|
package/src/Dashboard.js
CHANGED
|
@@ -133,7 +133,7 @@ function SectionByMethod({ method, brokers }) {
|
|
|
133
133
|
r('tr', null,
|
|
134
134
|
r('td', null, r(PreviewLink, { method, urlMask })),
|
|
135
135
|
r('td', null, r(MockSelector, { broker })),
|
|
136
|
-
r('td', null, r(
|
|
136
|
+
r('td', null, r(DelayRouteToggler, { broker })),
|
|
137
137
|
r('td', null, r(InternalServerErrorToggler, { broker }))
|
|
138
138
|
))))
|
|
139
139
|
}
|
|
@@ -188,9 +188,9 @@ function MockSelector({ broker }) {
|
|
|
188
188
|
this.style.fontWeight = this.value === this.options[0].value // default is selected
|
|
189
189
|
? 'normal'
|
|
190
190
|
: 'bold'
|
|
191
|
-
fetch(API.
|
|
191
|
+
fetch(API.select, {
|
|
192
192
|
method: 'PATCH',
|
|
193
|
-
body: JSON.stringify(
|
|
193
|
+
body: JSON.stringify(this.value)
|
|
194
194
|
})
|
|
195
195
|
.then(() => {
|
|
196
196
|
this.closest('tr').querySelector('a').click()
|
|
@@ -205,7 +205,7 @@ function MockSelector({ broker }) {
|
|
|
205
205
|
}, file))))
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
-
function
|
|
208
|
+
function DelayRouteToggler({ broker }) {
|
|
209
209
|
const name = broker.currentMock.file
|
|
210
210
|
const checked = Boolean(broker.currentMock.delay)
|
|
211
211
|
return (
|
|
@@ -219,10 +219,12 @@ function DelayToggler({ broker }) {
|
|
|
219
219
|
name,
|
|
220
220
|
checked,
|
|
221
221
|
onChange(event) {
|
|
222
|
-
|
|
222
|
+
const { method, urlMask } = parseFilename(this.name)
|
|
223
|
+
fetch(API.delay, {
|
|
223
224
|
method: 'PATCH',
|
|
224
225
|
body: JSON.stringify({
|
|
225
|
-
[DF.
|
|
226
|
+
[DF.routeMethod]: method,
|
|
227
|
+
[DF.routeUrlMask]: urlMask,
|
|
226
228
|
[DF.delayed]: event.currentTarget.checked
|
|
227
229
|
})
|
|
228
230
|
})
|
|
@@ -252,13 +254,11 @@ function InternalServerErrorToggler({ broker }) {
|
|
|
252
254
|
name,
|
|
253
255
|
checked,
|
|
254
256
|
onChange(event) {
|
|
255
|
-
fetch(API.
|
|
257
|
+
fetch(API.select, {
|
|
256
258
|
method: 'PATCH',
|
|
257
|
-
body: JSON.stringify(
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
: items[0]
|
|
261
|
-
})
|
|
259
|
+
body: JSON.stringify(event.currentTarget.checked
|
|
260
|
+
? items.find(f => parseFilename(f).status === 500)
|
|
261
|
+
: items[0])
|
|
262
262
|
})
|
|
263
263
|
.then(init)
|
|
264
264
|
.catch(console.error)
|
package/src/Mockaton.js
CHANGED
|
@@ -11,31 +11,33 @@ import { apiPatchRequests, apiGetRequests } from './Api.js'
|
|
|
11
11
|
export function Mockaton(options) {
|
|
12
12
|
setup(options)
|
|
13
13
|
mockBrokerCollection.init()
|
|
14
|
+
const server = createServer(onRequest)
|
|
15
|
+
server.listen(Config.port, Config.host, (error) => {
|
|
16
|
+
const { address, port } = server.address()
|
|
17
|
+
const url = `http://${address}:${port}`
|
|
18
|
+
console.log('Listening', url)
|
|
19
|
+
console.log('Dashboard', url + API.dashboard)
|
|
20
|
+
if (error)
|
|
21
|
+
console.error(error)
|
|
22
|
+
else
|
|
23
|
+
Config.onReady(url + API.dashboard)
|
|
24
|
+
})
|
|
25
|
+
return server
|
|
26
|
+
}
|
|
14
27
|
|
|
15
|
-
|
|
16
|
-
|
|
28
|
+
async function onRequest(req, response) {
|
|
29
|
+
response.setHeader('Server', 'Mockaton')
|
|
17
30
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
31
|
+
const { url, method } = req
|
|
32
|
+
if (method === 'GET' && apiGetRequests.has(url))
|
|
33
|
+
apiGetRequests.get(url)(req, response)
|
|
21
34
|
|
|
22
|
-
|
|
23
|
-
|
|
35
|
+
else if (method === 'PATCH' && apiPatchRequests.has(url))
|
|
36
|
+
await apiPatchRequests.get(url)(req, response)
|
|
24
37
|
|
|
25
|
-
|
|
26
|
-
|
|
38
|
+
else if (isStatic(req))
|
|
39
|
+
await dispatchStatic(req, response)
|
|
27
40
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
})
|
|
31
|
-
.listen(Config.port, Config.host, function (error) {
|
|
32
|
-
const { address, port } = this.address()
|
|
33
|
-
const url = `http://${address}:${port}`
|
|
34
|
-
console.log('Listening', url)
|
|
35
|
-
console.log('Dashboard', url + API.dashboard)
|
|
36
|
-
if (error)
|
|
37
|
-
console.error(error)
|
|
38
|
-
else
|
|
39
|
-
Config.onReady(url + API.dashboard)
|
|
40
|
-
})
|
|
41
|
+
else
|
|
42
|
+
await dispatchMock(req, response)
|
|
41
43
|
}
|