mockaton 0.9.0 → 0.9.2
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/.editorconfig +8 -0
- package/ApiConstants.js +0 -1
- package/Dashboard.html +4 -4
- package/MockBroker.js +1 -1
- package/Mockaton.js +3 -3
- package/README.md +72 -44
- package/Route.js +7 -7
- package/_usage_example.js +2 -2
- package/index.d.ts +11 -9
- package/package.json +12 -12
- package/sample-mocks/api/user/edit-name.PATCH.200.json +3 -1
- package/sample-mocks/api/user/friends.GET.204.json +3 -3
- package/sample-mocks/api/user/videos(assorted).GET.200.json +12 -12
- package/sample-mocks/api/user/videos(entirely unverified).GET.200.json +12 -12
- package/sample-mocks/api/user/videos(entirely verified)(another comment).GET.200.json +12 -12
- package/sample-mocks/api/video/[id].GET.200.json +3 -3
- package/sample-mocks/api/video/list.GET.200.json +10 -10
- package/sample-mocks/api/video/stat/[stat-id]/all-videos?limit=[limit].GET.200.json +3 -3
- package/sample-mocks/api/video/upload.POST.201.json +2 -2
- package/utils/jwt.js +13 -13
package/.editorconfig
ADDED
package/ApiConstants.js
CHANGED
package/Dashboard.html
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en-US">
|
|
3
3
|
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
<link rel="stylesheet" href="../Dashboard.css">
|
|
5
|
+
<link rel="icon" href="data:">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
7
|
+
<title>Mock Server</title>
|
|
8
8
|
</head>
|
|
9
9
|
<body>
|
|
10
10
|
<script src="../Dashboard.js" type="module"></script>
|
package/MockBroker.js
CHANGED
package/Mockaton.js
CHANGED
|
@@ -17,13 +17,13 @@ export function Mockaton(options) {
|
|
|
17
17
|
const { url, method } = req
|
|
18
18
|
if (method === 'GET' && apiGetRequests.has(url))
|
|
19
19
|
apiGetRequests.get(url)(req, response)
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
else if (method === 'PATCH' && apiPatchRequests.has(url))
|
|
22
22
|
await apiPatchRequests.get(url)(req, response)
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
else if (isStatic(req))
|
|
25
25
|
await dispatchStatic(req, response)
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
else
|
|
28
28
|
await dispatchMock(req, response)
|
|
29
29
|
})
|
package/README.md
CHANGED
|
@@ -10,17 +10,22 @@ api/user/
|
|
|
10
10
|
api/user/[user-id].GET.200.json
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
By the way, this [browser
|
|
14
|
+
extension](https://github.com/ericfortis/devtools-ext-tar-http-requests) can
|
|
15
|
+
be used for downloading a tar of your XHR requests following that convention.
|
|
16
|
+
|
|
17
|
+
|
|
13
18
|
### Mock Variants
|
|
14
|
-
Each route can have different mocks and those variants could either be:
|
|
15
|
-
- a different response status code, (e.g. 200, 401),
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
UI, or programmatically for instance for setting up tests.
|
|
19
|
+
Each route can have different mocks and those variants could either be:
|
|
20
|
+
- a different response status code, (e.g. 200, 401), or
|
|
21
|
+
- a comment on the filename, which is anything within parentheses.
|
|
22
|
+
|
|
23
|
+
Those variants can be manually selected in the dashboard
|
|
24
|
+
UI, or programmatically, for instance, for setting up tests.
|
|
20
25
|
|
|
21
26
|
|
|
22
27
|
## Getting Started
|
|
23
|
-
The best way to learn
|
|
28
|
+
The best way to learn _Mockaton_ is by checking out this repo and
|
|
24
29
|
exploring its [sample-mocks/](./sample-mocks) directory. Then run
|
|
25
30
|
[`./_usage_example.js`](./_usage_example.js) and you’ll see this dashboard:
|
|
26
31
|
|
|
@@ -29,12 +34,12 @@ exploring its [sample-mocks/](./sample-mocks) directory. Then run
|
|
|
29
34
|
|
|
30
35
|
### Mock Variants of Status Code
|
|
31
36
|
The **sample-mocks/** directory has three mock alternatives for serving
|
|
32
|
-
`/api/user/friends
|
|
33
|
-
-
|
|
34
|
-
- another one with _204 - No Content_ of an empty list of friends, and
|
|
37
|
+
`/api/user/friends`:
|
|
38
|
+
- an HTTP status of _200 - OK_,
|
|
39
|
+
- another one with _204 - No Content_ of an empty list of friends, and
|
|
35
40
|
- a _501 - Internal Server Error_
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
- 501 mocks get autogenerated for routes that have no 501’s.
|
|
42
|
+
|
|
38
43
|

|
|
39
44
|
|
|
40
45
|
### Mock Variants with Comments
|
|
@@ -45,19 +50,20 @@ Comments are anything within parentheses, including them.
|
|
|
45
50
|
|
|
46
51
|
## Delay
|
|
47
52
|
The clock icon next to the mock selector dropdown is a checkbox for delaying a
|
|
48
|
-
particular response. They are handy for testing spinners when developing UIs.
|
|
49
|
-
|
|
53
|
+
particular response. They are handy for testing spinners when developing UIs.
|
|
54
|
+
|
|
55
|
+
The milliseconds for the delay is globally configurable via `Config.delay = 1200`
|
|
50
56
|
|
|
51
57
|
---
|
|
52
58
|
|
|
53
59
|
## Basic Usage (see [_usage_example.js](./_usage_example.js))
|
|
54
60
|
```
|
|
55
|
-
npm install
|
|
61
|
+
npm install mockaton
|
|
56
62
|
```
|
|
57
63
|
Create a `my-mockaton.js` file
|
|
58
64
|
```js
|
|
59
65
|
import { resolve } from 'node:path'
|
|
60
|
-
import { Mockaton } from '
|
|
66
|
+
import { Mockaton } from 'mockaton'
|
|
61
67
|
|
|
62
68
|
Mockaton({ // Config options
|
|
63
69
|
port: 2345,
|
|
@@ -69,19 +75,49 @@ Mockaton({ // Config options
|
|
|
69
75
|
node my-mockaton.js
|
|
70
76
|
```
|
|
71
77
|
|
|
78
|
+
## Config Options
|
|
79
|
+
```ts
|
|
80
|
+
interface Config {
|
|
81
|
+
mocksDir: string
|
|
82
|
+
staticDir?: string
|
|
83
|
+
host?: string,
|
|
84
|
+
port?: number
|
|
85
|
+
|
|
86
|
+
cookies?(): object
|
|
87
|
+
|
|
88
|
+
skipOpen?: boolean
|
|
89
|
+
allowedExt?: RegExp
|
|
90
|
+
delayMilliseconds?: number
|
|
91
|
+
database?: object
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Cookies
|
|
96
|
+
```js
|
|
97
|
+
import { jwtCookie } from 'mockaton'
|
|
98
|
+
|
|
99
|
+
Config.cookies = {
|
|
100
|
+
'My Admin User': 'my-cookie=1;Path=/;SameSite=strict',
|
|
101
|
+
'My Normal User': 'my-cookie=0;Path=/;SameSite=strict',
|
|
102
|
+
'My JWT': jwtCookie('my-cookie', { foo: 'bar' })
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
That `jwtCookie` has a hardcoded header and signature. In other
|
|
107
|
+
words, it’s useful iff you care about its payload in frontend.
|
|
108
|
+
|
|
72
109
|
---
|
|
73
110
|
|
|
74
111
|
## File Name Convention
|
|
75
112
|
|
|
76
113
|
|
|
77
|
-
|
|
78
114
|
### Extension
|
|
79
115
|
`.Method.HttpResponseStatusCode.FileExt`
|
|
80
116
|
|
|
81
117
|
The **file extension** can anything, but `.md` and `.mjs` are reserved
|
|
82
118
|
for documentation, and mock processors (more on that later).
|
|
83
119
|
|
|
84
|
-
|
|
120
|
+
The `Config.allowedExt` regex defaults to: `/\.(json|txt|md|mjs)$/`
|
|
85
121
|
|
|
86
122
|
|
|
87
123
|
### Dynamic Parameters
|
|
@@ -121,31 +157,6 @@ api/foo/(my comment).GET.200.json
|
|
|
121
157
|
|
|
122
158
|
---
|
|
123
159
|
|
|
124
|
-
## Config Options
|
|
125
|
-
```ts
|
|
126
|
-
interface Config {
|
|
127
|
-
mocksDir: string
|
|
128
|
-
staticDir?: string
|
|
129
|
-
host?: string,
|
|
130
|
-
port?: number
|
|
131
|
-
|
|
132
|
-
cookies?(): object
|
|
133
|
-
|
|
134
|
-
skipOpen?: boolean
|
|
135
|
-
allowedExt?: RegExp
|
|
136
|
-
delayMilliseconds?: number
|
|
137
|
-
database?: object
|
|
138
|
-
}
|
|
139
|
-
```
|
|
140
|
-
---
|
|
141
|
-
|
|
142
|
-
## Cookies
|
|
143
|
-
```
|
|
144
|
-
Config.cookies = {
|
|
145
|
-
'My Admin User': 'my-cookie=1;Path=/;SameSite=strict',
|
|
146
|
-
'My Normal User': 'my-cookie=0;Path=/;SameSite=strict'
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
160
|
|
|
150
161
|
---
|
|
151
162
|
## Mock Precedence
|
|
@@ -197,7 +208,23 @@ other words, only one transform per route is supported in demo mode.
|
|
|
197
208
|
|
|
198
209
|
---
|
|
199
210
|
|
|
200
|
-
##
|
|
211
|
+
## API
|
|
212
|
+
|
|
213
|
+
### Changing a mock for one route
|
|
214
|
+
```
|
|
215
|
+
PATCH http://localhost:2345/mockaton/edit
|
|
216
|
+
{
|
|
217
|
+
"file": "api/foo.200.GET.json"
|
|
218
|
+
"delayed": true // optional
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Bulk Selecting Mocks by Matching comments
|
|
223
|
+
```
|
|
224
|
+
PATCH http://localhost:2345/mockaton/bulk-select
|
|
225
|
+
{ "comment": "demo-a" }
|
|
226
|
+
```
|
|
227
|
+
|
|
201
228
|
Many mocks can be changed at once. We do that by searching the
|
|
202
229
|
comments on the filename. For example, `api/foo(demo-a).GET.200.json`
|
|
203
230
|
|
|
@@ -209,3 +236,4 @@ Similarly, if there’s no demo mock at all for
|
|
|
209
236
|
a route, the first dev mock (a-z) will be served.
|
|
210
237
|
|
|
211
238
|
|
|
239
|
+
|
package/Route.js
CHANGED
|
@@ -44,19 +44,19 @@ export class Route {
|
|
|
44
44
|
|
|
45
45
|
static parseFilename(file) {
|
|
46
46
|
const tokens = file.replace(Route.reComments, '').split('.')
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
let error = ''
|
|
49
49
|
if (tokens.length < 4)
|
|
50
50
|
error = 'Invalid Filename Convention'
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
const method = tokens.at(-3)
|
|
53
53
|
if (!httpMethods.includes(method))
|
|
54
54
|
error = `Unrecognized HTTP Method: "${method}"`
|
|
55
|
-
|
|
55
|
+
|
|
56
56
|
const status = Number(tokens.at(-2))
|
|
57
57
|
if (!responseStatusIsValid(status))
|
|
58
58
|
error = `Invalid HTTP Response Status: "${status}"`
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
return {
|
|
61
61
|
error,
|
|
62
62
|
urlMask: '/' + removeTrailingSlash(tokens.at(-4)),
|
|
@@ -84,7 +84,7 @@ function removeTrailingSlash(url = '') {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
function responseStatusIsValid(status) {
|
|
87
|
-
return Number.isInteger(status)
|
|
88
|
-
&& status >= 100
|
|
87
|
+
return Number.isInteger(status)
|
|
88
|
+
&& status >= 100
|
|
89
89
|
&& status <= 599
|
|
90
|
-
}
|
|
90
|
+
}
|
package/_usage_example.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { resolve } from 'node:path'
|
|
4
|
-
import { Mockaton } from './index.js' // from 'mockaton'
|
|
4
|
+
import { Mockaton, jwtCookie } from './index.js' // from 'mockaton'
|
|
5
5
|
|
|
6
6
|
Mockaton({
|
|
7
7
|
port: 2345,
|
|
@@ -11,4 +11,4 @@ Mockaton({
|
|
|
11
11
|
'Admin User': 'my-cookie=1;Path=/;SameSite=strict',
|
|
12
12
|
'Normal User': 'my-cookie=0;Path=/;SameSite=strict'
|
|
13
13
|
}
|
|
14
|
-
})
|
|
14
|
+
})
|
package/index.d.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { Server } from 'node:http';
|
|
2
2
|
|
|
3
3
|
interface Config {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
mocksDir: string
|
|
5
|
+
staticDir?: string
|
|
6
|
+
host?: string,
|
|
7
|
+
port?: number
|
|
8
|
+
delay?: number
|
|
9
|
+
|
|
10
|
+
cookies?(): object
|
|
11
|
+
|
|
12
|
+
database?: object
|
|
13
|
+
skipOpen?: boolean
|
|
14
|
+
allowedExt?: RegExp
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
export function Mockaton(options: Config): Server
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
"name": "mockaton",
|
|
3
|
+
"description": "A deterministic server-side for developing and testing frontend clients",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"version": "0.9.2",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"types": "index.d.ts",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"repository": "https://github.com/ericfortis/mockaton",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "./Tests.js",
|
|
12
|
+
"demo": "_usage_example.js"
|
|
13
|
+
}
|
|
14
14
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
2
|
+
"_": "An example response of a user without friends. Uses HTTP Status: 204 - No Content",
|
|
3
|
+
"friends": []
|
|
4
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
2
|
+
"_": "This file has a comment: `(assorted)`. i.e. the route is /api/user/videos",
|
|
3
|
+
"videos": [
|
|
4
|
+
{
|
|
5
|
+
"url": "https://example.com/1",
|
|
6
|
+
"verified": true
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"url": "https://example.com/2",
|
|
10
|
+
"verified": false
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
2
|
+
"_": "This file has a comment: `(entirely unverified)`. i.e. the route is /api/user/videos",
|
|
3
|
+
"videos": [
|
|
4
|
+
{
|
|
5
|
+
"url": "https://example.com/1",
|
|
6
|
+
"verified": false
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"url": "https://example.com/2",
|
|
10
|
+
"verified": false
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
2
|
+
"_": "This file has two comments: `(entirely verified)` and `(another comment)`. i.e. the route is /api/user/videos",
|
|
3
|
+
"videos": [
|
|
4
|
+
{
|
|
5
|
+
"url": "https://example.com/1",
|
|
6
|
+
"verified": true
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"url": "https://example.com/2",
|
|
10
|
+
"verified": true
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
2
|
+
"_": "This route has a dynamic param `<id>`. i.e. /api/video/123",
|
|
3
|
+
"url": "https://example.com/123"
|
|
4
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
2
|
+
"_": "This file has query string params, but they are fully ignored. i.e. /api/video/list and /api/video/list?page_num=1 would match as well",
|
|
3
|
+
"videos": [
|
|
4
|
+
{
|
|
5
|
+
"url": "https://example.com/1"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"url": "https://example.com/2"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
2
|
+
"_": "Example filename with a query string. BTW, it doesn't work on Windows, because '?' is an illegal character. At any rate, the full query string is ignored.",
|
|
3
|
+
"data": []
|
|
4
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
}
|
|
2
|
+
"created": "OK"
|
|
3
|
+
}
|
package/utils/jwt.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
export function jwtCookie(cookieName, payload) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
return [
|
|
3
|
+
`${cookieName}=${jwt(payload)}`,
|
|
4
|
+
'Path=/',
|
|
5
|
+
'SameSite=strict'
|
|
6
|
+
].join(';')
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
function jwt(payload) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
return [
|
|
11
|
+
'Header_Not_In_Use',
|
|
12
|
+
toBase64Url(payload),
|
|
13
|
+
'Signature_Not_In_Use'
|
|
14
|
+
].join('.')
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
function toBase64Url(obj) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
return btoa(JSON.stringify(obj))
|
|
19
|
+
.replace('+', '-')
|
|
20
|
+
.replace('/', '_')
|
|
21
21
|
}
|