mockaton 8.3.0 → 8.3.2
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 +8 -8
- package/TODO.md +7 -0
- package/package.json +1 -1
- package/src/MockDispatcher.js +2 -2
- package/src/Mockaton.test.js +17 -7
- package/src/ProxyRelay.js +9 -3
- package/src/utils/http-request.js +6 -5
- package/src/utils/mime.js +5 -11
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ import { Mockaton } from 'mockaton'
|
|
|
51
51
|
|
|
52
52
|
// See the Config section for more options
|
|
53
53
|
Mockaton({
|
|
54
|
-
mocksDir: resolve('my-mocks-dir'),
|
|
54
|
+
mocksDir: resolve('my-mocks-dir'), // must exist
|
|
55
55
|
port: 2345
|
|
56
56
|
})
|
|
57
57
|
```
|
|
@@ -296,9 +296,13 @@ On the other hand, newly saved mocks get overwritten while they are unregistered
|
|
|
296
296
|
<details>
|
|
297
297
|
<summary>Extension Details</summary>
|
|
298
298
|
<p>
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
299
|
+
An <code>.empty</code> extension means the <code>Content-Type</code>
|
|
300
|
+
header was not sent by your backend.
|
|
301
|
+
</p>
|
|
302
|
+
|
|
303
|
+
<p>
|
|
304
|
+
An <code>.unknown</code> extension means the <code>Content-Type</code> is not in
|
|
305
|
+
Mockaton’s predefined list. For that, you can add it to <code>config.extraMimes</code>
|
|
302
306
|
</p>
|
|
303
307
|
</details>
|
|
304
308
|
|
|
@@ -494,7 +498,3 @@ await mockaton.reset()
|
|
|
494
498
|
<img src="./sample-mocks/api/user/avatar.GET.200.png" width="170"/>
|
|
495
499
|
<p style="font-size: 18px">“Use Mockaton”</p>
|
|
496
500
|
</div>
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
## TODO
|
|
500
|
-
- Refactor Tests
|
package/TODO.md
ADDED
package/package.json
CHANGED
package/src/MockDispatcher.js
CHANGED
|
@@ -5,7 +5,7 @@ import { cookie } from './cookie.js'
|
|
|
5
5
|
import { Config } from './Config.js'
|
|
6
6
|
import { applyPlugins } from './MockDispatcherPlugins.js'
|
|
7
7
|
import * as mockBrokerCollection from './mockBrokersCollection.js'
|
|
8
|
-
import {
|
|
8
|
+
import { BodyReaderError } from './utils/http-request.js'
|
|
9
9
|
import { sendInternalServerError, sendNotFound, sendBadRequest } from './utils/http-response.js'
|
|
10
10
|
|
|
11
11
|
|
|
@@ -37,7 +37,7 @@ export async function dispatchMock(req, response) {
|
|
|
37
37
|
setTimeout(() => response.end(body), broker.delay)
|
|
38
38
|
}
|
|
39
39
|
catch (error) {
|
|
40
|
-
if (error instanceof
|
|
40
|
+
if (error instanceof BodyReaderError)
|
|
41
41
|
sendBadRequest(response, error)
|
|
42
42
|
else if (error.code === 'ENOENT') // mock-file has been deleted
|
|
43
43
|
sendNotFound(response)
|
package/src/Mockaton.test.js
CHANGED
|
@@ -9,6 +9,7 @@ import { writeFileSync, mkdtempSync, mkdirSync } from 'node:fs'
|
|
|
9
9
|
import { Config } from './Config.js'
|
|
10
10
|
import { mimeFor } from './utils/mime.js'
|
|
11
11
|
import { Mockaton } from './Mockaton.js'
|
|
12
|
+
import { readBody } from './utils/http-request.js'
|
|
12
13
|
import { Commander } from './Commander.js'
|
|
13
14
|
import { parseFilename } from './Filename.js'
|
|
14
15
|
import { CorsHeader } from './utils/http-cors.js'
|
|
@@ -421,19 +422,28 @@ async function testInvalidFilenamesAreIgnored() {
|
|
|
421
422
|
|
|
422
423
|
async function testEnableFallbackSoRoutesWithoutMocksGetRelayed() {
|
|
423
424
|
await describe('Fallback', async () => {
|
|
424
|
-
const fallbackServer = createServer((
|
|
425
|
-
response.
|
|
426
|
-
|
|
427
|
-
|
|
425
|
+
const fallbackServer = createServer(async (req, response) => {
|
|
426
|
+
response.writeHead(423, {
|
|
427
|
+
'custom_header': 'my_custom_header',
|
|
428
|
+
'set-cookie': [
|
|
429
|
+
'cookieA=A',
|
|
430
|
+
'cookieB=B'
|
|
431
|
+
]
|
|
432
|
+
})
|
|
433
|
+
response.end(await readBody(req)) // echoes they req body payload
|
|
428
434
|
})
|
|
429
435
|
await promisify(fallbackServer.listen).bind(fallbackServer, 0, '127.0.0.1')()
|
|
430
436
|
|
|
431
437
|
await commander.setProxyFallback(`http://localhost:${fallbackServer.address().port}`)
|
|
432
438
|
await it('Relays to fallback server', async () => {
|
|
433
|
-
const res = await request('/non-existing-mock'
|
|
434
|
-
|
|
439
|
+
const res = await request('/non-existing-mock', {
|
|
440
|
+
method: 'POST',
|
|
441
|
+
body: 'text_body'
|
|
442
|
+
})
|
|
435
443
|
equal(res.status, 423)
|
|
436
|
-
equal(
|
|
444
|
+
equal(res.headers.get('custom_header'), 'my_custom_header')
|
|
445
|
+
equal(res.headers.get('set-cookie'), ['cookieA=A', 'cookieB=B'].join(', '))
|
|
446
|
+
equal(await res.text(), 'text_body')
|
|
437
447
|
fallbackServer.close()
|
|
438
448
|
})
|
|
439
449
|
})
|
package/src/ProxyRelay.js
CHANGED
|
@@ -2,16 +2,22 @@ import { join } from 'node:path'
|
|
|
2
2
|
import { write } from './utils/fs.js'
|
|
3
3
|
import { Config } from './Config.js'
|
|
4
4
|
import { extFor } from './utils/mime.js'
|
|
5
|
+
import { readBody } from './utils/http-request.js'
|
|
5
6
|
import { makeMockFilename } from './Filename.js'
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
export async function proxy(req, response) {
|
|
9
10
|
const proxyResponse = await fetch(Config.proxyFallback + req.url, {
|
|
10
11
|
method: req.method,
|
|
11
|
-
headers: req.headers
|
|
12
|
+
headers: req.headers,
|
|
13
|
+
body: req.method === 'GET' || req.method === 'HEAD'
|
|
14
|
+
? undefined
|
|
15
|
+
: await readBody(req)
|
|
12
16
|
})
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
|
|
18
|
+
const headers = Object.fromEntries(proxyResponse.headers)
|
|
19
|
+
headers['set-cookie'] = proxyResponse.headers.getSetCookie() // parses multiple into an array
|
|
20
|
+
response.writeHead(proxyResponse.status, headers)
|
|
15
21
|
const body = await proxyResponse.text()
|
|
16
22
|
response.end(body)
|
|
17
23
|
|
|
@@ -3,10 +3,11 @@ export const StandardMethods = [
|
|
|
3
3
|
'HEAD', 'OPTIONS', 'TRACE', 'CONNECT'
|
|
4
4
|
]
|
|
5
5
|
|
|
6
|
+
export class BodyReaderError extends Error {}
|
|
6
7
|
|
|
7
|
-
export
|
|
8
|
+
export const parseJSON = req => readBody(req, JSON.parse)
|
|
8
9
|
|
|
9
|
-
export function
|
|
10
|
+
export function readBody(req, parser = a => a) {
|
|
10
11
|
return new Promise((resolve, reject) => {
|
|
11
12
|
const MAX_BODY_SIZE = 200 * 1024
|
|
12
13
|
const expectedLength = req.headers['content-length'] | 0
|
|
@@ -29,13 +30,13 @@ export function parseJSON(req) {
|
|
|
29
30
|
req.removeListener('end', onEnd)
|
|
30
31
|
req.removeListener('error', onEnd)
|
|
31
32
|
if (lengthSoFar !== expectedLength)
|
|
32
|
-
reject(new
|
|
33
|
+
reject(new BodyReaderError())
|
|
33
34
|
else
|
|
34
35
|
try {
|
|
35
|
-
resolve(
|
|
36
|
+
resolve(parser(Buffer.concat(body).toString()))
|
|
36
37
|
}
|
|
37
38
|
catch (_) {
|
|
38
|
-
reject(new
|
|
39
|
+
reject(new BodyReaderError())
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
})
|
package/src/utils/mime.js
CHANGED
|
@@ -89,19 +89,13 @@ const mimes = {
|
|
|
89
89
|
|
|
90
90
|
export function mimeFor(filename) {
|
|
91
91
|
const ext = filename.replace(/.*\./, '').toLowerCase()
|
|
92
|
-
|
|
93
|
-
if (!mime)
|
|
94
|
-
console.info(`Missing MIME for ${filename}`)
|
|
95
|
-
return mime
|
|
92
|
+
return Config.extraMimes[ext] || mimes[ext] || ''
|
|
96
93
|
}
|
|
97
94
|
|
|
98
95
|
export function extFor(mime) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return EXT_FOR_UNKNOWN_MIME
|
|
103
|
-
}
|
|
104
|
-
return ext
|
|
96
|
+
return mime
|
|
97
|
+
? findExt(mime)
|
|
98
|
+
: 'empty'
|
|
105
99
|
}
|
|
106
100
|
|
|
107
101
|
function findExt(targetMime) {
|
|
@@ -111,5 +105,5 @@ function findExt(targetMime) {
|
|
|
111
105
|
for (const [ext, mime] of Object.entries(mimes))
|
|
112
106
|
if (targetMime === mime)
|
|
113
107
|
return ext
|
|
114
|
-
return
|
|
108
|
+
return EXT_FOR_UNKNOWN_MIME
|
|
115
109
|
}
|