mockaton 8.19.0 → 8.20.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/README.md +21 -25
- package/package.json +1 -6
- package/src/Dashboard.css +21 -22
- package/src/Dashboard.js +22 -17
- package/dev-config.js +0 -18
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ For example, for [/api/user/123](#), the mock filename could be:
|
|
|
26
26
|
On the dashboard you can select a mock variant for a particular route, delaying responses,
|
|
27
27
|
or triggering an autogenerated `500` error, among other features.
|
|
28
28
|
Nonetheless, there’s a programmatic API, which is handy
|
|
29
|
-
for setting up tests (see **Commander API** section).
|
|
29
|
+
for setting up tests (see **Commander API** section below).
|
|
30
30
|
|
|
31
31
|
<picture>
|
|
32
32
|
<source media="(prefers-color-scheme: light)" srcset="pixaton-tests/macos/pic-for-readme.vp962x800.light.gold.png">
|
|
@@ -65,17 +65,18 @@ api/videos.GET.<b>500</b>.txt # Internal Server Error
|
|
|
65
65
|
## Scraping mocks from your Backend
|
|
66
66
|
|
|
67
67
|
### Option 1: Browser Extension
|
|
68
|
-
This [browser extension](https://github.com/ericfortis/download-http-requests-browser-ext)
|
|
69
|
-
lets you download all the HTTP responses
|
|
68
|
+
This [browser extension](https://github.com/ericfortis/download-http-requests-browser-ext)
|
|
69
|
+
lets you download all the HTTP responses, and they
|
|
70
|
+
get saved following Mockaton’s filename convention.
|
|
70
71
|
|
|
71
72
|
### Option 2: Fallback to Your Backend
|
|
72
73
|
This option could be a bit elaborate if your backend uses third-party auth,
|
|
73
|
-
because you’d have to inject
|
|
74
|
+
because you’d have to manually inject cookies or `sessionStorage` tokens.
|
|
74
75
|
|
|
75
|
-
On the other hand,
|
|
76
|
-
|
|
76
|
+
On the other hand, proxying to your backend is straightforward if your backend
|
|
77
|
+
handles the session cookie, or if you can develop without auth.
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
Either way you can forward requests to your backend for routes you don’t have
|
|
79
80
|
mocks for, or routes that have the ☁️ **Cloud Checkbox** checked. In addition, by
|
|
80
81
|
checking ✅ **Save Mocks**, you can collect the responses that hit your backend.
|
|
81
82
|
They will be saved in your `config.mocksDir` following the filename convention.
|
|
@@ -115,11 +116,7 @@ node --import=tsx my-mockaton.js
|
|
|
115
116
|
|
|
116
117
|
<br/>
|
|
117
118
|
|
|
118
|
-
## Demo App (Vite)
|
|
119
|
-
|
|
120
|
-
This is a minimal React + Vite + Mockaton app. It’s a list of
|
|
121
|
-
colors containing all of their possible states. For example,
|
|
122
|
-
permutations for out-of-stock, new-arrival, and discontinued.
|
|
119
|
+
## Demo App (Vite + React)
|
|
123
120
|
|
|
124
121
|
```sh
|
|
125
122
|
git clone https://github.com/ericfortis/mockaton.git
|
|
@@ -128,37 +125,36 @@ npm install
|
|
|
128
125
|
|
|
129
126
|
npm run mockaton
|
|
130
127
|
npm run start # in another terminal
|
|
131
|
-
|
|
132
|
-
# BTW, that directory has scripts for running both
|
|
133
|
-
# servers with one command in two terminals.
|
|
134
128
|
```
|
|
135
129
|
|
|
136
|
-
|
|
137
|
-
|
|
130
|
+
The demo app has a list of colors containing all of their possible states. For example,
|
|
131
|
+
permutations for out-of-stock, new-arrival, and discontinued. It looks like this:
|
|
138
132
|
|
|
139
133
|
<img src="./demo-app-vite/pixaton-tests/pic-for-readme.vp740x880.light.gold.png" alt="Mockaton Demo App Screenshot" width="740" />
|
|
140
134
|
|
|
141
135
|
<br/>
|
|
142
136
|
|
|
143
137
|
## Use Cases
|
|
144
|
-
### Testing
|
|
138
|
+
### Testing Backend or Frontend
|
|
145
139
|
- Empty responses
|
|
146
|
-
- Spinners by delaying responses
|
|
147
140
|
- Errors such as _Bad Request_ and _Internal Server Error_
|
|
148
|
-
- Setting up UI tests
|
|
149
141
|
- Mocking third-party APIs
|
|
150
142
|
- Polled resources (for triggering their different states)
|
|
151
143
|
- alerts
|
|
152
144
|
- notifications
|
|
153
145
|
- slow to build resources
|
|
154
146
|
|
|
147
|
+
### Testing Frontend
|
|
148
|
+
- Spinners by delaying responses
|
|
149
|
+
- Setting up UI tests
|
|
150
|
+
|
|
155
151
|
### Time travel
|
|
156
152
|
If you commit the mocks to your repo, it’s straightforward to
|
|
157
153
|
bisect bugs and check out long-lived branches, so you don’t
|
|
158
154
|
have to downgrade backends to old API contracts or databases.
|
|
159
155
|
|
|
160
156
|
### Simulating complex backend states
|
|
161
|
-
Sometimes, the ideal flow you need is too difficult to reproduce from
|
|
157
|
+
Sometimes, the ideal flow you need is too difficult to reproduce from the actual backend.
|
|
162
158
|
For this, you can **Bulk Select** mocks by comments to simulate the complete states
|
|
163
159
|
you want. For example, by adding `(demo-part1)`, `(demo-part2)` to the filenames.
|
|
164
160
|
|
|
@@ -197,8 +193,8 @@ export default (request, response) =>
|
|
|
197
193
|
JSON.stringify({ foo: 'bar' })
|
|
198
194
|
```
|
|
199
195
|
|
|
200
|
-
Think of these functions as HTTP handlers
|
|
201
|
-
intercept requests
|
|
196
|
+
Think of these functions as HTTP handlers. For example,
|
|
197
|
+
you can intercept requests to write to a database.
|
|
202
198
|
|
|
203
199
|
<details>
|
|
204
200
|
<summary><b>See Intercepting Requests Examples</b></summary>
|
|
@@ -325,7 +321,7 @@ documenting the URL contract.
|
|
|
325
321
|
api/video<b>?limit=[limit]</b>.GET.200.json
|
|
326
322
|
</pre>
|
|
327
323
|
|
|
328
|
-
On Windows filenames containing "?" are [not
|
|
324
|
+
On Windows, filenames containing "?" are [not
|
|
329
325
|
permitted](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file), but since that’s part of the query string it’s ignored anyway.
|
|
330
326
|
|
|
331
327
|
<br/>
|
|
@@ -352,7 +348,7 @@ api/foo/bar.GET.200.json
|
|
|
352
348
|
This is the only required field. The directory must exist.
|
|
353
349
|
|
|
354
350
|
### `staticDir?: string`
|
|
355
|
-
|
|
351
|
+
This option is not needed besides serving partial content (e.g., videos). But
|
|
356
352
|
it’s convenient for serving 200 GET requests without having to add the filename
|
|
357
353
|
extension convention. For example, for using Mockaton as a standalone demo server,
|
|
358
354
|
as explained above in the _Use Cases_ section.
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "mockaton",
|
|
3
3
|
"description": "HTTP Mock Server",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "8.
|
|
5
|
+
"version": "8.20.0",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"types": "index.d.ts",
|
|
8
8
|
"license": "MIT",
|
|
@@ -25,11 +25,6 @@
|
|
|
25
25
|
"optionalDependencies": {
|
|
26
26
|
"open": "^10.0.0"
|
|
27
27
|
},
|
|
28
|
-
"dependencies": {
|
|
29
|
-
"@vitejs/plugin-react": "5.0.1",
|
|
30
|
-
"mockaton": "8.18.0",
|
|
31
|
-
"vite": "7.1.3"
|
|
32
|
-
},
|
|
33
28
|
"devDependencies": {
|
|
34
29
|
"pixaton": "1.1.2",
|
|
35
30
|
"puppeteer": "24.17.0"
|
package/src/Dashboard.css
CHANGED
|
@@ -274,8 +274,7 @@ main {
|
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
.rightSide {
|
|
277
|
-
padding
|
|
278
|
-
padding-left: 16px;
|
|
277
|
+
padding: 16px;
|
|
279
278
|
overflow-y: auto;
|
|
280
279
|
}
|
|
281
280
|
}
|
|
@@ -518,28 +517,28 @@ table {
|
|
|
518
517
|
}
|
|
519
518
|
}
|
|
520
519
|
|
|
521
|
-
.
|
|
522
|
-
|
|
523
|
-
width:
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
animation:
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
animation-duration:
|
|
520
|
+
.ProgressBar {
|
|
521
|
+
position: relative;
|
|
522
|
+
width: 100%;
|
|
523
|
+
height: 2px;
|
|
524
|
+
background: var(--colorComboBoxHeaderBackground);
|
|
525
|
+
|
|
526
|
+
div {
|
|
527
|
+
position: absolute;
|
|
528
|
+
top: 0;
|
|
529
|
+
left: 0;
|
|
530
|
+
width: 0;
|
|
531
|
+
height: 100%;
|
|
532
|
+
background: var(--colorAccent);
|
|
533
|
+
animation-name: _kfProgress;
|
|
534
|
+
animation-timing-function: linear;
|
|
535
|
+
animation-delay: 80ms;
|
|
536
|
+
/*animation-duration: It's in JavaScript */
|
|
538
537
|
}
|
|
539
538
|
}
|
|
540
|
-
@keyframes
|
|
541
|
-
|
|
542
|
-
|
|
539
|
+
@keyframes _kfProgress {
|
|
540
|
+
to {
|
|
541
|
+
width: 100%;
|
|
543
542
|
}
|
|
544
543
|
}
|
|
545
544
|
|
package/src/Dashboard.js
CHANGED
|
@@ -53,12 +53,10 @@ const CSS = {
|
|
|
53
53
|
NotFoundToggler: 'NotFoundToggler',
|
|
54
54
|
PayloadViewer: 'PayloadViewer',
|
|
55
55
|
PreviewLink: 'PreviewLink',
|
|
56
|
+
ProgressBar: 'ProgressBar',
|
|
56
57
|
ProxyToggler: 'ProxyToggler',
|
|
57
58
|
ResetButton: 'ResetButton',
|
|
58
59
|
SaveProxiedCheckbox: 'SaveProxiedCheckbox',
|
|
59
|
-
SpinnerClock: 'SpinnerClock',
|
|
60
|
-
SpinnerClockHourHand: 'HourHand',
|
|
61
|
-
SpinnerClockMinuteHand: 'MinuteHand',
|
|
62
60
|
StaticFilesList: 'StaticFilesList',
|
|
63
61
|
|
|
64
62
|
chosen: 'chosen',
|
|
@@ -296,9 +294,9 @@ function PreviewLink({ method, urlMask, urlMaskDittoed }) {
|
|
|
296
294
|
async function onClick(event) {
|
|
297
295
|
event.preventDefault()
|
|
298
296
|
try {
|
|
299
|
-
await previewMock(method, urlMask, this.href)
|
|
300
297
|
document.querySelector(`.${CSS.PreviewLink}.${CSS.chosen}`)?.classList.remove(CSS.chosen)
|
|
301
298
|
this.classList.add(CSS.chosen)
|
|
299
|
+
await previewMock(method, urlMask, this.href)
|
|
302
300
|
}
|
|
303
301
|
catch (error) {
|
|
304
302
|
onError(error)
|
|
@@ -397,7 +395,7 @@ function InternalServerErrorToggler({ broker }) {
|
|
|
397
395
|
r('span', null, '500')))
|
|
398
396
|
}
|
|
399
397
|
|
|
400
|
-
/** @param {{ broker: MockBroker
|
|
398
|
+
/** @param {{ broker: MockBroker }} props */
|
|
401
399
|
function ProxyToggler({ broker }) {
|
|
402
400
|
function onChange() {
|
|
403
401
|
const { urlMask, method } = parseFilename(broker.mocks[0])
|
|
@@ -515,13 +513,11 @@ function PayloadViewer() {
|
|
|
515
513
|
r('code', { ref: payloadViewerRef }, Strings.click_link_to_preview))))
|
|
516
514
|
}
|
|
517
515
|
|
|
518
|
-
|
|
516
|
+
|
|
517
|
+
function PayloadViewerProgressBar() {
|
|
519
518
|
return (
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
s('line', { class: CSS.SpinnerClockHourHand, x1: 12, y1: 12, x2: 12, y2: 8 }),
|
|
523
|
-
s('line', { class: CSS.SpinnerClockMinuteHand, x1: 12, y1: 12, x2: 12, y2: 5 })
|
|
524
|
-
))
|
|
519
|
+
r('div', { className: CSS.ProgressBar },
|
|
520
|
+
r('div', { style: { animationDuration: globalDelay + 'ms' } })))
|
|
525
521
|
}
|
|
526
522
|
|
|
527
523
|
function PayloadViewerTitle({ file, status, statusText }) {
|
|
@@ -543,14 +539,23 @@ function PayloadViewerTitleWhenProxied({ mime, status, statusText, gatewayIsBad
|
|
|
543
539
|
}
|
|
544
540
|
|
|
545
541
|
async function previewMock(method, urlMask, href) {
|
|
546
|
-
|
|
542
|
+
previewMock.controller?.abort()
|
|
543
|
+
previewMock.controller = new AbortController
|
|
544
|
+
|
|
545
|
+
renderProgressBar()
|
|
547
546
|
payloadViewerTitleRef.current.replaceChildren(r('span', null, Strings.fetching))
|
|
548
|
-
const response = await fetch(href, { method })
|
|
549
|
-
clearTimeout(timer)
|
|
550
|
-
await updatePayloadViewer(method, urlMask, response)
|
|
551
547
|
|
|
552
|
-
|
|
553
|
-
|
|
548
|
+
try {
|
|
549
|
+
const response = await fetch(href, {
|
|
550
|
+
method,
|
|
551
|
+
signal: previewMock.controller.signal
|
|
552
|
+
})
|
|
553
|
+
await updatePayloadViewer(method, urlMask, response)
|
|
554
|
+
}
|
|
555
|
+
catch {}
|
|
556
|
+
|
|
557
|
+
function renderProgressBar() {
|
|
558
|
+
payloadViewerRef.current.replaceChildren(PayloadViewerProgressBar())
|
|
554
559
|
}
|
|
555
560
|
}
|
|
556
561
|
|
package/dev-config.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { join } from 'node:path'
|
|
2
|
-
import { jwtCookie } from './index.js'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export const devConfig = {
|
|
6
|
-
port: 2345,
|
|
7
|
-
mocksDir: join(import.meta.dirname, 'fixtures-mocks'),
|
|
8
|
-
staticDir: join(import.meta.dirname, 'fixtures-static-mocks'),
|
|
9
|
-
cookies: {
|
|
10
|
-
'My Admin User': 'my-cookie=1;Path=/;SameSite=strict',
|
|
11
|
-
'My Normal User': 'my-cookie=0;Path=/;SameSite=strict',
|
|
12
|
-
'My JWT': jwtCookie('my-cookie', {
|
|
13
|
-
email: 'john.doe@example.com',
|
|
14
|
-
picture: 'https://cdn.auth0.com/avatars/jd.png'
|
|
15
|
-
}),
|
|
16
|
-
'None': ''
|
|
17
|
-
}
|
|
18
|
-
}
|