mockaton 0.10.2 → 0.10.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.
- package/README.md +12 -12
- package/Tests.js +13 -13
- package/package.json +1 -1
- package/src/Api.js +10 -10
- package/src/ApiConstants.js +1 -1
- package/src/Dashboard.js +1 -3
- package/src/MockDispatcher.js +2 -2
- package/src/Mockaton.js +3 -2
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ be used for downloading a TAR of your XHR requests following that convention.
|
|
|
16
16
|
### Mock Variants
|
|
17
17
|
Each route can have many mocks, which could either be:
|
|
18
18
|
- Different response __status code__.
|
|
19
|
-
- e.g. for testing error responses.
|
|
19
|
+
- e.g. for testing error responses. As a side note, an _Internal Server
|
|
20
20
|
Error_ mock is autogenerated for routes that have no 500.
|
|
21
21
|
- __Comment__ on the filename, which is anything within parentheses.
|
|
22
22
|
- e.g. `api/user(my-comment).POST.201.json`
|
|
@@ -71,9 +71,9 @@ node my-mockaton.js
|
|
|
71
71
|
interface Config {
|
|
72
72
|
mocksDir: string
|
|
73
73
|
staticDir?: string
|
|
74
|
-
host?: string, // 'localhost'
|
|
75
|
-
port?: number // 0 auto-assigned
|
|
76
|
-
delay?: number // 1200 ms
|
|
74
|
+
host?: string, // defaults to 'localhost'
|
|
75
|
+
port?: number // defaults to 0, which means auto-assigned
|
|
76
|
+
delay?: number // defaults to 1200 (ms)
|
|
77
77
|
cookies?: object
|
|
78
78
|
database?: object // for "Transforms"
|
|
79
79
|
skipOpen?: boolean // Prevents opening the dashboard in a browser
|
|
@@ -95,10 +95,10 @@ Config.cookies = {
|
|
|
95
95
|
})
|
|
96
96
|
}
|
|
97
97
|
```
|
|
98
|
-
The key is just a label used
|
|
98
|
+
The key is just a label used for selecting a particular cookie in the dashboard.
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
words, it’s useful
|
|
100
|
+
`jwtCookie` has a hardcoded header and signature. In other
|
|
101
|
+
words, it’s useful if you only care about its payload.
|
|
102
102
|
|
|
103
103
|
---
|
|
104
104
|
|
|
@@ -115,7 +115,7 @@ The `Config.allowedExt` regex defaults to: `/\.(json|txt|md|mjs)$/`
|
|
|
115
115
|
|
|
116
116
|
|
|
117
117
|
### Dynamic Parameters
|
|
118
|
-
Anything within square brackets. For example
|
|
118
|
+
Anything within square brackets. For example:
|
|
119
119
|
<pre>
|
|
120
120
|
api/user/<b>[id]</b>/<b>[age]</b>.GET.200.json
|
|
121
121
|
</pre>
|
|
@@ -134,10 +134,10 @@ api/foo.GET.200.json
|
|
|
134
134
|
api/video<b>?limit=[limit]</b>.GET.200.json
|
|
135
135
|
</pre>
|
|
136
136
|
|
|
137
|
-
The query string is ignored when routing to it.
|
|
138
|
-
only used for documenting the URL
|
|
137
|
+
The query string is ignored when routing to it. In other words, it’s
|
|
138
|
+
only used for documenting the URL contract.
|
|
139
139
|
|
|
140
|
-
|
|
140
|
+
Speaking of which, in Windows, filenames containing "?" are [not
|
|
141
141
|
permitted](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file),
|
|
142
142
|
but since that’s part of the query string, it’s ignored anyway.
|
|
143
143
|
|
|
@@ -155,7 +155,7 @@ api/foo/(my comment).GET.200.json
|
|
|
155
155
|
|
|
156
156
|
## Documenting Contracts (.md)
|
|
157
157
|
This is handy for documenting request payload parameters. The dashboard will
|
|
158
|
-
print the
|
|
158
|
+
print the Markdown document (as plain text) above the actual payload content.
|
|
159
159
|
|
|
160
160
|
Create a markdown file following the same filename convention.
|
|
161
161
|
The status code can be any number. For example,
|
package/Tests.js
CHANGED
|
@@ -10,7 +10,7 @@ import { writeFileSync, mkdtempSync, mkdirSync } from 'node:fs'
|
|
|
10
10
|
import { Route } from './src/Route.js'
|
|
11
11
|
import { mimeFor } from './src/utils/mime.js'
|
|
12
12
|
import { Mockaton } from './src/Mockaton.js'
|
|
13
|
-
import {
|
|
13
|
+
import { API, DF } from './src/ApiConstants.js'
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
const tmpDir = mkdtempSync(tmpdir()) + '/'
|
|
@@ -169,11 +169,11 @@ async function runTests() {
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
async function reset() {
|
|
172
|
-
await request(
|
|
172
|
+
await request(API.reset, { method: 'PATCH' })
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
async function testItRendersDashboard() {
|
|
176
|
-
const res = await request(
|
|
176
|
+
const res = await request(API.dashboard)
|
|
177
177
|
const body = await res.text()
|
|
178
178
|
await describe('Dashboard', () =>
|
|
179
179
|
it('Renders HTML', () => match(body, new RegExp('<!DOCTYPE html>'))))
|
|
@@ -197,7 +197,7 @@ async function testMockDispatching(url, file, expectedBody, reqBody = void 0) {
|
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
async function testItUpdatesTheCurrentSelectedMock(url, file, expectedStatus, expectedBody) {
|
|
200
|
-
await request(
|
|
200
|
+
await request(API.edit, {
|
|
201
201
|
method: 'PATCH',
|
|
202
202
|
body: JSON.stringify({ [DF.file]: file })
|
|
203
203
|
})
|
|
@@ -210,7 +210,7 @@ async function testItUpdatesTheCurrentSelectedMock(url, file, expectedStatus, ex
|
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
async function testItUpdatesDelayAndFile(url, file, expectedBody) {
|
|
213
|
-
await request(
|
|
213
|
+
await request(API.edit, {
|
|
214
214
|
method: 'PATCH',
|
|
215
215
|
body: JSON.stringify({
|
|
216
216
|
[DF.file]: file,
|
|
@@ -228,7 +228,7 @@ async function testItUpdatesDelayAndFile(url, file, expectedBody) {
|
|
|
228
228
|
|
|
229
229
|
|
|
230
230
|
async function testAutogenerates500(url, file) {
|
|
231
|
-
await request(
|
|
231
|
+
await request(API.edit, {
|
|
232
232
|
method: 'PATCH',
|
|
233
233
|
body: JSON.stringify({ [DF.file]: file })
|
|
234
234
|
})
|
|
@@ -241,7 +241,7 @@ async function testAutogenerates500(url, file) {
|
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
async function testPreservesExiting500(url, file, expectedBody) {
|
|
244
|
-
await request(
|
|
244
|
+
await request(API.edit, {
|
|
245
245
|
method: 'PATCH',
|
|
246
246
|
body: JSON.stringify({ [DF.file]: file })
|
|
247
247
|
})
|
|
@@ -254,14 +254,14 @@ async function testPreservesExiting500(url, file, expectedBody) {
|
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
async function testExtractsAllComments(expected) {
|
|
257
|
-
const res = await request(
|
|
257
|
+
const res = await request(API.comments)
|
|
258
258
|
const body = await res.json()
|
|
259
259
|
await it('Extracts all comments without duplicates', () =>
|
|
260
260
|
deepEqual(body, expected))
|
|
261
261
|
}
|
|
262
262
|
|
|
263
263
|
async function testItBulkSelectsByComment(comment, tests) {
|
|
264
|
-
await request(
|
|
264
|
+
await request(API.bulkSelect, {
|
|
265
265
|
method: 'PATCH',
|
|
266
266
|
body: JSON.stringify({ [DF.comment]: comment })
|
|
267
267
|
})
|
|
@@ -273,7 +273,7 @@ async function testItBulkSelectsByComment(comment, tests) {
|
|
|
273
273
|
async function testItUpdatesUserRole() {
|
|
274
274
|
await describe('Cookie', () => {
|
|
275
275
|
it('Defaults to the first key:value', async () => {
|
|
276
|
-
const res = await request(
|
|
276
|
+
const res = await request(API.cookies)
|
|
277
277
|
deepEqual(await res.json(), [
|
|
278
278
|
['userA', true],
|
|
279
279
|
['userB', false]
|
|
@@ -281,11 +281,11 @@ async function testItUpdatesUserRole() {
|
|
|
281
281
|
})
|
|
282
282
|
|
|
283
283
|
it('Update the selected cookie', async () => {
|
|
284
|
-
await request(
|
|
284
|
+
await request(API.cookies, {
|
|
285
285
|
method: 'PATCH',
|
|
286
286
|
body: JSON.stringify({ [DF.currentCookieKey]: 'userB' })
|
|
287
287
|
})
|
|
288
|
-
const res = await request(
|
|
288
|
+
const res = await request(API.cookies)
|
|
289
289
|
deepEqual(await res.json(), [
|
|
290
290
|
['userA', false],
|
|
291
291
|
['userB', true]
|
|
@@ -305,7 +305,7 @@ export default function (mock, reqBody, config) {
|
|
|
305
305
|
return JSON.stringify(body);
|
|
306
306
|
}`)
|
|
307
307
|
await reset() // for registering the files
|
|
308
|
-
await request(
|
|
308
|
+
await request(API.transform, {
|
|
309
309
|
method: 'PATCH',
|
|
310
310
|
body: JSON.stringify({ [DF.file]: 'api/transform.POST.200.mjs' })
|
|
311
311
|
})
|
package/package.json
CHANGED
package/src/Api.js
CHANGED
|
@@ -6,29 +6,29 @@
|
|
|
6
6
|
import { join } from 'node:path'
|
|
7
7
|
import { cookie } from './cookie.js'
|
|
8
8
|
import { Config } from './Config.js'
|
|
9
|
-
import { DF,
|
|
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
12
|
import { sendOK, sendBadRequest, sendJSON, sendFile } from './utils/http-response.js'
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
export const apiGetRequests = new Map([
|
|
16
|
-
[
|
|
16
|
+
[API.dashboard, serveDashboard],
|
|
17
17
|
['/Route.js', serveDashboardAsset],
|
|
18
18
|
['/Dashboard.js', serveDashboardAsset],
|
|
19
19
|
['/Dashboard.css', serveDashboardAsset],
|
|
20
20
|
['/ApiConstants.js', serveDashboardAsset],
|
|
21
|
-
[
|
|
22
|
-
[
|
|
23
|
-
[
|
|
21
|
+
[API.mocks, listMockBrokers],
|
|
22
|
+
[API.cookies, listCookies],
|
|
23
|
+
[API.comments, listComments]
|
|
24
24
|
])
|
|
25
25
|
|
|
26
26
|
export const apiPatchRequests = new Map([
|
|
27
|
-
[
|
|
28
|
-
[
|
|
29
|
-
[
|
|
30
|
-
[
|
|
31
|
-
[
|
|
27
|
+
[API.bulkSelect, bulkUpdateBrokersByCommentTag],
|
|
28
|
+
[API.edit, updateBroker],
|
|
29
|
+
[API.reset, reinitialize],
|
|
30
|
+
[API.cookies, selectCookie],
|
|
31
|
+
[API.transform, updateBrokerTransform]
|
|
32
32
|
])
|
|
33
33
|
|
|
34
34
|
function serveDashboard(_, response) {
|
package/src/ApiConstants.js
CHANGED
package/src/Dashboard.js
CHANGED
package/src/MockDispatcher.js
CHANGED
|
@@ -23,7 +23,7 @@ export async function dispatchMock(req, response) {
|
|
|
23
23
|
if (Config.proxyFallback)
|
|
24
24
|
await proxy(req, response)
|
|
25
25
|
else
|
|
26
|
-
sendNotFound(response) // TESTME
|
|
26
|
+
sendNotFound(response) // TODO unit TESTME
|
|
27
27
|
return
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -59,7 +59,7 @@ const nonSafeMethods = ['PATCH', 'POST', 'PUT', 'DELETE', 'CONNECT']
|
|
|
59
59
|
|
|
60
60
|
async function requestBodyForTransform(req, mockAsText) {
|
|
61
61
|
if (nonSafeMethods.includes(req.method))
|
|
62
|
-
return req.headers[DF.isForDashboard] // TESTME
|
|
62
|
+
return req.headers[DF.isForDashboard] // TODO unit TESTME
|
|
63
63
|
? JSON.parse(mockAsText)
|
|
64
64
|
: await parseJSON(req)
|
|
65
65
|
return ''
|
package/src/Mockaton.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { exec } from 'node:child_process'
|
|
2
2
|
import { createServer } from 'node:http'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { API } from './ApiConstants.js'
|
|
5
5
|
import { Config, setup } from './Config.js'
|
|
6
6
|
import { dispatchMock } from './MockDispatcher.js'
|
|
7
7
|
import * as mockBrokerCollection from './mockBrokersCollection.js'
|
|
@@ -31,9 +31,10 @@ export function Mockaton(options) {
|
|
|
31
31
|
const { address, port } = this.address()
|
|
32
32
|
const url = `http://${address}:${port}`
|
|
33
33
|
console.log('Listening on', url)
|
|
34
|
+
console.log('Dashboard', url + API.dashboard)
|
|
34
35
|
if (error)
|
|
35
36
|
console.error(error)
|
|
36
37
|
else if (!Config.skipOpen)
|
|
37
|
-
exec(`open ${url +
|
|
38
|
+
exec(`open ${url + API.dashboard}`)
|
|
38
39
|
})
|
|
39
40
|
}
|