mockaton 10.6.8 → 11.0.0
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/Makefile +33 -0
- package/README.md +25 -27
- package/index.d.ts +14 -14
- package/package.json +2 -7
- package/src/Api.js +69 -51
- package/src/ApiCommander.js +22 -39
- package/src/ApiConstants.js +2 -14
- package/src/Dashboard.css +24 -8
- package/src/Dashboard.js +136 -115
- package/src/DashboardDom.js +8 -12
- package/src/DashboardStore.js +134 -119
- package/src/Filename.js +3 -3
- package/src/MockBroker.js +46 -63
- package/src/MockDispatcher.js +2 -3
- package/src/Mockaton.js +17 -15
- package/src/Watcher.js +33 -25
- package/src/config.js +1 -1
- package/src/mockBrokersCollection.js +6 -14
- package/src/utils/http-request.js +3 -3
- package/src/utils/mime.js +3 -3
package/Makefile
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
start:
|
|
2
|
+
@node src/cli.js
|
|
3
|
+
|
|
4
|
+
watch:
|
|
5
|
+
@node --watch src/cli.js
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
test:
|
|
9
|
+
node --test 'src/**/*.test.js'
|
|
10
|
+
|
|
11
|
+
test-docker:
|
|
12
|
+
docker run --rm -it \
|
|
13
|
+
-v "$$PWD":/app \
|
|
14
|
+
-w /app \
|
|
15
|
+
node:24 \
|
|
16
|
+
make test
|
|
17
|
+
|
|
18
|
+
coverage:
|
|
19
|
+
node --test --experimental-test-coverage \
|
|
20
|
+
--test-reporter=spec --test-reporter-destination=stdout \
|
|
21
|
+
--test-reporter=lcov --test-reporter-destination=lcov.info \
|
|
22
|
+
'src/**/*.test.js'
|
|
23
|
+
|
|
24
|
+
pixaton:
|
|
25
|
+
node --test --experimental-test-isolation=none \
|
|
26
|
+
--import=./pixaton-tests/_setup.js \
|
|
27
|
+
'pixaton-tests/**/*.test.js'
|
|
28
|
+
|
|
29
|
+
outdated:
|
|
30
|
+
@npm outdated --parseable |\
|
|
31
|
+
awk -F: '{ printf "npm i %-30s ;# %s\n", $$4, $$2 }'
|
|
32
|
+
|
|
33
|
+
.PHONY: *
|
package/README.md
CHANGED
|
@@ -10,33 +10,6 @@
|
|
|
10
10
|
An HTTP mock server for simulating APIs with minimal setup
|
|
11
11
|
— ideal for testing difficult to reproduce states.
|
|
12
12
|
|
|
13
|
-
<br/>
|
|
14
|
-
|
|
15
|
-
## Motivation
|
|
16
|
-
|
|
17
|
-
**No API state should be too hard to test.**
|
|
18
|
-
With Mockaton, developers can achieve correctness and speed.
|
|
19
|
-
|
|
20
|
-
### Correctness
|
|
21
|
-
- Enables testing of complex scenarios that would otherwise be skipped. e.g.,
|
|
22
|
-
- Triggering errors on third-party APIs.
|
|
23
|
-
- Triggering errors on your project’s backend (if you are a frontend developer).
|
|
24
|
-
- Allows for deterministic, comprehensive, and consistent state.
|
|
25
|
-
- Spot inadvertent regressions during development.
|
|
26
|
-
- Use it to set up screenshot tests, e.g., with [pixaton](https://github.com/ericfortis/pixaton).
|
|
27
|
-
|
|
28
|
-
### Speed
|
|
29
|
-
- Works around unstable dev backends while developing UIs.
|
|
30
|
-
- Spinning up development infrastructure.
|
|
31
|
-
- Syncing database states.
|
|
32
|
-
- Prevents progress from being blocked by waiting for APIs.
|
|
33
|
-
- Time travel. If you commit the mocks to your repo,
|
|
34
|
-
you don’t have to downgrade backends for:
|
|
35
|
-
- checking out long-lived branches
|
|
36
|
-
- bisecting bugs
|
|
37
|
-
|
|
38
|
-
<br/>
|
|
39
|
-
|
|
40
13
|
## Overview
|
|
41
14
|
With Mockaton, you don’t need to write code for wiring up your
|
|
42
15
|
mocks. Instead, a given directory is scanned for filenames
|
|
@@ -118,6 +91,31 @@ checking ✅ **Save Mocks**, you can collect the responses that hit your backend
|
|
|
118
91
|
They will be saved in your `config.mocksDir` following the filename convention.
|
|
119
92
|
</details>
|
|
120
93
|
|
|
94
|
+
<br/>
|
|
95
|
+
|
|
96
|
+
## Motivation
|
|
97
|
+
|
|
98
|
+
**No API state should be too hard to test.**
|
|
99
|
+
With Mockaton, developers can achieve correctness and speed.
|
|
100
|
+
|
|
101
|
+
### Correctness
|
|
102
|
+
- Enables testing of complex scenarios that would otherwise be skipped. e.g.,
|
|
103
|
+
- Triggering errors on third-party APIs.
|
|
104
|
+
- Triggering errors on your project’s backend (if you are a frontend developer).
|
|
105
|
+
- Allows for deterministic, comprehensive, and consistent state.
|
|
106
|
+
- Spot inadvertent regressions during development.
|
|
107
|
+
- Use it to set up screenshot tests, e.g., with [pixaton](https://github.com/ericfortis/pixaton).
|
|
108
|
+
|
|
109
|
+
### Speed
|
|
110
|
+
- Works around unstable dev backends while developing UIs.
|
|
111
|
+
- Spinning up development infrastructure.
|
|
112
|
+
- Syncing database states.
|
|
113
|
+
- Prevents progress from being blocked by waiting for APIs.
|
|
114
|
+
- Time travel. If you commit the mocks to your repo,
|
|
115
|
+
you don’t have to downgrade backends for:
|
|
116
|
+
- checking out long-lived branches
|
|
117
|
+
- bisecting bugs
|
|
118
|
+
|
|
121
119
|
|
|
122
120
|
<br/>
|
|
123
121
|
|
package/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Server, IncomingMessage, OutgoingMessage } from 'node:http'
|
|
1
|
+
import { Server, IncomingMessage, OutgoingMessage } from 'node:http'
|
|
2
2
|
|
|
3
3
|
type Plugin = (
|
|
4
4
|
filePath: string,
|
|
@@ -16,7 +16,7 @@ interface Config {
|
|
|
16
16
|
|
|
17
17
|
host?: string,
|
|
18
18
|
port?: number
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
logLevel?: 'normal' | 'verbose' | 'quiet'
|
|
21
21
|
|
|
22
22
|
delay?: number
|
|
@@ -37,8 +37,8 @@ interface Config {
|
|
|
37
37
|
corsExposedHeaders?: string[]
|
|
38
38
|
corsCredentials?: boolean
|
|
39
39
|
corsMaxAge?: number
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
|
|
41
|
+
|
|
42
42
|
plugins?: [filenameTester: RegExp, plugin: Plugin][]
|
|
43
43
|
|
|
44
44
|
onReady?: (address: string) => void
|
|
@@ -64,11 +64,11 @@ export type JsonPromise<T> = Promise<Response & { json(): Promise<T> }>
|
|
|
64
64
|
|
|
65
65
|
export type ClientMockBroker = {
|
|
66
66
|
mocks: string[]
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
file: string
|
|
68
|
+
status: number
|
|
69
|
+
auto500: boolean
|
|
70
|
+
delayed: boolean
|
|
71
|
+
proxied: boolean
|
|
72
72
|
}
|
|
73
73
|
export type ClientBrokersByMethod = {
|
|
74
74
|
[method: string]: {
|
|
@@ -89,14 +89,14 @@ export type ClientStaticBrokers = {
|
|
|
89
89
|
export interface State {
|
|
90
90
|
brokersByMethod: ClientBrokersByMethod
|
|
91
91
|
staticBrokers: ClientStaticBrokers
|
|
92
|
-
|
|
93
|
-
cookies: [label:string, selected:boolean][]
|
|
92
|
+
|
|
93
|
+
cookies: [label: string, selected: boolean][]
|
|
94
94
|
comments: string[]
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
delay: number
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
collectProxied: boolean
|
|
99
99
|
proxyFallback: string
|
|
100
|
-
|
|
100
|
+
|
|
101
101
|
corsAllowed?: boolean
|
|
102
102
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "mockaton",
|
|
3
3
|
"description": "HTTP Mock Server",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "11.0.0",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"types": "index.d.ts",
|
|
8
8
|
"license": "MIT",
|
|
@@ -18,12 +18,7 @@
|
|
|
18
18
|
"mockaton": "src/cli.js"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
|
-
"
|
|
22
|
-
"coverage": "node --test --test-reporter=lcov --test-reporter-destination=lcov.info --experimental-test-coverage 'src/**/*.test.js'",
|
|
23
|
-
"start": "node src/cli.js",
|
|
24
|
-
"watch": "node --watch src/cli.js",
|
|
25
|
-
"pixaton": "node --test --import=./pixaton-tests/_setup.js --experimental-test-isolation=none 'pixaton-tests/**/*.test.js'",
|
|
26
|
-
"outdated": "npm outdated --parseable | awk -F: '{ printf \"npm i %s ;# %s\\n\", $4, $2 }'"
|
|
21
|
+
"start": "make start"
|
|
27
22
|
},
|
|
28
23
|
"devDependencies": {
|
|
29
24
|
"pixaton": "1.1.3",
|
package/src/Api.js
CHANGED
|
@@ -12,17 +12,21 @@ import * as staticCollection from './staticCollection.js'
|
|
|
12
12
|
import * as mockBrokersCollection from './mockBrokersCollection.js'
|
|
13
13
|
import { config, ConfigValidator } from './config.js'
|
|
14
14
|
import { DashboardHtml, CSP } from './DashboardHtml.js'
|
|
15
|
-
import { DF, API, LONG_POLL_SERVER_TIMEOUT } from './ApiConstants.js'
|
|
16
15
|
import { sendOK, sendJSON, sendUnprocessableContent, sendFile, sendHTML } from './utils/http-response.js'
|
|
16
|
+
import { API, LONG_POLL_SERVER_TIMEOUT, HEADER_FOR_SYNC_VERSION } from './ApiConstants.js'
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
export const apiGetRequests = new Map([
|
|
20
20
|
[API.dashboard, serveDashboard],
|
|
21
21
|
...[
|
|
22
|
+
'Logo.svg',
|
|
22
23
|
'Dashboard.css',
|
|
24
|
+
'ApiCommander.js',
|
|
25
|
+
'ApiConstants.js',
|
|
23
26
|
'Dashboard.js',
|
|
24
|
-
'
|
|
25
|
-
'
|
|
27
|
+
'DashboardDom.js',
|
|
28
|
+
'DashboardStore.js',
|
|
29
|
+
'Filename.js'
|
|
26
30
|
].map(f => [API.dashboard + '/' + f, serveStatic(f)]),
|
|
27
31
|
|
|
28
32
|
[API.state, getState],
|
|
@@ -57,6 +61,7 @@ function serveStatic(f) {
|
|
|
57
61
|
return (_, response) => sendFile(response, join(import.meta.dirname, f))
|
|
58
62
|
}
|
|
59
63
|
|
|
64
|
+
|
|
60
65
|
function getState(_, response) {
|
|
61
66
|
sendJSON(response, {
|
|
62
67
|
cookies: cookie.list(),
|
|
@@ -74,12 +79,14 @@ function getState(_, response) {
|
|
|
74
79
|
})
|
|
75
80
|
}
|
|
76
81
|
|
|
82
|
+
|
|
77
83
|
function longPollClientSyncVersion(req, response) {
|
|
78
|
-
if (uiSyncVersion.version !== Number(req.headers[
|
|
84
|
+
if (uiSyncVersion.version !== Number(req.headers[HEADER_FOR_SYNC_VERSION])) {
|
|
79
85
|
// e.g., tab was hidden while new mocks were added or removed
|
|
80
86
|
sendJSON(response, uiSyncVersion.version)
|
|
81
87
|
return
|
|
82
88
|
}
|
|
89
|
+
|
|
83
90
|
function onAddOrRemoveMock() {
|
|
84
91
|
uiSyncVersion.unsubscribe(onAddOrRemoveMock)
|
|
85
92
|
sendJSON(response, uiSyncVersion.version)
|
|
@@ -102,127 +109,139 @@ function reinitialize(_, response) {
|
|
|
102
109
|
sendOK(response)
|
|
103
110
|
}
|
|
104
111
|
|
|
112
|
+
|
|
105
113
|
async function selectCookie(req, response) {
|
|
106
|
-
const
|
|
114
|
+
const label = await parseJSON(req)
|
|
115
|
+
|
|
116
|
+
const error = cookie.setCurrent(label)
|
|
107
117
|
if (error)
|
|
108
118
|
sendUnprocessableContent(response, error?.message || error)
|
|
109
119
|
else
|
|
110
120
|
sendJSON(response, cookie.list())
|
|
111
121
|
}
|
|
112
122
|
|
|
123
|
+
|
|
113
124
|
async function selectMock(req, response) {
|
|
114
125
|
const file = await parseJSON(req)
|
|
126
|
+
|
|
115
127
|
const broker = mockBrokersCollection.brokerByFilename(file)
|
|
116
128
|
if (!broker || !broker.hasMock(file))
|
|
117
129
|
sendUnprocessableContent(response, `Missing Mock: ${file}`)
|
|
118
130
|
else {
|
|
119
131
|
broker.selectFile(file)
|
|
120
|
-
sendJSON(response, broker
|
|
132
|
+
sendJSON(response, broker)
|
|
121
133
|
}
|
|
122
134
|
}
|
|
123
135
|
|
|
136
|
+
|
|
124
137
|
async function toggle500(req, response) {
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
body[DF.routeUrlMask])
|
|
138
|
+
const [method, urlMask] = await parseJSON(req)
|
|
139
|
+
|
|
140
|
+
const broker = mockBrokersCollection.brokerByRoute(method, urlMask)
|
|
129
141
|
if (!broker)
|
|
130
|
-
sendUnprocessableContent(response, `Route does not exist: ${
|
|
142
|
+
sendUnprocessableContent(response, `Route does not exist: ${method} ${urlMask}`)
|
|
131
143
|
else {
|
|
132
144
|
broker.toggle500()
|
|
133
|
-
sendJSON(response, broker
|
|
145
|
+
sendJSON(response, broker)
|
|
134
146
|
}
|
|
135
147
|
}
|
|
136
148
|
|
|
149
|
+
|
|
137
150
|
async function setRouteIsDelayed(req, response) {
|
|
138
|
-
const
|
|
139
|
-
const delayed = body[DF.delayed]
|
|
140
|
-
const broker = mockBrokersCollection.brokerByRoute(
|
|
141
|
-
body[DF.routeMethod],
|
|
142
|
-
body[DF.routeUrlMask])
|
|
151
|
+
const [method, urlMask, delayed] = await parseJSON(req)
|
|
143
152
|
|
|
153
|
+
const broker = mockBrokersCollection.brokerByRoute(method, urlMask)
|
|
144
154
|
if (!broker)
|
|
145
|
-
sendUnprocessableContent(response, `Route does not exist: ${
|
|
155
|
+
sendUnprocessableContent(response, `Route does not exist: ${method} ${urlMask}`)
|
|
146
156
|
else if (typeof delayed !== 'boolean')
|
|
147
157
|
sendUnprocessableContent(response, `Expected boolean for "delayed"`)
|
|
148
158
|
else {
|
|
149
159
|
broker.setDelayed(delayed)
|
|
150
|
-
|
|
160
|
+
sendJSON(response, broker)
|
|
151
161
|
}
|
|
152
162
|
}
|
|
153
163
|
|
|
164
|
+
|
|
154
165
|
async function setRouteIsProxied(req, response) {
|
|
155
|
-
const
|
|
156
|
-
const proxied = body[DF.proxied]
|
|
157
|
-
const broker = mockBrokersCollection.brokerByRoute(
|
|
158
|
-
body[DF.routeMethod],
|
|
159
|
-
body[DF.routeUrlMask])
|
|
166
|
+
const [method, urlMask, proxied] = await parseJSON(req)
|
|
160
167
|
|
|
168
|
+
const broker = mockBrokersCollection.brokerByRoute(method, urlMask)
|
|
161
169
|
if (!broker)
|
|
162
|
-
sendUnprocessableContent(response, `Route does not exist: ${
|
|
170
|
+
sendUnprocessableContent(response, `Route does not exist: ${method} ${urlMask}`)
|
|
163
171
|
else if (typeof proxied !== 'boolean')
|
|
164
172
|
sendUnprocessableContent(response, `Expected boolean for "proxied"`)
|
|
165
173
|
else if (proxied && !config.proxyFallback)
|
|
166
174
|
sendUnprocessableContent(response, `There’s no proxy fallback`)
|
|
167
175
|
else {
|
|
168
176
|
broker.setProxied(proxied)
|
|
169
|
-
|
|
177
|
+
sendJSON(response, broker)
|
|
170
178
|
}
|
|
171
179
|
}
|
|
172
180
|
|
|
181
|
+
|
|
173
182
|
async function updateProxyFallback(req, response) {
|
|
174
183
|
const fallback = await parseJSON(req)
|
|
175
|
-
|
|
184
|
+
|
|
185
|
+
if (!ConfigValidator.proxyFallback(fallback))
|
|
176
186
|
sendUnprocessableContent(response, `Invalid Proxy Fallback URL`)
|
|
177
|
-
|
|
187
|
+
else {
|
|
188
|
+
config.proxyFallback = fallback
|
|
189
|
+
sendOK(response)
|
|
178
190
|
}
|
|
179
|
-
config.proxyFallback = fallback
|
|
180
|
-
sendOK(response)
|
|
181
191
|
}
|
|
182
192
|
|
|
193
|
+
|
|
183
194
|
async function setCollectProxied(req, response) {
|
|
184
195
|
const collectProxied = await parseJSON(req)
|
|
185
|
-
|
|
196
|
+
|
|
197
|
+
if (!ConfigValidator.collectProxied(collectProxied))
|
|
186
198
|
sendUnprocessableContent(response, `Expected a boolean for "collectProxied"`)
|
|
187
|
-
|
|
199
|
+
else {
|
|
200
|
+
config.collectProxied = collectProxied
|
|
201
|
+
sendOK(response)
|
|
188
202
|
}
|
|
189
|
-
config.collectProxied = collectProxied
|
|
190
|
-
sendOK(response)
|
|
191
203
|
}
|
|
192
204
|
|
|
205
|
+
|
|
193
206
|
async function bulkUpdateBrokersByCommentTag(req, response) {
|
|
194
|
-
|
|
207
|
+
const comment = await parseJSON(req)
|
|
208
|
+
|
|
209
|
+
mockBrokersCollection.setMocksMatchingComment(comment)
|
|
195
210
|
sendOK(response)
|
|
196
211
|
}
|
|
197
212
|
|
|
213
|
+
|
|
198
214
|
async function setCorsAllowed(req, response) {
|
|
199
215
|
const corsAllowed = await parseJSON(req)
|
|
200
|
-
|
|
216
|
+
|
|
217
|
+
if (!ConfigValidator.corsAllowed(corsAllowed))
|
|
201
218
|
sendUnprocessableContent(response, `Expected boolean for "corsAllowed"`)
|
|
202
|
-
|
|
219
|
+
else {
|
|
220
|
+
config.corsAllowed = corsAllowed
|
|
221
|
+
sendOK(response)
|
|
203
222
|
}
|
|
204
|
-
config.corsAllowed = corsAllowed
|
|
205
|
-
sendOK(response)
|
|
206
223
|
}
|
|
207
224
|
|
|
225
|
+
|
|
208
226
|
async function setGlobalDelay(req, response) {
|
|
209
227
|
const delay = await parseJSON(req)
|
|
210
|
-
|
|
228
|
+
|
|
229
|
+
if (!ConfigValidator.delay(delay))
|
|
211
230
|
sendUnprocessableContent(response, `Expected non-negative integer for "delay"`)
|
|
212
|
-
|
|
231
|
+
else {
|
|
232
|
+
config.delay = delay
|
|
233
|
+
sendOK(response)
|
|
213
234
|
}
|
|
214
|
-
config.delay = delay
|
|
215
|
-
sendOK(response)
|
|
216
235
|
}
|
|
217
236
|
|
|
218
237
|
|
|
238
|
+
|
|
219
239
|
async function setStaticRouteStatusCode(req, response) {
|
|
220
|
-
const
|
|
221
|
-
const status = Number(body[DF.statusCode])
|
|
222
|
-
const broker = staticCollection.brokerByRoute(body[DF.routeUrlMask])
|
|
240
|
+
const [urlMask, status] = await parseJSON(req)
|
|
223
241
|
|
|
242
|
+
const broker = staticCollection.brokerByRoute(urlMask)
|
|
224
243
|
if (!broker)
|
|
225
|
-
sendUnprocessableContent(response, `Static route does not exist: ${
|
|
244
|
+
sendUnprocessableContent(response, `Static route does not exist: ${urlMask}`)
|
|
226
245
|
else if (!(status === 200 || status === 404))
|
|
227
246
|
sendUnprocessableContent(response, `Expected 200 or 404 status code`)
|
|
228
247
|
else {
|
|
@@ -233,12 +252,11 @@ async function setStaticRouteStatusCode(req, response) {
|
|
|
233
252
|
|
|
234
253
|
|
|
235
254
|
async function setStaticRouteIsDelayed(req, response) {
|
|
236
|
-
const
|
|
237
|
-
const delayed = body[DF.delayed]
|
|
238
|
-
const broker = staticCollection.brokerByRoute(body[DF.routeUrlMask])
|
|
255
|
+
const [urlMask, delayed] = await parseJSON(req)
|
|
239
256
|
|
|
257
|
+
const broker = staticCollection.brokerByRoute(urlMask)
|
|
240
258
|
if (!broker)
|
|
241
|
-
sendUnprocessableContent(response, `Static route does not exist: ${
|
|
259
|
+
sendUnprocessableContent(response, `Static route does not exist: ${urlMask}`)
|
|
242
260
|
else if (typeof delayed !== 'boolean')
|
|
243
261
|
sendUnprocessableContent(response, `Expected boolean for "delayed"`)
|
|
244
262
|
else {
|
package/src/ApiCommander.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { API,
|
|
1
|
+
import { API, LONG_POLL_SERVER_TIMEOUT, HEADER_FOR_SYNC_VERSION } from './ApiConstants.js'
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
/** Client for controlling Mockaton via its HTTP API */
|
|
@@ -9,27 +9,27 @@ export class Commander {
|
|
|
9
9
|
this.#addr = addr
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
#patch = (api, body) =>
|
|
13
|
-
|
|
12
|
+
#patch = (api, body) =>
|
|
13
|
+
fetch(this.#addr + api, {
|
|
14
14
|
method: 'PATCH',
|
|
15
15
|
body: JSON.stringify(body)
|
|
16
16
|
})
|
|
17
|
-
}
|
|
18
17
|
|
|
19
18
|
/** @returns {JsonPromise<State>} */
|
|
20
|
-
getState = () =>
|
|
21
|
-
|
|
22
|
-
}
|
|
19
|
+
getState = () =>
|
|
20
|
+
fetch(this.#addr + API.state)
|
|
23
21
|
|
|
24
22
|
/** @returns {JsonPromise<number>} */
|
|
25
|
-
getSyncVersion = (
|
|
26
|
-
|
|
27
|
-
signal: AbortSignal.any([
|
|
23
|
+
getSyncVersion = (currSyncVer, abortSignal) =>
|
|
24
|
+
fetch(this.#addr + API.syncVersion, {
|
|
25
|
+
signal: AbortSignal.any([
|
|
26
|
+
abortSignal,
|
|
27
|
+
AbortSignal.timeout(LONG_POLL_SERVER_TIMEOUT + 1000)
|
|
28
|
+
]),
|
|
28
29
|
headers: {
|
|
29
|
-
[
|
|
30
|
+
[HEADER_FOR_SYNC_VERSION]: currSyncVer
|
|
30
31
|
}
|
|
31
32
|
})
|
|
32
|
-
}
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
reset() {
|
|
@@ -40,45 +40,28 @@ export class Commander {
|
|
|
40
40
|
return this.#patch(API.select, file)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
toggle500(
|
|
44
|
-
return this.#patch(API.toggle500,
|
|
45
|
-
[DF.routeMethod]: routeMethod,
|
|
46
|
-
[DF.routeUrlMask]: routeUrlMask
|
|
47
|
-
})
|
|
43
|
+
toggle500(method, urlMask) {
|
|
44
|
+
return this.#patch(API.toggle500, [method, urlMask])
|
|
48
45
|
}
|
|
49
46
|
|
|
50
47
|
bulkSelectByComment(comment) {
|
|
51
48
|
return this.#patch(API.bulkSelect, comment)
|
|
52
49
|
}
|
|
53
50
|
|
|
54
|
-
setRouteIsDelayed(
|
|
55
|
-
return this.#patch(API.delay,
|
|
56
|
-
[DF.routeMethod]: routeMethod,
|
|
57
|
-
[DF.routeUrlMask]: routeUrlMask,
|
|
58
|
-
[DF.delayed]: delayed
|
|
59
|
-
})
|
|
51
|
+
setRouteIsDelayed(method, urlMask, delayed) {
|
|
52
|
+
return this.#patch(API.delay, [method, urlMask, delayed])
|
|
60
53
|
}
|
|
61
54
|
|
|
62
|
-
setStaticRouteIsDelayed(
|
|
63
|
-
return this.#patch(API.delayStatic,
|
|
64
|
-
[DF.routeUrlMask]: routeUrlMask,
|
|
65
|
-
[DF.delayed]: delayed
|
|
66
|
-
})
|
|
55
|
+
setStaticRouteIsDelayed(urlMask, delayed) {
|
|
56
|
+
return this.#patch(API.delayStatic, [urlMask, delayed])
|
|
67
57
|
}
|
|
68
58
|
|
|
69
|
-
setStaticRouteStatus(
|
|
70
|
-
return this.#patch(API.staticStatus,
|
|
71
|
-
[DF.routeUrlMask]: routeUrlMask,
|
|
72
|
-
[DF.statusCode]: status
|
|
73
|
-
})
|
|
59
|
+
setStaticRouteStatus(urlMask, status) {
|
|
60
|
+
return this.#patch(API.staticStatus, [urlMask, status])
|
|
74
61
|
}
|
|
75
62
|
|
|
76
|
-
setRouteIsProxied(
|
|
77
|
-
return this.#patch(API.proxied,
|
|
78
|
-
[DF.routeMethod]: routeMethod,
|
|
79
|
-
[DF.routeUrlMask]: routeUrlMask,
|
|
80
|
-
[DF.proxied]: proxied
|
|
81
|
-
})
|
|
63
|
+
setRouteIsProxied(method, urlMask, proxied) {
|
|
64
|
+
return this.#patch(API.proxied, [method, urlMask, proxied])
|
|
82
65
|
}
|
|
83
66
|
|
|
84
67
|
selectCookie(cookieKey) {
|
package/src/ApiConstants.js
CHANGED
|
@@ -19,21 +19,9 @@ export const API = {
|
|
|
19
19
|
toggle500: MOUNT + '/toggle500'
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export const
|
|
23
|
-
|
|
24
|
-
routeUrlMask: 'route_url_mask',
|
|
25
|
-
delayed: 'delayed',
|
|
26
|
-
proxied: 'proxied',
|
|
27
|
-
statusCode: 'status_code',
|
|
28
|
-
syncVersion: 'last_received_sync_version'
|
|
29
|
-
}
|
|
22
|
+
export const HEADER_FOR_502 = 'Mockaton502'
|
|
23
|
+
export const HEADER_FOR_SYNC_VERSION = 'sync_version'
|
|
30
24
|
|
|
31
|
-
// TODO @ThinkAbout these affecting partial matches when bulk-selecting
|
|
32
|
-
// e.g. 'ton' would match
|
|
33
|
-
export const AUTO_500_COMMENT = '(Mockaton 500)'
|
|
34
25
|
export const DEFAULT_MOCK_COMMENT = '(default)'
|
|
35
|
-
|
|
36
26
|
export const EXT_FOR_UNKNOWN_MIME = 'unknown'
|
|
37
27
|
export const LONG_POLL_SERVER_TIMEOUT = 8_000
|
|
38
|
-
|
|
39
|
-
export const HEADER_FOR_502 = 'Mockaton502'
|
package/src/Dashboard.css
CHANGED
|
@@ -369,6 +369,19 @@ table {
|
|
|
369
369
|
> tr:first-child > th {
|
|
370
370
|
border-top: 0;
|
|
371
371
|
}
|
|
372
|
+
|
|
373
|
+
tr.animIn {
|
|
374
|
+
opacity: 0;
|
|
375
|
+
transform: scaleY(0);
|
|
376
|
+
animation: _kfAnimIn 180ms ease-in-out forwards;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
@keyframes _kfAnimIn {
|
|
381
|
+
to {
|
|
382
|
+
opacity: 1;
|
|
383
|
+
transform: scaleY(1);
|
|
384
|
+
}
|
|
372
385
|
}
|
|
373
386
|
|
|
374
387
|
.Method {
|
|
@@ -544,11 +557,22 @@ table {
|
|
|
544
557
|
}
|
|
545
558
|
}
|
|
546
559
|
|
|
560
|
+
&:disabled + span {
|
|
561
|
+
cursor: not-allowed;
|
|
562
|
+
opacity: 0.7;
|
|
563
|
+
}
|
|
547
564
|
&:checked + span {
|
|
548
565
|
border-color: var(--colorRed);
|
|
549
566
|
color: white;
|
|
550
567
|
background: var(--colorRed);
|
|
551
568
|
}
|
|
569
|
+
&:not(:checked):enabled:hover + span {
|
|
570
|
+
border-color: var(--colorRed);
|
|
571
|
+
color: var(--colorRed);
|
|
572
|
+
}
|
|
573
|
+
&:enabled:active + span {
|
|
574
|
+
cursor: grabbing;
|
|
575
|
+
}
|
|
552
576
|
}
|
|
553
577
|
|
|
554
578
|
> span {
|
|
@@ -558,14 +582,6 @@ table {
|
|
|
558
582
|
font-weight: bold;
|
|
559
583
|
color: var(--colorSecondaryAction);
|
|
560
584
|
border-radius: var(--radius);
|
|
561
|
-
|
|
562
|
-
&:hover {
|
|
563
|
-
border-color: var(--colorRed);
|
|
564
|
-
color: var(--colorRed);
|
|
565
|
-
}
|
|
566
|
-
&:active {
|
|
567
|
-
cursor: grabbing;
|
|
568
|
-
}
|
|
569
585
|
}
|
|
570
586
|
}
|
|
571
587
|
|