mockaton 6.4.1 → 6.4.4

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
@@ -8,9 +8,31 @@ example, the following file will be served for `/api/user/1234`
8
8
  my-mocks-dir/api/user/[user-id].GET.200.json
9
9
  ```
10
10
 
11
- By the way, [this browser
12
- extension](https://github.com/ericfortis/devtools-ext-tar-http-requests) can
13
- be used for downloading a TAR of your XHR requests following that convention.
11
+ [This browser extension](https://github.com/ericfortis/devtools-ext-tar-http-requests)
12
+ can be used for downloading a TAR of your XHR requests following that convention.
13
+
14
+ ## What do I use Mockaton for?
15
+ - I’m a frontend dev, so I don’t have to spin up and maintain hefty or complex backends.
16
+ - For a deterministic and comprehensive state. Having all the possible
17
+ state variants at once lets me visually spot inadvertent bugs right away.
18
+ - Testing empty responses.
19
+ - Testing spinners by delaying responses.
20
+ - Triggering errors such as Bad Request and Internal Server Error.
21
+ - Triggering notifications and alerts.
22
+ - As check-in the mocks in the repo, when bisecting a bug, I don’t
23
+ have to sync the frontend with many backend repos.
24
+ - Similarly, I can check out long-lived branches that have old API contracts.
25
+ - Prototyping before the backend API is developed.
26
+ - As API documentation.
27
+ - Setting up tests.
28
+
29
+ ## Alternatives
30
+ - Chrome DevTools allows for [overriding responses](https://developer.chrome.com/docs/devtools/overrides)
31
+ - Reverse Proxies such as [Burp](https://portswigger.net/burp) are also handy for overriding responses.
32
+ - [Storybook](https://storybook.js.org)
33
+
34
+ ### Caveats
35
+ - Syncing the mocks. The browser extension mentioned above helps.
14
36
 
15
37
 
16
38
  ## Getting Started
@@ -45,22 +67,23 @@ node my-mockaton.js
45
67
  ```ts
46
68
  interface Config {
47
69
  mocksDir: string
48
- ignore?: RegExp // defaults to /(\.DS_Store|~)$/
70
+ ignore?: RegExp // Defaults to /(\.DS_Store|~)$/
49
71
 
50
- staticDir?: string
72
+ staticDir?: string // These files don’t use the mock-filename convention
51
73
 
52
- host?: string, // defaults to 'localhost'
53
- port?: number // defaults to 0, which means auto-assigned
74
+ host?: string, // Defaults to 'localhost'
75
+ port?: number // Defaults to 0, which means auto-assigned
54
76
  proxyFallback?: string // e.g. http://localhost:9999 Target for relaying routes without mocks
55
77
 
56
- delay?: number // defaults to 1200 (ms)
78
+ delay?: number // Defaults to 1200 (ms)
57
79
  cookies?: { [label: string]: string }
58
80
  extraMimes?: { [fileExt: string]: string }
59
81
  extraHeaders?: []
60
82
 
61
- onReady?: (dashboardUrl: string) => void // defaults to trying to open macOS default browser. pass a noop to prevent opening the dashboard
83
+ onReady?: (dashboardUrl: string) => void // Defaults to trying to open macOS and Win default browser.
62
84
  }
63
85
  ```
86
+ There’s a Config section below with more details.
64
87
 
65
88
  ---
66
89
 
@@ -78,7 +101,6 @@ You can add the comment: `(default)` to a filename.
78
101
  Otherwise, the first file in **alphabetical order** wins.
79
102
 
80
103
  ```
81
- api/user(some comment).GET.200.json
82
104
  api/user(default).GET.200.json
83
105
  ```
84
106
 
@@ -112,18 +134,6 @@ export default function optionalName(request, response) {
112
134
  ```
113
135
 
114
136
 
115
- ## Proxying Routes
116
- `Config.proxyFallback` lets you specify a target
117
- server for serving routes you don’t have mocks for.
118
-
119
-
120
- ## Delay 🕓
121
- The clock icon next to the mock selector is a checkbox for delaying a
122
- particular response. They are handy for testing spinners.
123
-
124
- The delay is globally configurable via `Config.delay = 1200` (milliseconds).
125
-
126
-
127
137
  ## File Name Convention
128
138
 
129
139
 
@@ -174,6 +184,29 @@ api/foo.GET.200.json
174
184
  api/foo/.GET.200.json
175
185
  ```
176
186
 
187
+ ---
188
+
189
+
190
+ ## `Config.proxyFallback`
191
+ Lets you specify a target server for serving routes you don’t have mocks for.
192
+
193
+
194
+ ## `Config.delay` 🕓
195
+ The clock icon next to the mock selector is a checkbox for delaying a
196
+ particular response. They are handy for testing spinners.
197
+
198
+ The delay is globally configurable via `Config.delay = 1200` (milliseconds).
199
+
200
+
201
+ ## `Config.staticDir`
202
+ These files don’t use the mock filename convention. They take precedence
203
+ over mocks. Also, they get served on the same address, so no CORS issues.
204
+
205
+ Use Case 1: If you have a bunch of static assets you don’t want to add `.GET.200.ext`
206
+
207
+ Use Case 2: For a standalone demo server. For example,
208
+ build your frontend bundle, and serve it from Mockaton.
209
+
177
210
 
178
211
  ## `Config.cookies`
179
212
  The selected cookie is sent in every response in the `Set-Cookie` header.
@@ -219,6 +252,33 @@ Config.extraMimes = {
219
252
  }
220
253
  ```
221
254
 
255
+ ## `Config.onReady`
256
+ This is a callback `(dashboardAddress: string) => void`, which defaults to
257
+ trying to open the dashboard in your default browser in macOS and Windows.
258
+
259
+ If you don’t want to open a browser, pass a noop, such as
260
+ ```js
261
+ Config.onReady = () => {}
262
+ ```
263
+
264
+ On Linux, you could pass:
265
+ ```js
266
+ import { exec } from 'node:child_process'
267
+
268
+
269
+ Config.onReady = function openInBrowser(address) {
270
+ exec(`xdg-open ${address}`)
271
+ }
272
+ ```
273
+
274
+ Or, for more cross-platform utility, you could `npm install open` and pass it.
275
+ ```js
276
+ import open from 'open'
277
+
278
+
279
+ Config.onReady = open
280
+ ```
281
+
222
282
  ---
223
283
 
224
284
  ## API
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.1",
5
+ "version": "6.4.4",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "license": "MIT",
@@ -15,5 +15,5 @@ export const DF = { // Dashboard Fields (XHR)
15
15
  file: 'file'
16
16
  }
17
17
 
18
- export const DEFAULT_500_COMMENT = '(Mockaton Temp 500)'
18
+ export const DEFAULT_500_COMMENT = '(Mockaton 500)'
19
19
  export const DEFAULT_MOCK_COMMENT = '(default)'
package/src/Config.js CHANGED
@@ -21,6 +21,7 @@ export const Config = Object.seal({
21
21
  onReady: openInBrowser
22
22
  })
23
23
 
24
+
24
25
  export function setup(options) {
25
26
  Object.assign(Config, options)
26
27
  validate(Config, {
package/src/Filename.js CHANGED
@@ -4,7 +4,6 @@ const httpMethods = [
4
4
  'POST', 'PUT', 'TRACE'
5
5
  ]
6
6
 
7
-
8
7
  const reComments = /\(.*?\)/g // Anything within parentheses
9
8
 
10
9
  export const extractComments = filename =>
@@ -20,21 +19,18 @@ export function filenameIsValid(file) {
20
19
  console.error(error, file)
21
20
  return !error
22
21
  }
23
-
24
22
  function validateFilename(file) {
25
23
  const tokens = file.replace(reComments, '').split('.')
26
24
  if (tokens.length < 4)
27
25
  return 'Invalid Filename Convention'
28
-
29
26
  const { status, method } = parseFilename(file)
30
-
31
27
  if (!responseStatusIsValid(status))
32
28
  return `Invalid HTTP Response Status: "${status}"`
33
-
34
29
  if (!httpMethods.includes(method))
35
30
  return `Unrecognized HTTP Method: "${method}"`
36
31
  }
37
32
 
33
+
38
34
  export function parseFilename(file) {
39
35
  const tokens = file.replace(reComments, '').split('.')
40
36
  return {
@@ -44,6 +40,7 @@ export function parseFilename(file) {
44
40
  }
45
41
  }
46
42
 
43
+
47
44
  function removeTrailingSlash(url = '') {
48
45
  return url
49
46
  .replace(/\/$/, '')
package/src/MockBroker.js CHANGED
@@ -7,23 +7,18 @@ import { includesComment, extractComments, parseFilename } from './Filename.js'
7
7
  // that can be served for the route, the currently selected file, and its delay.
8
8
  export class MockBroker {
9
9
  #urlRegex
10
-
11
10
  constructor(file) {
12
11
  const { urlMask } = parseFilename(file)
13
12
  this.#urlRegex = new RegExp('^' + disregardVariables(removeQueryStringAndFragment(urlMask)) + '/*$')
14
-
15
13
  this.mocks = []
16
14
  this.currentMock = {
17
15
  file: '',
18
16
  delay: 0
19
17
  }
20
-
21
18
  this.register(file)
22
19
  }
23
20
 
24
- register(file) {
25
- this.mocks.push(file)
26
- }
21
+ register(file) { this.mocks.push(file) }
27
22
 
28
23
  // Appending a '/' so URLs ending with variables don't match
29
24
  // URLs that have a path after that variable. For example,
@@ -39,11 +34,12 @@ export class MockBroker {
39
34
  get file() { return this.currentMock.file }
40
35
  get delay() { return this.currentMock.delay }
41
36
  get status() { return parseFilename(this.file).status }
37
+ get isTemp500() { return includesComment(this.file, DEFAULT_500_COMMENT) }
42
38
 
43
39
  selectDefaultFile() {
44
40
  const userSpecifiedDefault = this.#findMockWithDefaultComment()
45
- if (userSpecifiedDefault)
46
- this.mocks = [ // sort for dashboard list TESTME
41
+ if (userSpecifiedDefault) // Sort for dashboard list TESTME
42
+ this.mocks = [
47
43
  userSpecifiedDefault,
48
44
  ...this.mocks.filter(m => m !== userSpecifiedDefault)
49
45
  ]
@@ -55,17 +51,9 @@ export class MockBroker {
55
51
  return f
56
52
  }
57
53
 
58
- mockExists(file) {
59
- return this.mocks.includes(file)
60
- }
61
-
62
- updateFile(filename) {
63
- this.currentMock.file = filename
64
- }
65
-
66
- updateDelay(delayed) {
67
- this.currentMock.delay = Number(delayed) * Config.delay
68
- }
54
+ mockExists(file) { return this.mocks.includes(file) }
55
+ updateFile(filename) { this.currentMock.file = filename }
56
+ updateDelay(delayed) { this.currentMock.delay = Number(delayed) * Config.delay }
69
57
 
70
58
  setByMatchingComment(comment) {
71
59
  for (const file of this.mocks)
@@ -94,9 +82,6 @@ export class MockBroker {
94
82
  const file = urlMask.replace(/^\//, '') // Removes leading slash TESTME
95
83
  this.register(`${file}${DEFAULT_500_COMMENT}.${method}.500.txt`)
96
84
  }
97
- get isTemp500() {
98
- return includesComment(this.file, DEFAULT_500_COMMENT)
99
- }
100
85
  }
101
86
 
102
87
  // Stars out (for regex) all the paths that are in square brackets