mockaton 4.0.1 → 5.0.1
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 +32 -24
- package/package.json +1 -1
- package/sample-mocks/api/user/edit-name.PATCH.md +9 -0
- package/src/Config.js +1 -1
- package/src/Dashboard.js +1 -2
- package/src/MockBroker.js +1 -1
- package/src/Route.js +33 -13
- package/sample-mocks/api/user/edit-name.PATCH.200.md +0 -12
package/README.md
CHANGED
|
@@ -21,7 +21,6 @@ exploring its [sample-mocks/](./sample-mocks) directory. Then, run
|
|
|
21
21
|
|
|
22
22
|
<img src="./README-dashboard.png" style="max-width:820px"/>
|
|
23
23
|
|
|
24
|
-
|
|
25
24
|
## Basic Usage
|
|
26
25
|
```
|
|
27
26
|
npm install mockaton
|
|
@@ -52,7 +51,7 @@ interface Config {
|
|
|
52
51
|
onReady?: (dashboardUrl: string) => void // defaults to openInBrowser. pass a noop to prevent opening the dashboard
|
|
53
52
|
cookies?: object
|
|
54
53
|
proxyFallback?: string // e.g. http://localhost:9999 Target for relaying routes without mocks
|
|
55
|
-
allowedExt?: RegExp // /\.(json|txt|
|
|
54
|
+
allowedExt?: RegExp // /\.(md|json|txt|js)$/ Just for excluding temporary editor files (e.g. JetBrains appends a ~)
|
|
56
55
|
extraHeaders?: []
|
|
57
56
|
}
|
|
58
57
|
```
|
|
@@ -61,8 +60,7 @@ interface Config {
|
|
|
61
60
|
|
|
62
61
|
## Mock Variants
|
|
63
62
|
Each route can have many mocks, which could either be:
|
|
64
|
-
- Different response __status code__.
|
|
65
|
-
- e.g. for testing error responses.
|
|
63
|
+
- Different response __status code__. For example, for testing error responses.
|
|
66
64
|
- __Comment__ on the filename, which is anything within parentheses.
|
|
67
65
|
- e.g. `api/user(my-comment).POST.201.json`
|
|
68
66
|
|
|
@@ -81,11 +79,18 @@ export default [
|
|
|
81
79
|
]
|
|
82
80
|
```
|
|
83
81
|
|
|
84
|
-
Or, export default a function.
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
Or, export default a function. In it, you can override the response status and the
|
|
83
|
+
default JSON content type. But don’t call `response.end()`, just return a string.
|
|
84
|
+
|
|
85
|
+
In a sense, you can think of this is an HTTP handler. So you can read or
|
|
86
|
+
write to a database, or pull data from a backend. The `request` is of type
|
|
87
|
+
[IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage), and the
|
|
88
|
+
`response` a [ServerResponse](https://nodejs.org/api/http.html#class-httpserverresponse).
|
|
87
89
|
```js
|
|
88
|
-
export default function (
|
|
90
|
+
export default function optionalName(request, response) {
|
|
91
|
+
globalThis.myDatabase ??= { count: 0 }
|
|
92
|
+
globalThis.myDatabase.count++
|
|
93
|
+
|
|
89
94
|
return JSON.stringify({ a: 1 })
|
|
90
95
|
}
|
|
91
96
|
```
|
|
@@ -104,15 +109,16 @@ particular response. They are handy for testing spinners.
|
|
|
104
109
|
The delay is globally configurable via `Config.delay = 1200` (milliseconds).
|
|
105
110
|
|
|
106
111
|
|
|
112
|
+
|
|
107
113
|
## File Name Convention
|
|
108
114
|
|
|
109
115
|
|
|
110
116
|
### Extension
|
|
111
|
-
`.Method.
|
|
117
|
+
`.Method.ResponseStatusCode.FileExt`
|
|
112
118
|
|
|
113
119
|
The **file extension** can be anything, but `.md` is reserved for documentation.
|
|
114
120
|
|
|
115
|
-
The `Config.allowedExt` regex defaults to: `/\.(json|txt|
|
|
121
|
+
The `Config.allowedExt` regex defaults to: `/\.(md|json|txt|js)$/`
|
|
116
122
|
|
|
117
123
|
|
|
118
124
|
### Dynamic Parameters
|
|
@@ -157,6 +163,14 @@ api/foo/(my comment).GET.200.json
|
|
|
157
163
|
|
|
158
164
|
## `Config.cookies`
|
|
159
165
|
The selected cookie is sent in every response in the `Set-Cookie` header.
|
|
166
|
+
|
|
167
|
+
The key is just a label used for selecting a particular cookie in the
|
|
168
|
+
dashboard. In the dashboard, only one cookie can be selected. If you need
|
|
169
|
+
more cookies you can inject additional cookies globally in `Config.extraHeaders`.
|
|
170
|
+
|
|
171
|
+
`jwtCookie` has a hardcoded header and signature. In other
|
|
172
|
+
words, it’s useful if you only care about its payload.
|
|
173
|
+
|
|
160
174
|
```js
|
|
161
175
|
import { jwtCookie } from 'mockaton'
|
|
162
176
|
|
|
@@ -169,15 +183,11 @@ Config.cookies = {
|
|
|
169
183
|
})
|
|
170
184
|
}
|
|
171
185
|
```
|
|
172
|
-
The key is just a label used for selecting a particular cookie in the dashboard.
|
|
173
|
-
|
|
174
|
-
`jwtCookie` has a hardcoded header and signature. In other
|
|
175
|
-
words, it’s useful if you only care about its payload.
|
|
176
|
-
|
|
177
186
|
|
|
178
187
|
## `Config.extraHeaders`
|
|
179
|
-
They are applied last, right before ending the response.
|
|
180
|
-
can overwrite the `Content-Type`.
|
|
188
|
+
They are applied last, right before ending the response.
|
|
189
|
+
In other words, they can overwrite the `Content-Type`. Note
|
|
190
|
+
that it's an array and the header name goes in even indices.
|
|
181
191
|
|
|
182
192
|
```js
|
|
183
193
|
Config.extraHeaders = [
|
|
@@ -188,16 +198,15 @@ Config.extraHeaders = [
|
|
|
188
198
|
```
|
|
189
199
|
|
|
190
200
|
## Documenting Contracts (.md)
|
|
191
|
-
This is handy for documenting request payload parameters. The
|
|
192
|
-
|
|
201
|
+
This is handy for documenting request payload parameters. The
|
|
202
|
+
dashboard prints the Markdown document as plain text (I know, I know).
|
|
193
203
|
|
|
194
|
-
Create a markdown file following the same filename convention.
|
|
195
|
-
The status code can be any number. For example,
|
|
196
204
|
```text
|
|
197
|
-
api/foo/[user-id].POST.
|
|
205
|
+
api/foo/[user-id].POST.md
|
|
198
206
|
api/foo/[user-id].POST.201.json
|
|
199
207
|
```
|
|
200
208
|
|
|
209
|
+
---
|
|
201
210
|
|
|
202
211
|
## API
|
|
203
212
|
|
|
@@ -229,8 +238,7 @@ fetch(addr + '/mockaton/reset', {
|
|
|
229
238
|
```
|
|
230
239
|
|
|
231
240
|
### Select a cookie
|
|
232
|
-
In `Config.cookies`, each key is the label used
|
|
233
|
-
for changing it. Only one cookie can be set.
|
|
241
|
+
In `Config.cookies`, each key is the label used for changing it.
|
|
234
242
|
```js
|
|
235
243
|
fetch(addr + '/mockaton/cookies', {
|
|
236
244
|
method: 'PATCH',
|
package/package.json
CHANGED
package/src/Config.js
CHANGED
|
@@ -11,7 +11,7 @@ export const Config = {
|
|
|
11
11
|
cookies: {}, // defaults to the first kv
|
|
12
12
|
onReady: openInBrowser,
|
|
13
13
|
proxyFallback: '', // e.g. http://localhost:9999
|
|
14
|
-
allowedExt: /\.(json|txt|
|
|
14
|
+
allowedExt: /\.(md|json|txt|js)$/, // Just for excluding temporary editor files (e.g. JetBrains appends a ~)
|
|
15
15
|
extraHeaders: []
|
|
16
16
|
}
|
|
17
17
|
|
package/src/Dashboard.js
CHANGED
|
@@ -132,8 +132,7 @@ function SectionByMethod({ method, brokers }) {
|
|
|
132
132
|
r('tbody', null,
|
|
133
133
|
r('th', null, method),
|
|
134
134
|
Object.entries(brokers)
|
|
135
|
-
.
|
|
136
|
-
.filter(([, broker]) => broker.mocks.length) // handles Markdown doc
|
|
135
|
+
.filter(([, broker]) => broker.mocks.length > 1) // Excludes Markdown only routes (>1 because of the autogen500)
|
|
137
136
|
.map(([urlMask, broker]) =>
|
|
138
137
|
r('tr', null,
|
|
139
138
|
r('td', null, r(PreviewLink, { method, urlMask, documentation: broker.documentation })),
|
package/src/MockBroker.js
CHANGED
|
@@ -78,7 +78,7 @@ export class MockBroker {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
#registerTemp500() {
|
|
81
|
-
const { urlMask, method } = Route.parseFilename(this.mocks[0])
|
|
81
|
+
const { urlMask, method } = Route.parseFilename(this.mocks[0] || this.documentation)
|
|
82
82
|
let mask = urlMask
|
|
83
83
|
const t = join(Config.mocksDir, urlMask)
|
|
84
84
|
if (existsSync(t) && lstatSync(t).isDirectory())
|
package/src/Route.js
CHANGED
|
@@ -44,23 +44,43 @@ export class Route {
|
|
|
44
44
|
|
|
45
45
|
static parseFilename(file) {
|
|
46
46
|
const tokens = file.replace(Route.reComments, '').split('.')
|
|
47
|
+
return file.endsWith('.md')
|
|
48
|
+
? parseDocumentation(tokens)
|
|
49
|
+
: parseMock(tokens)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function parseDocumentation(tokens) { // TESTME
|
|
54
|
+
if (tokens.length < 3)
|
|
55
|
+
return { error: 'Invalid Documentation Filename Convention' }
|
|
56
|
+
|
|
57
|
+
const method = tokens.at(-2)
|
|
58
|
+
if (!httpMethods.includes(method))
|
|
59
|
+
return { error: `Unrecognized HTTP Method: "${method}"` }
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
urlMask: '/' + removeTrailingSlash(tokens.at(-3)),
|
|
63
|
+
method,
|
|
64
|
+
status: 200
|
|
65
|
+
}
|
|
66
|
+
}
|
|
47
67
|
|
|
48
|
-
|
|
49
|
-
|
|
68
|
+
function parseMock(tokens) {
|
|
69
|
+
if (tokens.length < 4)
|
|
70
|
+
return { error: 'Invalid Filename Convention' }
|
|
50
71
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
72
|
+
const status = Number(tokens.at(-2))
|
|
73
|
+
if (!responseStatusIsValid(status))
|
|
74
|
+
return { error: `Invalid HTTP Response Status: "${status}"` }
|
|
54
75
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
76
|
+
const method = tokens.at(-3)
|
|
77
|
+
if (!httpMethods.includes(method))
|
|
78
|
+
return { error: `Unrecognized HTTP Method: "${method}"` }
|
|
58
79
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
80
|
+
return {
|
|
81
|
+
urlMask: '/' + removeTrailingSlash(tokens.at(-4)),
|
|
82
|
+
method,
|
|
83
|
+
status
|
|
64
84
|
}
|
|
65
85
|
}
|
|
66
86
|
|