mockaton 0.9.10 → 0.10.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 +28 -37
- package/Tests.js +24 -10
- package/index.d.ts +2 -3
- package/package.json +2 -2
- package/src/Config.js +2 -0
- package/src/MockDispatcher.js +6 -2
- package/src/ProxyRelay.js +11 -0
- package/README-dashboard-dropdown.png +0 -0
- package/README-mocks-with-comments.png +0 -0
package/README.md
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
# Mockaton
|
|
2
2
|
_Mockaton_ is a mock server for developing and testing frontends.
|
|
3
3
|
|
|
4
|
-
It scans `Config.mocksDir` for files following a specific
|
|
5
|
-
|
|
4
|
+
It scans `Config.mocksDir` for files following a specific
|
|
5
|
+
file name convention, which is similar to the URL paths. For
|
|
6
6
|
example, the following file will be served for `/api/user/1234`
|
|
7
7
|
```
|
|
8
|
-
|
|
9
|
-
|-- user/
|
|
10
|
-
|-- [user-id].GET.200.json
|
|
8
|
+
my-mocks-dir/api/user/[user-id].GET.200.json
|
|
11
9
|
```
|
|
12
10
|
|
|
13
11
|
By the way, [this browser
|
|
@@ -17,14 +15,21 @@ be used for downloading a TAR of your XHR requests following that convention.
|
|
|
17
15
|
|
|
18
16
|
### Mock Variants
|
|
19
17
|
Each route can have many mocks, which could either be:
|
|
20
|
-
- Different response
|
|
21
|
-
-
|
|
18
|
+
- Different response __status code__.
|
|
19
|
+
- e.g. for testing error responses. BTW, an _Internal Server
|
|
20
|
+
Error_ mock is autogenerated for routes that have no 500.
|
|
21
|
+
- __Comment__ on the filename, which is anything within parentheses.
|
|
22
|
+
- e.g. `api/user(my-comment).POST.201.json`
|
|
22
23
|
|
|
23
24
|
Those alternatives can be manually selected in the dashboard
|
|
24
25
|
UI, or programmatically, for instance, for setting up tests.
|
|
25
26
|
|
|
26
27
|
About the default mock file, the first file in **alphabetical order** wins.
|
|
27
28
|
|
|
29
|
+
### Proxying Routes
|
|
30
|
+
`Config.proxyFallback` lets you specify a target
|
|
31
|
+
server for serving routes you don’t have mocks for.
|
|
32
|
+
|
|
28
33
|
|
|
29
34
|
## Getting Started
|
|
30
35
|
The best way to learn _Mockaton_ is by checking out this repo and
|
|
@@ -34,20 +39,6 @@ exploring its [sample-mocks/](./sample-mocks) directory. Then, run
|
|
|
34
39
|

|
|
35
40
|
|
|
36
41
|
|
|
37
|
-
### Mock Variants of Status Code
|
|
38
|
-
The **sample-mocks/** directory has three mock alternatives for serving
|
|
39
|
-
`/api/user/friends`:
|
|
40
|
-
- _200 - OK_
|
|
41
|
-
- _204 - No Content_ with an empty list of friends
|
|
42
|
-
- _500 - Internal Server Error_
|
|
43
|
-
- BTW, 500 mocks get autogenerated for routes that have no 500’s.
|
|
44
|
-
|
|
45
|
-

|
|
46
|
-
|
|
47
|
-
### Mock Variants with Comments
|
|
48
|
-
Comments are anything within parentheses, including them.
|
|
49
|
-

|
|
50
|
-
|
|
51
42
|
## Delay 🕓
|
|
52
43
|
The clock icon next to the mock selector is a checkbox for delaying a
|
|
53
44
|
particular response. They are handy for testing spinners.
|
|
@@ -63,12 +54,11 @@ npm install mockaton
|
|
|
63
54
|
Create a `my-mockaton.js` file
|
|
64
55
|
```js
|
|
65
56
|
import { resolve } from 'node:path'
|
|
66
|
-
import { Mockaton } from '
|
|
67
|
-
|
|
57
|
+
import { Mockaton } from 'mockaton'
|
|
68
58
|
|
|
69
|
-
Mockaton({
|
|
70
|
-
|
|
71
|
-
|
|
59
|
+
Mockaton({
|
|
60
|
+
mocksDir: resolve('my-mocks-dir'),
|
|
61
|
+
port: 2345
|
|
72
62
|
})
|
|
73
63
|
```
|
|
74
64
|
|
|
@@ -84,9 +74,10 @@ interface Config {
|
|
|
84
74
|
host?: string, // 'localhost'
|
|
85
75
|
port?: number // 0 auto-assigned
|
|
86
76
|
delay?: number // 1200 ms
|
|
87
|
-
cookies
|
|
77
|
+
cookies?: object
|
|
88
78
|
database?: object // for "Transforms"
|
|
89
79
|
skipOpen?: boolean // Prevents opening the dashboard in a browser
|
|
80
|
+
proxyFallback?: string // e.g. http://localhost:9999 Target for relaying routes without mocks
|
|
90
81
|
allowedExt?: RegExp // /\.(json|txt|md|mjs)$/ Just for excluding temporary editor files (e.g. JetBrains appends a ~)
|
|
91
82
|
}
|
|
92
83
|
```
|
|
@@ -95,16 +86,16 @@ interface Config {
|
|
|
95
86
|
```js
|
|
96
87
|
import { jwtCookie } from 'src/Mockaton'
|
|
97
88
|
|
|
98
|
-
|
|
99
89
|
Config.cookies = {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
90
|
+
'My Admin User': 'my-cookie=1;Path=/;SameSite=strict',
|
|
91
|
+
'My Normal User': 'my-cookie=0;Path=/;SameSite=strict',
|
|
92
|
+
'My JWT': jwtCookie('my-cookie', {
|
|
93
|
+
email: 'john.doe@example.com',
|
|
94
|
+
picture: 'https://cdn.auth0.com/avatars/jd.png'
|
|
95
|
+
})
|
|
106
96
|
}
|
|
107
97
|
```
|
|
98
|
+
The key is just a label used in dashboard for selecting the desired cookie.
|
|
108
99
|
|
|
109
100
|
That `jwtCookie` has a hardcoded header and signature. In other
|
|
110
101
|
words, it’s useful iff you care about its payload in the frontend.
|
|
@@ -179,9 +170,9 @@ with `.mjs` will process the mock before serving it.
|
|
|
179
170
|
|
|
180
171
|
For example, this handler will capitalize the mock body and increment a counter.
|
|
181
172
|
```js
|
|
182
|
-
export default function capitalizeAllText(mockAsText, requestBody,
|
|
183
|
-
|
|
184
|
-
|
|
173
|
+
export default function capitalizeAllText(mockAsText, requestBody, config) {
|
|
174
|
+
config.database.myCount ??= 0
|
|
175
|
+
config.database.myCount++
|
|
185
176
|
return mockAsText.toUpperCase()
|
|
186
177
|
}
|
|
187
178
|
```
|
package/Tests.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { tmpdir } from 'node:os'
|
|
4
4
|
import { dirname } from 'node:path'
|
|
5
5
|
import { describe, it } from 'node:test'
|
|
6
|
+
import { createServer } from 'node:http'
|
|
6
7
|
import { equal, deepEqual, match } from 'node:assert/strict'
|
|
7
8
|
import { writeFileSync, mkdtempSync, mkdirSync } from 'node:fs'
|
|
8
9
|
|
|
@@ -98,17 +99,22 @@ writeStatic('index.html', '<h1>Static</h1>')
|
|
|
98
99
|
writeStatic('assets/app.js', 'const app = 1')
|
|
99
100
|
writeStatic('another-entry/index.html', '<h1>Another</h1>')
|
|
100
101
|
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
102
|
+
let server
|
|
103
|
+
const fallbackServer = createServer((_, response) => {
|
|
104
|
+
response.end('From_Fallback_Server')
|
|
105
|
+
}).listen(0, 'localhost', function () {
|
|
106
|
+
server = Mockaton({
|
|
107
|
+
mocksDir: tmpDir,
|
|
108
|
+
staticDir: staticTmpDir,
|
|
109
|
+
skipOpen: true,
|
|
110
|
+
cookies: {
|
|
111
|
+
userA: 'CookieA',
|
|
112
|
+
userB: 'CookieB'
|
|
113
|
+
},
|
|
114
|
+
proxyFallback: `http://localhost:${fallbackServer.address().port}`
|
|
115
|
+
})
|
|
116
|
+
server.on('listening', runTests)
|
|
110
117
|
})
|
|
111
|
-
server.on('listening', runTests)
|
|
112
118
|
|
|
113
119
|
async function runTests() {
|
|
114
120
|
await testItRendersDashboard()
|
|
@@ -157,7 +163,9 @@ async function runTests() {
|
|
|
157
163
|
await testTransforms()
|
|
158
164
|
await testStaticFileServing()
|
|
159
165
|
await testInvalidFilenamesAreIgnored()
|
|
166
|
+
await testRouteWithoutMocksRelaysGetsProxied()
|
|
160
167
|
server.close()
|
|
168
|
+
fallbackServer.close()
|
|
161
169
|
}
|
|
162
170
|
|
|
163
171
|
async function reset() {
|
|
@@ -350,6 +358,12 @@ async function testInvalidFilenamesAreIgnored() {
|
|
|
350
358
|
})
|
|
351
359
|
}
|
|
352
360
|
|
|
361
|
+
async function testRouteWithoutMocksRelaysGetsProxied() {
|
|
362
|
+
await it('Fallback relay', async () => {
|
|
363
|
+
const res = await request('/non-existing-mock')
|
|
364
|
+
equal(await res.text(), 'From_Fallback_Server')
|
|
365
|
+
})
|
|
366
|
+
}
|
|
353
367
|
|
|
354
368
|
// Utils
|
|
355
369
|
|
package/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
"name": "mockaton",
|
|
3
3
|
"description": "A deterministic server-side for developing and testing frontend clients",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.10.1",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"types": "index.d.ts",
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"repository": "https://github.com/ericfortis/mockaton",
|
|
10
10
|
"scripts": {
|
|
11
11
|
"test": "./Tests.js",
|
|
12
|
-
"demo": "_usage_example.js"
|
|
12
|
+
"demo": "./_usage_example.js"
|
|
13
13
|
}
|
|
14
14
|
}
|
package/src/Config.js
CHANGED
|
@@ -11,6 +11,7 @@ export const Config = {
|
|
|
11
11
|
cookies: {}, // defaults to the first kv
|
|
12
12
|
database: {},
|
|
13
13
|
skipOpen: false,
|
|
14
|
+
proxyFallback: '', // e.g. http://localhost:9999
|
|
14
15
|
allowedExt: /\.(json|txt|md|mjs)$/ // Just for excluding temporary editor files (e.g. JetBrains appends a ~)
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -25,6 +26,7 @@ export function setup(options) {
|
|
|
25
26
|
cookies: is(Object),
|
|
26
27
|
database: is(Object),
|
|
27
28
|
skipOpen: is(Boolean),
|
|
29
|
+
proxyFallback: is(String),
|
|
28
30
|
allowedExt: is(RegExp)
|
|
29
31
|
})
|
|
30
32
|
}
|
package/src/MockDispatcher.js
CHANGED
|
@@ -2,6 +2,7 @@ import { join } from 'node:path'
|
|
|
2
2
|
import { readFileSync } from 'node:fs'
|
|
3
3
|
|
|
4
4
|
import { DF } from './ApiConstants.js'
|
|
5
|
+
import { proxy } from './ProxyRelay.js'
|
|
5
6
|
import { cookie } from './cookie.js'
|
|
6
7
|
import { Config } from './Config.js'
|
|
7
8
|
import { mimeFor } from './utils/mime.js'
|
|
@@ -19,10 +20,13 @@ export async function dispatchMock(req, response) {
|
|
|
19
20
|
|
|
20
21
|
const broker = mockBrokerCollection.getBrokerForUrl(req.method, req.url)
|
|
21
22
|
if (!broker) {
|
|
22
|
-
|
|
23
|
+
if (Config.proxyFallback)
|
|
24
|
+
await proxy(req, response)
|
|
25
|
+
else
|
|
26
|
+
sendNotFound(response) // TESTME
|
|
23
27
|
return
|
|
24
28
|
}
|
|
25
|
-
|
|
29
|
+
|
|
26
30
|
try {
|
|
27
31
|
const { file, status, delay, currentTransform } = broker
|
|
28
32
|
console.log('\n', req.url, '→\n ', file)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Config } from './Config.js'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export async function proxy(req, response) {
|
|
5
|
+
const proxyResponse = await fetch(Config.proxyFallback + req.url, {
|
|
6
|
+
method: req.method,
|
|
7
|
+
headers: req.headers
|
|
8
|
+
})
|
|
9
|
+
response.writeHead(proxyResponse.status, proxyResponse.headers)
|
|
10
|
+
response.end(await proxyResponse.text())
|
|
11
|
+
}
|
|
Binary file
|
|
Binary file
|