mockaton 0.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/Api.js +108 -0
- package/ApiConstants.js +22 -0
- package/Config.js +41 -0
- package/Dashboard.css +206 -0
- package/Dashboard.html +12 -0
- package/Dashboard.js +355 -0
- package/LICENSE +21 -0
- package/MockBroker.js +107 -0
- package/MockDispatcher.js +72 -0
- package/Mockaton.js +39 -0
- package/README-dashboard-dropdown.png +0 -0
- package/README-dashboard.png +0 -0
- package/README-mocks-with-comments.png +0 -0
- package/README.md +211 -0
- package/Route.js +90 -0
- package/StaticDispatcher.js +29 -0
- package/Tests.js +367 -0
- package/_usage_example.js +14 -0
- package/cookie.js +29 -0
- package/index.d.ts +17 -0
- package/index.js +2 -0
- package/mockBrokersCollection.js +84 -0
- package/package.json +12 -0
- package/sample-mocks/api/user/.GET.200.json +1 -0
- package/sample-mocks/api/user/.GET.501.txt +7 -0
- package/sample-mocks/api/user/edit-name.PATCH.200.json +1 -0
- package/sample-mocks/api/user/edit-name.PATCH.200.md +12 -0
- package/sample-mocks/api/user/edit-name.PATCH.501.txt +0 -0
- package/sample-mocks/api/user/friends.GET.200.json +1 -0
- package/sample-mocks/api/user/friends.GET.204.json +4 -0
- package/sample-mocks/api/user/friends.GET.501.txt +0 -0
- package/sample-mocks/api/user/logout.POST.200.json +1 -0
- package/sample-mocks/api/user/logout.POST.501.txt +0 -0
- package/sample-mocks/api/user/videos(assorted).GET.200.json +13 -0
- package/sample-mocks/api/user/videos(entirely unverified).GET.200.json +13 -0
- package/sample-mocks/api/user/videos(entirely verified)(another comment).GET.200.json +13 -0
- package/sample-mocks/api/user/videos.GET.501.txt +0 -0
- package/sample-mocks/api/video/[id].GET.200.json +4 -0
- package/sample-mocks/api/video/[id].GET.501.txt +0 -0
- package/sample-mocks/api/video/list(concat newly uploaded).GET.200.mjs +8 -0
- package/sample-mocks/api/video/list.GET.200.json +11 -0
- package/sample-mocks/api/video/list.GET.501.txt +0 -0
- package/sample-mocks/api/video/stat/[stat-id]/[video-id].GET.200.json +1 -0
- package/sample-mocks/api/video/stat/[stat-id]/[video-id].GET.501.txt +0 -0
- package/sample-mocks/api/video/stat/[stat-id]/all-videos?limit=[limit].GET.200.json +4 -0
- package/sample-mocks/api/video/stat/[stat-id]/all-videos?limit=[limit].GET.501.txt +0 -0
- package/sample-mocks/api/video/upload(insert newly uploaded).POST.201.mjs +10 -0
- package/sample-mocks/api/video/upload.POST.201.json +3 -0
- package/sample-mocks/api/video/upload.POST.501.txt +0 -0
- package/sample-static/another-entry/index.html +12 -0
- package/sample-static/assets/app.js +1 -0
- package/sample-static/assets/video.mp4 +0 -0
- package/sample-static/index.html +13 -0
- package/utils/http-request.js +36 -0
- package/utils/http-response.js +60 -0
- package/utils/jwt.js +21 -0
- package/utils/mime.js +47 -0
- package/utils/validate.js +17 -0
package/Api.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API for controlling the mock server. For example,
|
|
3
|
+
* setting a specific mock-file for a particular route.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { join } from 'node:path'
|
|
7
|
+
import { cookie } from './cookie.js'
|
|
8
|
+
import { Config } from './Config.js'
|
|
9
|
+
import { DF, DP } from './ApiConstants.js'
|
|
10
|
+
import { parseJSON } from './utils/http-request.js'
|
|
11
|
+
import * as mockBrokersCollection from './mockBrokersCollection.js'
|
|
12
|
+
import { sendOK, sendBadRequest, sendJSON, sendFile } from './utils/http-response.js'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
export const apiGetRequests = new Map([
|
|
16
|
+
[DP.dashboard, serveDashboard],
|
|
17
|
+
['/Route.js', serveDashboardAsset],
|
|
18
|
+
['/Dashboard.js', serveDashboardAsset],
|
|
19
|
+
['/Dashboard.css', serveDashboardAsset],
|
|
20
|
+
['/ApiConstants.js', serveDashboardAsset],
|
|
21
|
+
[DP.mocks, listMockBrokers],
|
|
22
|
+
[DP.cookies, listCookies],
|
|
23
|
+
[DP.comments, listComments]
|
|
24
|
+
])
|
|
25
|
+
|
|
26
|
+
export const apiPatchRequests = new Map([
|
|
27
|
+
[DP.bulkSelect, bulkUpdateBrokersByCommentTag],
|
|
28
|
+
[DP.edit, updateBroker],
|
|
29
|
+
[DP.reset, reinitialize],
|
|
30
|
+
[DP.cookies, selectCookie],
|
|
31
|
+
[DP.transform, updateBrokerTransform]
|
|
32
|
+
])
|
|
33
|
+
|
|
34
|
+
function serveDashboard(_, response) {
|
|
35
|
+
sendFile(response, join(import.meta.dirname, 'Dashboard.html'))
|
|
36
|
+
}
|
|
37
|
+
function serveDashboardAsset(req, response) {
|
|
38
|
+
sendFile(response, join(import.meta.dirname, req.url))
|
|
39
|
+
}
|
|
40
|
+
function listCookies(_, response) {
|
|
41
|
+
sendJSON(response, cookie.list())
|
|
42
|
+
}
|
|
43
|
+
function listComments(_, response) {
|
|
44
|
+
sendJSON(response, mockBrokersCollection.extractAllComments())
|
|
45
|
+
}
|
|
46
|
+
function listMockBrokers(_, response) {
|
|
47
|
+
sendJSON(response, mockBrokersCollection.getAll())
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
async function selectCookie(req, response) {
|
|
52
|
+
try {
|
|
53
|
+
const body = await parseJSON(req)
|
|
54
|
+
cookie.setCurrent(body[DF.currentCookieKey])
|
|
55
|
+
sendOK(response)
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.error(error)
|
|
59
|
+
sendBadRequest(response)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function reinitialize(_, response) {
|
|
64
|
+
Config.database = {}
|
|
65
|
+
mockBrokersCollection.init()
|
|
66
|
+
sendOK(response)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function updateBroker(req, response) {
|
|
70
|
+
try {
|
|
71
|
+
const body = await parseJSON(req)
|
|
72
|
+
const broker = mockBrokersCollection.getBrokerByFilename(body[DF.file])
|
|
73
|
+
if (DF.delayed in body)
|
|
74
|
+
broker.updateDelay(body[DF.delayed])
|
|
75
|
+
else
|
|
76
|
+
broker.updateFile(body[DF.file])
|
|
77
|
+
sendOK(response)
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
console.error(error)
|
|
81
|
+
sendBadRequest(response)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function bulkUpdateBrokersByCommentTag(req, response) {
|
|
86
|
+
try {
|
|
87
|
+
const body = await parseJSON(req)
|
|
88
|
+
mockBrokersCollection.setMocksMatchingComment(body[DF.comment])
|
|
89
|
+
sendOK(response)
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
console.error(error)
|
|
93
|
+
sendBadRequest(response)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function updateBrokerTransform(req, response) {
|
|
98
|
+
try {
|
|
99
|
+
const body = await parseJSON(req)
|
|
100
|
+
const broker = mockBrokersCollection.getBroker(body[DF.method], body[DF.urlMask])
|
|
101
|
+
broker.updateTransform(body[DF.file])
|
|
102
|
+
sendOK(response)
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
console.error(error)
|
|
106
|
+
sendBadRequest(response)
|
|
107
|
+
}
|
|
108
|
+
}
|
package/ApiConstants.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const MOUNT = '/mockaton'
|
|
2
|
+
export const DP = { // Dashboard Paths
|
|
3
|
+
dashboard: MOUNT,
|
|
4
|
+
bulkSelect: MOUNT + '/bulk-select',
|
|
5
|
+
comments: MOUNT + '/comments',
|
|
6
|
+
edit: MOUNT + '/edit',
|
|
7
|
+
mocks: MOUNT + '/mocks',
|
|
8
|
+
reset: MOUNT + '/reset',
|
|
9
|
+
transform: MOUNT + '/transform',
|
|
10
|
+
cookies: MOUNT + '/cookies'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const DF = { // Dashboard Fields (XHR)
|
|
14
|
+
comment: 'comment',
|
|
15
|
+
delayed: 'delayed',
|
|
16
|
+
file: 'file',
|
|
17
|
+
isAdmin: 'is_admin',
|
|
18
|
+
currentCookieKey: 'current_cookie_key',
|
|
19
|
+
isForDashboard: 'mock_request_payload',
|
|
20
|
+
method: 'method',
|
|
21
|
+
urlMask: 'url_mask'
|
|
22
|
+
}
|
package/Config.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { existsSync, lstatSync } from 'node:fs'
|
|
2
|
+
import { validate } from './utils/validate.js'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export const Config = {
|
|
6
|
+
mocksDir: '',
|
|
7
|
+
staticDir: '',
|
|
8
|
+
host: '127.0.0.1',
|
|
9
|
+
port: 0, // auto-assigned
|
|
10
|
+
delay: 1200, // milliseconds
|
|
11
|
+
cookies: {}, // defaults to the first kv
|
|
12
|
+
database: {},
|
|
13
|
+
skipOpen: false, // Prevents opening the dashboard in a browser
|
|
14
|
+
allowedExt: /\.(json|txt|md|mjs)$/ // Just for excluding temporary editor files (e.g. JetBrains appends a ~)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function setup(options) {
|
|
18
|
+
Object.assign(Config, options)
|
|
19
|
+
validate(Config, {
|
|
20
|
+
mocksDir: isDirectory,
|
|
21
|
+
staticDir: optional(isDirectory),
|
|
22
|
+
host: String,
|
|
23
|
+
port: port => Number.isInteger(port) && port >= 0 && port < 2 ** 16,
|
|
24
|
+
delay: ms => Number.isInteger(ms) && ms > 0,
|
|
25
|
+
cookies: Object,
|
|
26
|
+
database: Object,
|
|
27
|
+
skipOpen: Boolean,
|
|
28
|
+
allowedExt: RegExp
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
function optional(tester) {
|
|
34
|
+
return val => !val || tester(val)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isDirectory(dir) {
|
|
38
|
+
return existsSync(dir) && lstatSync(dir).isDirectory()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
package/Dashboard.css
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--colorAccent: #0069d0;
|
|
3
|
+
--colorHover: #dfefff;
|
|
4
|
+
--colorRed: #da0f00;
|
|
5
|
+
--colorLightRed: #ffe4ee;
|
|
6
|
+
--colorLightOrange: #ffedd1;
|
|
7
|
+
--colorLightGrey: rgba(0, 0, 0, 0.02);
|
|
8
|
+
}
|
|
9
|
+
html, body {
|
|
10
|
+
margin: 0;
|
|
11
|
+
font-size: 13px;
|
|
12
|
+
}
|
|
13
|
+
body {
|
|
14
|
+
padding: 16px;
|
|
15
|
+
}
|
|
16
|
+
* {
|
|
17
|
+
border: 0;
|
|
18
|
+
margin: 0;
|
|
19
|
+
font-family: system-ui, sans-serif;
|
|
20
|
+
font-size: 100%;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
h1 {
|
|
24
|
+
padding: 12px 0;
|
|
25
|
+
margin: 0;
|
|
26
|
+
font-size: 2rem;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
select {
|
|
31
|
+
padding: 3px 0;
|
|
32
|
+
border: 1px solid #444;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
fieldset {
|
|
36
|
+
width: 120px;
|
|
37
|
+
border: 1px solid #ccc;
|
|
38
|
+
|
|
39
|
+
label {
|
|
40
|
+
display: flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
padding: 4px 0;
|
|
43
|
+
|
|
44
|
+
input {
|
|
45
|
+
margin-right: 6px;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.CookieSelector {
|
|
51
|
+
display: flex;
|
|
52
|
+
align-items: center;
|
|
53
|
+
margin-left: 20px;
|
|
54
|
+
|
|
55
|
+
select {
|
|
56
|
+
margin-left: 5px;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
main {
|
|
61
|
+
display: flex;
|
|
62
|
+
align-items: flex-start;
|
|
63
|
+
|
|
64
|
+
> table {
|
|
65
|
+
border-collapse: collapse;
|
|
66
|
+
|
|
67
|
+
th {
|
|
68
|
+
padding-top: 20px;
|
|
69
|
+
padding-bottom: 2px;
|
|
70
|
+
text-align: left;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.TitleWrap {
|
|
76
|
+
display: flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
|
|
79
|
+
button {
|
|
80
|
+
padding: 3px 12px;
|
|
81
|
+
border: 1px solid var(--colorRed);
|
|
82
|
+
margin-left: 20px;
|
|
83
|
+
background: transparent;
|
|
84
|
+
color: var(--colorRed);
|
|
85
|
+
border-radius: 50px;
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
|
|
88
|
+
&:hover {
|
|
89
|
+
background: var(--colorRed);
|
|
90
|
+
color: white;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.PayloadViewer {
|
|
96
|
+
position: sticky;
|
|
97
|
+
top: 0;
|
|
98
|
+
width: 50%;
|
|
99
|
+
margin-left: 16px;
|
|
100
|
+
|
|
101
|
+
pre {
|
|
102
|
+
&:not(:empty) {
|
|
103
|
+
overflow: auto;
|
|
104
|
+
max-height: calc(100vh - 160px);
|
|
105
|
+
padding: 12px;
|
|
106
|
+
margin-top: 6px;
|
|
107
|
+
background: var(--colorLightGrey);
|
|
108
|
+
font-family: monospace;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
&.Documentation {
|
|
112
|
+
margin-bottom: 12px;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.PreviewLink {
|
|
118
|
+
position: relative;
|
|
119
|
+
left: -6px;
|
|
120
|
+
display: inline-block;
|
|
121
|
+
width: 280px;
|
|
122
|
+
padding: 8px 6px;
|
|
123
|
+
color: var(--colorAccent);
|
|
124
|
+
text-decoration: none;
|
|
125
|
+
|
|
126
|
+
&:hover {
|
|
127
|
+
background: var(--colorHover);
|
|
128
|
+
}
|
|
129
|
+
&.chosen {
|
|
130
|
+
color: white;
|
|
131
|
+
background: var(--colorAccent);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.BulkSelectSection {
|
|
136
|
+
margin: 20px 0;
|
|
137
|
+
}
|
|
138
|
+
.TransformsSection {
|
|
139
|
+
padding-top: 30px;
|
|
140
|
+
border-top: 1px solid #ccc;
|
|
141
|
+
margin: 30px 0;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.BulkSelectSection select {
|
|
145
|
+
margin-top: 5px;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.TransformSelector,
|
|
149
|
+
.MockSelector {
|
|
150
|
+
width: 300px;
|
|
151
|
+
padding: 8px 1px;
|
|
152
|
+
border: 0;
|
|
153
|
+
background: #eee;
|
|
154
|
+
text-align: right;
|
|
155
|
+
direction: rtl;
|
|
156
|
+
text-overflow: ellipsis;
|
|
157
|
+
|
|
158
|
+
&:disabled {
|
|
159
|
+
background: transparent;
|
|
160
|
+
color: #222;
|
|
161
|
+
cursor: not-allowed
|
|
162
|
+
}
|
|
163
|
+
&:enabled:hover {
|
|
164
|
+
cursor: pointer;
|
|
165
|
+
background: var(--colorHover);
|
|
166
|
+
}
|
|
167
|
+
&.status4xx {
|
|
168
|
+
background: var(--colorLightOrange);
|
|
169
|
+
}
|
|
170
|
+
&.status5xx {
|
|
171
|
+
background: var(--colorLightRed);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.DelayCheckbox {
|
|
176
|
+
display: flex;
|
|
177
|
+
margin-left: 6px;
|
|
178
|
+
cursor: pointer;
|
|
179
|
+
|
|
180
|
+
> input {
|
|
181
|
+
display: none;
|
|
182
|
+
|
|
183
|
+
&:checked ~ svg {
|
|
184
|
+
border-color: white;
|
|
185
|
+
filter: invert();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
> svg {
|
|
190
|
+
width: 14px;
|
|
191
|
+
height: 14px;
|
|
192
|
+
border: 1px solid #000;
|
|
193
|
+
vertical-align: bottom;
|
|
194
|
+
fill: #000;
|
|
195
|
+
border-radius: 50%;
|
|
196
|
+
background: white;
|
|
197
|
+
|
|
198
|
+
&:hover {
|
|
199
|
+
background: #ddd
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.bold {
|
|
205
|
+
font-weight: bold;
|
|
206
|
+
}
|
package/Dashboard.html
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en-US">
|
|
3
|
+
<head>
|
|
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
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<script src="../Dashboard.js" type="module"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|