mockaton 8.1.7 → 8.2.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-dashboard-dark.png +0 -0
- package/README-dashboard-light.png +0 -0
- package/README.md +14 -0
- package/index.d.ts +5 -0
- package/index.js +3 -1
- package/package.json +5 -4
- package/src/Api.js +10 -3
- package/src/Commander.js +3 -0
- package/src/Dashboard.css +26 -16
- package/src/Dashboard.js +29 -4
- package/src/mockaton-logo.svg +1 -1
- package/src/utils/http-response.js +10 -4
- package/ui-tests/_setup.js +6 -1
- package/ui-tests/bulk-select.vp1024x800.dark.gold.png +0 -0
- package/ui-tests/bulk-select.vp1024x800.light.gold.png +0 -0
- package/ui-tests/initial-dashboard-state.vp1024x800.dark.gold.png +0 -0
- package/ui-tests/initial-dashboard-state.vp1024x800.light.gold.png +0 -0
- package/ui-tests/payload-viewer-formats-json.vp1024x800.dark.gold.png +0 -0
- package/ui-tests/payload-viewer-formats-json.vp1024x800.light.gold.png +0 -0
- package/ui-tests/payload-viewer-renders-images.vp1024x800.dark.gold.png +0 -0
- package/ui-tests/payload-viewer-renders-images.vp1024x800.light.gold.png +0 -0
- package/ui-tests/select-mock-variant.vp1024x800.dark.gold.png +0 -0
- package/ui-tests/select-mock-variant.vp1024x800.light.gold.png +0 -0
|
Binary file
|
|
Binary file
|
package/README.md
CHANGED
|
@@ -127,6 +127,7 @@ database, or pull data from a backend.
|
|
|
127
127
|
Don’t call `response.end()`, just return a `string | Buffer | Uint8Array`.
|
|
128
128
|
|
|
129
129
|
```js
|
|
130
|
+
|
|
130
131
|
export default function optionalName(request, response) {
|
|
131
132
|
globalThis.myDatabase ??= { count: 0 }
|
|
132
133
|
globalThis.myDatabase.count++
|
|
@@ -142,6 +143,19 @@ export default function optionalName(request, response) {
|
|
|
142
143
|
If you need to serve a static `.js` file, put it in your
|
|
143
144
|
`Config.staticDir` without the mock filename convention.
|
|
144
145
|
|
|
146
|
+
This example will echo back the request body concatenated with another fixture.
|
|
147
|
+
```js
|
|
148
|
+
// api/color.POST.201.js
|
|
149
|
+
|
|
150
|
+
import colors from './colors.json' with { type: 'json' }
|
|
151
|
+
import { parseJSON } from 'mockaton' // body-parser alike
|
|
152
|
+
|
|
153
|
+
export default async function concatColor(request, response) {
|
|
154
|
+
const newColor = await parseJSON(request)
|
|
155
|
+
return JSON.stringify(colors.concat(newColor))
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
145
159
|
---
|
|
146
160
|
|
|
147
161
|
## Mock File Name Convention
|
package/index.d.ts
CHANGED
|
@@ -42,8 +42,13 @@ export function Mockaton(options: Config): Server
|
|
|
42
42
|
|
|
43
43
|
export const jsToJsonPlugin: Plugin
|
|
44
44
|
|
|
45
|
+
|
|
46
|
+
// Utils
|
|
47
|
+
|
|
45
48
|
export function jwtCookie(cookieName: string, payload: any): string
|
|
46
49
|
|
|
50
|
+
export function parseJSON(request: IncomingMessage): Promise<any>
|
|
51
|
+
|
|
47
52
|
|
|
48
53
|
export class Commander {
|
|
49
54
|
constructor(addr: string)
|
package/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { Mockaton } from './src/Mockaton.js'
|
|
2
|
-
export { jwtCookie } from './src/utils/jwt.js'
|
|
3
2
|
export { Commander } from './src/Commander.js'
|
|
4
3
|
export { jsToJsonPlugin } from './src/MockDispatcherPlugins.js'
|
|
4
|
+
|
|
5
|
+
export { jwtCookie } from './src/utils/jwt.js'
|
|
6
|
+
export { parseJSON } from './src/utils/http-request.js'
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "mockaton",
|
|
3
3
|
"description": "A deterministic server-side for developing and testing frontend clients",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "8.1
|
|
5
|
+
"version": "8.2.1",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"types": "index.d.ts",
|
|
8
8
|
"license": "MIT",
|
|
@@ -11,10 +11,11 @@
|
|
|
11
11
|
"test": "node --test src/**.test.js",
|
|
12
12
|
"demo": "node _usage_example.js",
|
|
13
13
|
"demo:ts": "node --import=tsx _usage_example.js",
|
|
14
|
-
"demo:test-ui": "node --test --import=./ui-tests/_setup.js --experimental-test-isolation=none \"./ui-tests/**/*.test.js\""
|
|
14
|
+
"demo:test-ui": "node --test --import=./ui-tests/_setup.js --experimental-test-isolation=none \"./ui-tests/**/*.test.js\"",
|
|
15
|
+
"outdated": "npm outdated --parseable | awk -F: '{ printf \"npm i %-30s ;# %s\\n\", $4, $2 }'"
|
|
15
16
|
},
|
|
16
17
|
"optionalDependencies": {
|
|
17
|
-
"
|
|
18
|
-
"
|
|
18
|
+
"pixaton": ">=1.0.1",
|
|
19
|
+
"puppeteer": ">=23.10.1"
|
|
19
20
|
}
|
|
20
21
|
}
|
package/src/Api.js
CHANGED
|
@@ -10,7 +10,7 @@ import { DF, API } from './ApiConstants.js'
|
|
|
10
10
|
import { parseJSON } from './utils/http-request.js'
|
|
11
11
|
import { listFilesRecursively } from './utils/fs.js'
|
|
12
12
|
import * as mockBrokersCollection from './mockBrokersCollection.js'
|
|
13
|
-
import { sendOK, sendBadRequest, sendJSON, sendFile } from './utils/http-response.js'
|
|
13
|
+
import { sendOK, sendBadRequest, sendJSON, sendFile, sendUnprocessableContent } from './utils/http-response.js'
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
export const apiGetRequests = new Map([
|
|
@@ -24,6 +24,7 @@ export const apiGetRequests = new Map([
|
|
|
24
24
|
[API.mocks, listMockBrokers],
|
|
25
25
|
[API.cookies, listCookies],
|
|
26
26
|
[API.comments, listComments],
|
|
27
|
+
[API.fallback, getProxyFallback],
|
|
27
28
|
[API.cors, getIsCorsAllowed],
|
|
28
29
|
[API.static, listStaticFiles]
|
|
29
30
|
])
|
|
@@ -44,6 +45,7 @@ function serveDashboardAsset(req, response) { sendFile(response, join(import.met
|
|
|
44
45
|
function listCookies(_, response) { sendJSON(response, cookie.list()) }
|
|
45
46
|
function listComments(_, response) { sendJSON(response, mockBrokersCollection.extractAllComments()) }
|
|
46
47
|
function listMockBrokers(_, response) { sendJSON(response, mockBrokersCollection.getAll()) }
|
|
48
|
+
function getProxyFallback(_, response) { sendJSON(response, Config.proxyFallback) }
|
|
47
49
|
function getIsCorsAllowed(_, response) { sendJSON(response, Config.corsAllowed) }
|
|
48
50
|
|
|
49
51
|
|
|
@@ -101,8 +103,13 @@ async function setRouteIsDelayed(req, response) {
|
|
|
101
103
|
|
|
102
104
|
async function updateProxyFallback(req, response) {
|
|
103
105
|
try {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
const fallback = await parseJSON(req)
|
|
107
|
+
if (fallback && !URL.canParse(fallback)) // TESTME
|
|
108
|
+
sendUnprocessableContent(response)
|
|
109
|
+
else {
|
|
110
|
+
Config.proxyFallback = fallback
|
|
111
|
+
sendOK(response)
|
|
112
|
+
}
|
|
106
113
|
}
|
|
107
114
|
catch (error) {
|
|
108
115
|
sendBadRequest(response, error)
|
package/src/Commander.js
CHANGED
package/src/Dashboard.css
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
:root {
|
|
2
|
-
--boxShadow1: 0 2px 1px -1px rgba(0, 0, 0, 0.
|
|
2
|
+
--boxShadow1: 0 2px 1px -1px rgba(0, 0, 0, 0.1), 0 1px 1px 0 rgba(0, 0, 0, 0.1), 0 1px 3px 0 rgba(0, 0, 0, 0.08);
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
@media (prefers-color-scheme: light) {
|
|
6
6
|
:root {
|
|
7
7
|
--color4xxBackground: #ffedd1;
|
|
8
|
-
--colorAccent: #
|
|
9
|
-
--colorAccentAlt: #
|
|
8
|
+
--colorAccent: #0081ef;
|
|
9
|
+
--colorAccentAlt: #009c71;
|
|
10
10
|
--colorBackground: #fff;
|
|
11
|
-
--colorHeaderBackground: #
|
|
11
|
+
--colorHeaderBackground: #f7f7f7;
|
|
12
12
|
--colorComboBoxBackground: #fafafa;
|
|
13
13
|
--colorComboBoxHeaderBackground: #fff;
|
|
14
14
|
--colorDisabled: #444;
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
@media (prefers-color-scheme: dark) {
|
|
24
24
|
:root {
|
|
25
25
|
--color4xxBackground: #403630;
|
|
26
|
-
--colorAccent: #
|
|
27
|
-
--colorAccentAlt: #
|
|
26
|
+
--colorAccent: #2495ff;
|
|
27
|
+
--colorAccentAlt: #00bf64;
|
|
28
28
|
--colorBackground: #161616;
|
|
29
29
|
--colorHeaderBackground: #090909;
|
|
30
30
|
--colorComboBoxBackground: #252525;
|
|
@@ -61,8 +61,8 @@ select {
|
|
|
61
61
|
background: var(--colorComboBoxBackground);
|
|
62
62
|
color: var(--colorText);
|
|
63
63
|
cursor: pointer;
|
|
64
|
-
border-radius: 4px;
|
|
65
64
|
outline: 0;
|
|
65
|
+
border-radius: 6px;
|
|
66
66
|
|
|
67
67
|
&:enabled {
|
|
68
68
|
box-shadow: var(--boxShadow1);
|
|
@@ -84,15 +84,16 @@ menu {
|
|
|
84
84
|
display: flex;
|
|
85
85
|
width: 100%;
|
|
86
86
|
align-items: flex-end;
|
|
87
|
-
padding:
|
|
87
|
+
padding: 16px;
|
|
88
88
|
border-bottom: 1px solid rgba(127, 127, 127, 0.1);
|
|
89
89
|
background: var(--colorHeaderBackground);
|
|
90
|
-
|
|
90
|
+
box-shadow: var(--boxShadow1);
|
|
91
|
+
gap: 12px;
|
|
91
92
|
|
|
92
93
|
img {
|
|
93
94
|
width: 130px;
|
|
94
95
|
align-self: center;
|
|
95
|
-
margin-right:
|
|
96
|
+
margin-right: 18px;
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
label {
|
|
@@ -102,13 +103,23 @@ menu {
|
|
|
102
103
|
font-size: 11px;
|
|
103
104
|
}
|
|
104
105
|
|
|
106
|
+
input[type=url],
|
|
105
107
|
select {
|
|
108
|
+
height: 24px;
|
|
106
109
|
width: 150px;
|
|
107
|
-
padding: 4px;
|
|
110
|
+
padding: 4px 2px;
|
|
108
111
|
border-right: 3px solid transparent;
|
|
109
112
|
margin-top: 2px;
|
|
110
113
|
font-size: 11px;
|
|
111
114
|
background: var(--colorComboBoxHeaderBackground);
|
|
115
|
+
border-radius: 6px;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
input[type=url] {
|
|
119
|
+
outline: 0;
|
|
120
|
+
padding: 0 6px;
|
|
121
|
+
box-shadow: var(--boxShadow1);
|
|
122
|
+
color: var(--colorText);
|
|
112
123
|
}
|
|
113
124
|
}
|
|
114
125
|
|
|
@@ -139,7 +150,7 @@ menu {
|
|
|
139
150
|
main {
|
|
140
151
|
display: flex;
|
|
141
152
|
align-items: flex-start;
|
|
142
|
-
margin-top:
|
|
153
|
+
margin-top: 56px;
|
|
143
154
|
|
|
144
155
|
> table {
|
|
145
156
|
border-collapse: collapse;
|
|
@@ -159,7 +170,7 @@ main {
|
|
|
159
170
|
|
|
160
171
|
.PayloadViewer {
|
|
161
172
|
position: sticky;
|
|
162
|
-
top:
|
|
173
|
+
top: 62px;
|
|
163
174
|
width: 50%;
|
|
164
175
|
margin-left: 20px;
|
|
165
176
|
|
|
@@ -190,7 +201,7 @@ main {
|
|
|
190
201
|
display: inline-block;
|
|
191
202
|
width: 280px;
|
|
192
203
|
padding: 8px 6px;
|
|
193
|
-
border-radius:
|
|
204
|
+
border-radius: 6px;
|
|
194
205
|
color: var(--colorAccent);
|
|
195
206
|
text-decoration: none;
|
|
196
207
|
|
|
@@ -209,7 +220,6 @@ main {
|
|
|
209
220
|
padding: 8px 1px;
|
|
210
221
|
border: 0;
|
|
211
222
|
border-left: 3px solid transparent;
|
|
212
|
-
border-radius: 0;
|
|
213
223
|
text-align: right;
|
|
214
224
|
direction: rtl;
|
|
215
225
|
text-overflow: ellipsis;
|
|
@@ -260,7 +270,7 @@ main {
|
|
|
260
270
|
|
|
261
271
|
.InternalServerErrorToggler {
|
|
262
272
|
display: flex;
|
|
263
|
-
margin-left:
|
|
273
|
+
margin-left: 8px;
|
|
264
274
|
cursor: pointer;
|
|
265
275
|
|
|
266
276
|
> input {
|
package/src/Dashboard.js
CHANGED
|
@@ -12,6 +12,8 @@ const Strings = {
|
|
|
12
12
|
cookie_disabled_title: 'No cookies specified in Config.cookies',
|
|
13
13
|
delay: 'Delay',
|
|
14
14
|
empty_response_body: '/* Empty Response Body */',
|
|
15
|
+
fallback_server: 'Fallback Server',
|
|
16
|
+
fallback_server_placeholder: 'Type Server Address',
|
|
15
17
|
internal_server_error: 'Internal Server Error',
|
|
16
18
|
mock: 'Mock',
|
|
17
19
|
reset: 'Reset',
|
|
@@ -46,6 +48,7 @@ function init() {
|
|
|
46
48
|
mockaton.listCookies(),
|
|
47
49
|
mockaton.listComments(),
|
|
48
50
|
mockaton.getCorsAllowed(),
|
|
51
|
+
mockaton.getProxyFallback(),
|
|
49
52
|
mockaton.listStaticFiles()
|
|
50
53
|
].map(api => api.then(response => response.ok && response.json())))
|
|
51
54
|
.then(App)
|
|
@@ -59,13 +62,14 @@ function App(apiResponses) {
|
|
|
59
62
|
.render(DevPanel(apiResponses))
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
function DevPanel([brokersByMethod, cookies, comments, corsAllowed, staticFiles]) {
|
|
65
|
+
function DevPanel([brokersByMethod, cookies, comments, corsAllowed, fallbackAddress, staticFiles]) {
|
|
63
66
|
return (
|
|
64
67
|
r('div', null,
|
|
65
68
|
r('menu', null,
|
|
66
69
|
r('img', { src: '/mockaton-logo.svg', width: 160, alt: Strings.title }),
|
|
67
70
|
r(CookieSelector, { list: cookies }),
|
|
68
71
|
r(BulkSelector, { comments }),
|
|
72
|
+
r(ProxyFallbackField, { fallbackAddress }),
|
|
69
73
|
r(CorsCheckbox, { corsAllowed }),
|
|
70
74
|
r(ResetButton)),
|
|
71
75
|
r('main', null,
|
|
@@ -124,6 +128,29 @@ function BulkSelector({ comments }) {
|
|
|
124
128
|
}
|
|
125
129
|
|
|
126
130
|
|
|
131
|
+
function ProxyFallbackField({ fallbackAddress = '' }) {
|
|
132
|
+
function onChange(event) {
|
|
133
|
+
const input = event.currentTarget
|
|
134
|
+
if (!input.validity.valid)
|
|
135
|
+
input.reportValidity()
|
|
136
|
+
else
|
|
137
|
+
mockaton.setProxyFallback(input.value)
|
|
138
|
+
.catch(console.error)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
r('label', null,
|
|
143
|
+
r('span', null, Strings.fallback_server),
|
|
144
|
+
r('input', {
|
|
145
|
+
type: 'url',
|
|
146
|
+
autocomplete: 'none',
|
|
147
|
+
placeholder: Strings.fallback_server_placeholder,
|
|
148
|
+
value: fallbackAddress,
|
|
149
|
+
onChange
|
|
150
|
+
})))
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
|
|
127
154
|
function CorsCheckbox({ corsAllowed }) {
|
|
128
155
|
function onChange(event) {
|
|
129
156
|
mockaton.setCorsAllowed(event.currentTarget.checked)
|
|
@@ -148,8 +175,7 @@ function ResetButton() {
|
|
|
148
175
|
.then(init)
|
|
149
176
|
.catch(console.error)
|
|
150
177
|
}
|
|
151
|
-
}, Strings.reset)
|
|
152
|
-
)
|
|
178
|
+
}, Strings.reset))
|
|
153
179
|
}
|
|
154
180
|
|
|
155
181
|
|
|
@@ -272,7 +298,6 @@ function MockSelector({ broker }) {
|
|
|
272
298
|
.catch(console.error)
|
|
273
299
|
}
|
|
274
300
|
|
|
275
|
-
|
|
276
301
|
function className(defaultIsSelected, status) {
|
|
277
302
|
return cssClass(
|
|
278
303
|
CSS.MockSelector,
|
package/src/mockaton-logo.svg
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<svg version="1.1" viewBox="0 0 570 100" xmlns="http://www.w3.org/2000/svg">
|
|
3
3
|
<style>
|
|
4
4
|
:root { --color: #000000; }
|
|
5
|
-
@media (prefers-color-scheme: light) { :root { --color: #
|
|
5
|
+
@media (prefers-color-scheme: light) { :root { --color: #555 } }
|
|
6
6
|
@media (prefers-color-scheme: dark) { :root { --color: #eee } }
|
|
7
7
|
path { fill: var(--color) }
|
|
8
8
|
</style>
|
|
@@ -17,12 +17,12 @@ export function sendJSON(response, payload) {
|
|
|
17
17
|
response.end(JSON.stringify(payload))
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export function sendFile(response,
|
|
21
|
-
if (!isFile(
|
|
20
|
+
export function sendFile(response, filePath) {
|
|
21
|
+
if (!isFile(filePath))
|
|
22
22
|
sendNotFound(response)
|
|
23
23
|
else {
|
|
24
|
-
response.setHeader('Content-Type', mimeFor(
|
|
25
|
-
response.end(read(
|
|
24
|
+
response.setHeader('Content-Type', mimeFor(filePath))
|
|
25
|
+
response.end(read(filePath))
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -64,6 +64,12 @@ export function sendNotFound(response) {
|
|
|
64
64
|
response.end()
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
export function sendUnprocessableContent(response, error) {
|
|
68
|
+
console.error(error)
|
|
69
|
+
response.statusCode = 422
|
|
70
|
+
response.end(error)
|
|
71
|
+
}
|
|
72
|
+
|
|
67
73
|
export function sendInternalServerError(response, error) {
|
|
68
74
|
console.error(error)
|
|
69
75
|
response.statusCode = 500
|
package/ui-tests/_setup.js
CHANGED
|
@@ -26,7 +26,12 @@ after(() => {
|
|
|
26
26
|
|
|
27
27
|
export function testPixels(testFileName, options = {}) {
|
|
28
28
|
options.beforeSuite = async () => await mockaton.reset()
|
|
29
|
-
options.viewports ??= [{
|
|
29
|
+
options.viewports ??= [{
|
|
30
|
+
width: 1024,
|
|
31
|
+
height: 800,
|
|
32
|
+
deviceScaleFactor: 1.5 // for better screenshots
|
|
33
|
+
}]
|
|
30
34
|
options.colorSchemes ??= ['light', 'dark']
|
|
35
|
+
options.screenshotOptions ??= {}
|
|
31
36
|
_testPixels(page, testFileName, MOCKATON_ADDR + '/mockaton', 'body', options)
|
|
32
37
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|