mockaton 6.4.0 → 6.4.3
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-dashboard.png +0 -0
- package/README.md +69 -10
- package/package.json +1 -1
- package/sample-mocks/api/user/{videos(entirely unverified).GET.200.json → videos(default).GET.200.json} +1 -1
- package/src/ApiConstants.js +1 -1
- package/src/Config.js +1 -0
- package/src/Filename.js +2 -5
- package/src/MockBroker.js +12 -21
- /package/sample-mocks/api/user/{videos(assorted).GET.200.json → videos(all variants).GET.200.json} +0 -0
- /package/sample-mocks/api/user/{videos(entirely verified)(another comment).GET.200.json → videos(verified)(another comment).GET.200.json} +0 -0
package/README-dashboard.png
CHANGED
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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 //
|
|
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, //
|
|
53
|
-
port?: number //
|
|
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 //
|
|
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 //
|
|
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
|
|
|
@@ -174,6 +196,16 @@ api/foo.GET.200.json
|
|
|
174
196
|
api/foo/.GET.200.json
|
|
175
197
|
```
|
|
176
198
|
|
|
199
|
+
---
|
|
200
|
+
## `Config.staticDir`
|
|
201
|
+
These files don’t use the mock filename convention. They take precedence
|
|
202
|
+
over mocks. Also, they get served on the same address, so no CORS issues.
|
|
203
|
+
|
|
204
|
+
Use Case 1: If you have a bunch of static assets you don’t want to add `.GET.200.ext`
|
|
205
|
+
|
|
206
|
+
Use Case 2: For a standalone demo server. For example,
|
|
207
|
+
build your frontend bundle, and serve it from Mockaton.
|
|
208
|
+
|
|
177
209
|
|
|
178
210
|
## `Config.cookies`
|
|
179
211
|
The selected cookie is sent in every response in the `Set-Cookie` header.
|
|
@@ -219,6 +251,33 @@ Config.extraMimes = {
|
|
|
219
251
|
}
|
|
220
252
|
```
|
|
221
253
|
|
|
254
|
+
## `Config.onReady`
|
|
255
|
+
This is a callback `(dashboardAddress: string) => void`, which defaults to
|
|
256
|
+
trying to open the dashboard in your default browser in macOS and Windows.
|
|
257
|
+
|
|
258
|
+
If you don’t want to open a browser, pass a noop, such as
|
|
259
|
+
```js
|
|
260
|
+
Config.onReady = () => {}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
On Linux, you could pass:
|
|
264
|
+
```js
|
|
265
|
+
import { exec } from 'node:child_process'
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
Config.onReady = function openInBrowser(address) {
|
|
269
|
+
exec(`xdg-open ${address}`)
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Or, for more cross-platform utility, you could `npm install open` and pass it.
|
|
274
|
+
```js
|
|
275
|
+
import open from 'open'
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
Config.onReady = open
|
|
279
|
+
```
|
|
280
|
+
|
|
222
281
|
---
|
|
223
282
|
|
|
224
283
|
## API
|
package/package.json
CHANGED
package/src/ApiConstants.js
CHANGED
package/src/Config.js
CHANGED
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,9 +34,16 @@ 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
|
-
this
|
|
40
|
+
const userSpecifiedDefault = this.#findMockWithDefaultComment()
|
|
41
|
+
if (userSpecifiedDefault) // Sort for dashboard list TESTME
|
|
42
|
+
this.mocks = [
|
|
43
|
+
userSpecifiedDefault,
|
|
44
|
+
...this.mocks.filter(m => m !== userSpecifiedDefault)
|
|
45
|
+
]
|
|
46
|
+
this.updateFile(userSpecifiedDefault || this.mocks[0])
|
|
45
47
|
}
|
|
46
48
|
#findMockWithDefaultComment() {
|
|
47
49
|
for (const f of this.mocks)
|
|
@@ -49,17 +51,9 @@ export class MockBroker {
|
|
|
49
51
|
return f
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
mockExists(file) {
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
updateFile(filename) {
|
|
57
|
-
this.currentMock.file = filename
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
updateDelay(delayed) {
|
|
61
|
-
this.currentMock.delay = Number(delayed) * Config.delay
|
|
62
|
-
}
|
|
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 }
|
|
63
57
|
|
|
64
58
|
setByMatchingComment(comment) {
|
|
65
59
|
for (const file of this.mocks)
|
|
@@ -88,9 +82,6 @@ export class MockBroker {
|
|
|
88
82
|
const file = urlMask.replace(/^\//, '') // Removes leading slash TESTME
|
|
89
83
|
this.register(`${file}${DEFAULT_500_COMMENT}.${method}.500.txt`)
|
|
90
84
|
}
|
|
91
|
-
get isTemp500() {
|
|
92
|
-
return includesComment(this.file, DEFAULT_500_COMMENT)
|
|
93
|
-
}
|
|
94
85
|
}
|
|
95
86
|
|
|
96
87
|
// Stars out (for regex) all the paths that are in square brackets
|
/package/sample-mocks/api/user/{videos(assorted).GET.200.json → videos(all variants).GET.200.json}
RENAMED
|
File without changes
|