mockaton 6.4.5 → 6.4.7

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.
Binary file
package/README.md CHANGED
@@ -12,35 +12,41 @@ my-mocks-dir/api/user/[user-id].GET.200.json
12
12
  [This browser extension](https://github.com/ericfortis/devtools-ext-tar-http-requests)
13
13
  can be used for downloading a TAR of your XHR requests following that convention.
14
14
 
15
- ## What do I use Mockaton for?
15
+ ## What do I use it for?
16
16
  - I’m a frontend dev, so I don’t have to spin up and maintain hefty or complex backends.
17
- - For a deterministic and comprehensive state. Having all the possible
18
- state variants at once lets me visually spot inadvertent bugs right away.
17
+ - For a deterministic and comprehensive backend state. For example, having all the possible
18
+ state variants of a particular collection helps for spotting inadvertent bugs. And having those
19
+ assorted responses are not easy to trigger from the backend.
19
20
  - Testing empty responses.
20
21
  - Testing spinners by delaying responses.
21
- - Triggering errors such as Bad Request and Internal Server Error.
22
+ - Testing errors such as _Bad Request_ and _Internal Server Error_.
22
23
  - Triggering notifications and alerts.
23
- - As check-in the mocks in the repo, when bisecting a bug, I don’t
24
+ - Prototyping before the backend API is developed.
25
+ - Setting up tests.
26
+ - If you commit the mocks in the repo, when bisecting a bug, you don’t
24
27
  have to sync the frontend with many backend repos.
25
28
  - Similarly, I can check out long-lived branches that have old API contracts.
26
- - Prototyping before the backend API is developed.
27
29
  - As API documentation.
28
- - Setting up tests.
29
30
 
30
31
  ## Alternatives
31
32
  - Chrome DevTools allows for [overriding responses](https://developer.chrome.com/docs/devtools/overrides)
32
33
  - Reverse Proxies such as [Burp](https://portswigger.net/burp) are also handy for overriding responses.
33
- - [Storybook](https://storybook.js.org)
34
+ - Storybook’s [MSW](https://storybook.js.org/addons/msw-storybook-addon)
34
35
 
35
36
  ### Caveats
36
- - Syncing the mocks. The browser extension mentioned above helps.
37
+ - Syncing the mocks, but the browser extension mentioned above helps.
37
38
 
38
39
 
39
40
  ## Getting Started
40
41
  The best way to learn _Mockaton_ is by checking out this repo and
41
42
  exploring its [sample-mocks/](./sample-mocks) directory. Then, run
42
- [`./_usage_example.js`](./_usage_example.js) and you’ll see this dashboard:
43
+ [`./_usage_example.js`](./_usage_example.js) and you’ll see the dashboard.
44
+
45
+ You can edit mock files without resetting Mockaton. The _Reset_
46
+ button is for when you add, remove, or rename a mock file.
43
47
 
48
+ The dropdown lets you pick a mock variant, details in the next section. Next to it is a
49
+ _Delay_ toggler, and a button for sending _500 - Internal Server Error_ on that endpoint.
44
50
 
45
51
  <img src="./README-dashboard.png" style="max-width:820px"/>
46
52
 
package/Tests.js CHANGED
@@ -165,7 +165,7 @@ async function runTests() {
165
165
  'api/alternative(comment-2).GET.200.json',
166
166
  JSON.stringify({ comment: 2 }))
167
167
 
168
- await test422WhenUpdatingNonExistingMockAlternative()
168
+ await testBadRequestWhenUpdatingNonExistingMockAlternative()
169
169
 
170
170
  await testAutogenerates500(
171
171
  '/api/alternative',
@@ -288,13 +288,15 @@ async function testItUpdatesDelayAndFile(url, file, expectedBody) {
288
288
  })
289
289
  }
290
290
 
291
- async function test422WhenUpdatingNonExistingMockAlternative() {
291
+ async function testBadRequestWhenUpdatingNonExistingMockAlternative() {
292
292
  await it('There are mocks for /api/the-route but not this one', async () => {
293
+ const missingFile = 'api/the-route(non-existing-variant).GET.200.json'
293
294
  const res = await request(API.edit, {
294
295
  method: 'PATCH',
295
- body: JSON.stringify({ [DF.file]: 'api/the-route(non-existing-variant).GET.200.json' })
296
+ body: JSON.stringify({ [DF.file]: missingFile })
296
297
  })
297
- equal(res.status, 422)
298
+ equal(res.status, 400)
299
+ equal(await res.text(), `Missing Mock: ${missingFile}`)
298
300
  })
299
301
  }
300
302
 
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.4.5",
5
+ "version": "6.4.7",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "license": "MIT",
package/src/Api.js CHANGED
@@ -9,7 +9,7 @@ import { Config } from './Config.js'
9
9
  import { DF, API } from './ApiConstants.js'
10
10
  import { parseJSON } from './utils/http-request.js'
11
11
  import * as mockBrokersCollection from './mockBrokersCollection.js'
12
- import { sendOK, sendBadRequest, sendJSON, sendFile, sendUnprocessableContent } from './utils/http-response.js'
12
+ import { sendOK, sendBadRequest, sendJSON, sendFile } from './utils/http-response.js'
13
13
 
14
14
 
15
15
  export const apiGetRequests = new Map([
@@ -60,10 +60,9 @@ async function updateBroker(req, response) {
60
60
  const body = await parseJSON(req)
61
61
  const file = body[DF.file]
62
62
  const broker = mockBrokersCollection.getBrokerByFilename(file)
63
- if (!broker || !broker.mockExists(file)) {
64
- sendUnprocessableContent(response, `Missing Mock: ${file}`)
65
- return
66
- }
63
+ if (!broker || !broker.mockExists(file))
64
+ throw `Missing Mock: ${file}`
65
+
67
66
  if (DF.delayed in body)
68
67
  broker.updateDelay(body[DF.delayed])
69
68
  broker.updateFile(file)
@@ -1,5 +1,5 @@
1
1
  import { join } from 'node:path'
2
- import { readFileSync } from 'node:fs'
2
+ import { readFileSync as read } from 'node:fs'
3
3
 
4
4
  import { proxy } from './ProxyRelay.js'
5
5
  import { cookie } from './cookie.js'
@@ -11,34 +11,40 @@ import { sendInternalServerError, sendNotFound, sendBadRequest } from './utils/h
11
11
 
12
12
 
13
13
  export async function dispatchMock(req, response) {
14
- const broker = mockBrokerCollection.getBrokerForUrl(req.method, req.url)
15
- if (!broker) {
16
- if (Config.proxyFallback)
17
- await proxy(req, response)
18
- else
19
- sendNotFound(response)
20
- return
21
- }
22
-
23
14
  try {
15
+ const broker = mockBrokerCollection.getBrokerForUrl(req.method, req.url)
16
+ if (!broker) {
17
+ if (Config.proxyFallback)
18
+ await proxy(req, response)
19
+ else
20
+ sendNotFound(response)
21
+ return
22
+ }
23
+
24
24
  const { file, status, delay } = broker
25
25
  console.log(decodeURIComponent(req.url), ' → ', file)
26
+ const filePath = join(Config.mocksDir, file)
26
27
 
27
- let mockText
28
+ let mockBody
28
29
  if (file.endsWith('.js')) {
29
30
  response.setHeader('Content-Type', mimeFor('.json'))
30
- mockText = await jsMockText(file, req, response)
31
+ const jsExport = (await import(filePath + '?' + Date.now())).default // date for cache busting
32
+ mockBody = typeof jsExport === 'function'
33
+ ? await jsExport(req, response)
34
+ : JSON.stringify(jsExport, null, 2)
31
35
  }
32
36
  else {
33
37
  response.setHeader('Content-Type', mimeFor(file))
34
- mockText = broker.isTemp500 ? '' : readMock(file)
38
+ mockBody = broker.isTemp500
39
+ ? ''
40
+ : read(filePath)
35
41
  }
36
-
42
+
37
43
  if (cookie.getCurrent())
38
44
  response.setHeader('Set-Cookie', cookie.getCurrent())
39
45
 
40
46
  response.writeHead(status, Config.extraHeaders)
41
- setTimeout(() => response.end(mockText), delay)
47
+ setTimeout(() => response.end(mockBody), delay)
42
48
  }
43
49
  catch (error) {
44
50
  if (error instanceof JsonBodyParserError)
@@ -49,19 +55,3 @@ export async function dispatchMock(req, response) {
49
55
  sendInternalServerError(response, error)
50
56
  }
51
57
  }
52
-
53
- async function jsMockText(file, req, response) {
54
- const jsExport = await importDefault(file)
55
- return typeof jsExport === 'function'
56
- ? await jsExport(req, response)
57
- : JSON.stringify(jsExport, null, 2)
58
- }
59
-
60
- function readMock(file) {
61
- return readFileSync(join(Config.mocksDir, file))
62
- }
63
-
64
- async function importDefault(file) {
65
- // The date param is just for cache busting
66
- return (await import(join(Config.mocksDir, file) + '?' + Date.now())).default
67
- }
@@ -51,7 +51,7 @@ export async function sendPartialContent(response, range, file) {
51
51
  export function sendBadRequest(response, error) {
52
52
  console.error(error)
53
53
  response.statusCode = 400
54
- response.end()
54
+ response.end(error)
55
55
  }
56
56
 
57
57
  export function sendNotFound(response) {
@@ -59,12 +59,6 @@ export function sendNotFound(response) {
59
59
  response.end()
60
60
  }
61
61
 
62
- export function sendUnprocessableContent(response, error) {
63
- console.error(error)
64
- response.statusCode = 422
65
- response.end()
66
- }
67
-
68
62
  export function sendInternalServerError(response, error) {
69
63
  console.error(error)
70
64
  response.statusCode = 500