mockaton 11.1.2 → 11.1.3

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 CHANGED
@@ -1,3 +1,16 @@
1
+ docker: docker-build docker-start
2
+
3
+ docker-build:
4
+ docker build -t mockaton .
5
+
6
+ docker-start: docker-stop
7
+ docker run --name mockaton -p 127.0.0.1:2020:2020 mockaton
8
+
9
+ docker-stop:
10
+ @docker stop mockaton >/dev/null 2>&1 || true
11
+ @docker rm mockaton >/dev/null 2>&1 || true
12
+
13
+
1
14
  start:
2
15
  @node src/cli.js
3
16
 
package/README.md CHANGED
@@ -6,9 +6,8 @@
6
6
  [![CodeQL](https://github.com/ericfortis/mockaton/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/ericfortis/mockaton/actions/workflows/github-code-scanning/codeql)
7
7
  [![codecov](https://codecov.io/github/ericfortis/mockaton/graph/badge.svg?token=90NYLMMG1J)](https://codecov.io/github/ericfortis/mockaton)
8
8
 
9
-
10
9
  An HTTP mock server for simulating APIs with minimal setup
11
- — ideal for testing difficult to reproduce states.
10
+ — ideal for testing difficult to reproduce backend states.
12
11
 
13
12
  ## Overview
14
13
  With Mockaton, you don’t need to write code for wiring up your
@@ -21,16 +20,13 @@ For example, for [/api/user/123](#), the filename could be:
21
20
  <code>my-mocks-dir/<b>api/user</b>/[user-id].GET.200.json</code>
22
21
  </pre>
23
22
 
24
- <br/>
25
23
 
26
24
  ## Dashboard
27
25
 
28
- On the dashboard you can select a mock variant for a particular route, delaying responses,
29
- or triggering an autogenerated `500` error, among other features.
30
-
31
-
32
- Nonetheless, there’s a programmatic API, which is handy
33
- for setting up tests (see **Commander&nbsp;API** section below).
26
+ On the dashboard you can select a mock variant for a particular route,
27
+ 🕓 delaying responses, or triggering an autogenerated `500` error, among
28
+ other features. Nonetheless, there’s a programmatic API, which is
29
+ handy for setting up tests (see **Commander&nbsp;API** section below).
34
30
 
35
31
  <picture>
36
32
  <source media="(prefers-color-scheme: light)" srcset="pixaton-tests/macos/pic-for-readme.vp761x720.light.gold.png">
@@ -54,6 +50,12 @@ api/login<b>(locked out user)</b>.POST.423.json
54
50
  api/login<b>(invalid login attempt)</b>.POST.401.json
55
51
  </pre>
56
52
 
53
+ You can **Bulk Select** mocks by comments to simulate the complete states
54
+ you want. For example:
55
+
56
+ <img src="docs/bulk-select.png" width="180px">
57
+
58
+
57
59
  ### Different response status code
58
60
  For instance, you can use a `4xx` or `5xx` status code for triggering error
59
61
  responses, or a `2xx` such as `204` for testing empty collections.
@@ -69,13 +71,13 @@ api/videos.GET.<b>500</b>.txt # Internal Server Error
69
71
 
70
72
  ## Scraping Mocks from your Backend
71
73
 
72
- ### Option 1: Browser Extension
74
+ ### Option 1: Browser extension
73
75
  The companion Chrome [devtools
74
76
  extension](https://github.com/ericfortis/download-http-requests-browser-ext)
75
77
  lets you download all the HTTP responses, and they
76
78
  get saved following Mockaton’s filename convention.
77
79
 
78
- ### Option 2: Fallback to Your Backend
80
+ ### Option 2: Fallback to your backend
79
81
  <details>
80
82
  <summary>Learn more…</summary>
81
83
 
@@ -97,138 +99,111 @@ They will be saved in your `config.mocksDir` following the filename convention.
97
99
 
98
100
 
99
101
  ## Motivation
100
- <details>
101
- <summary>Motivation…</summary>
102
-
103
- **No API state should be too hard to test.**
104
- With Mockaton, developers can achieve correctness and speed.
105
-
106
- ### Correctness
107
- - Enables testing of complex scenarios that would otherwise be skipped. e.g.,
108
- - Triggering errors on third-party APIs.
109
- - Triggering errors on your project’s backend (if you are a frontend developer).
110
- - Allows for deterministic, comprehensive, and consistent state.
111
- - Spot inadvertent regressions during development.
112
- - Use it to set up screenshot tests, e.g., with [pixaton](https://github.com/ericfortis/pixaton).
113
-
114
- ### Speed
115
- - Works around unstable dev backends while developing UIs.
116
- - Spinning up development infrastructure.
117
- - Syncing database states.
118
- - Prevents progress from being blocked by waiting for APIs.
119
- - Time travel. If you commit the mocks to your repo,
120
- you don’t have to downgrade backends for:
121
- - checking out long-lived branches
122
- - bisecting bugs
123
102
 
124
- </details>
103
+ ### Testing scenarios that would otherwise be skipped
104
+ - Simulate errors on third-party APIs, or on your project’s backend (if you are a frontend dev, or unfamiliar with that code)
105
+ - Trigger dynamic states on an API. You can do this by using comments on mock filenames, for example, for polled alerts or notifications.
106
+ - Trigger empty (no content) responses
107
+ - Sometimes, the ideal flow you need is just too difficult to reproduce from the actual backend
108
+
109
+ ### Works around unstable dev backends while developing UIs
110
+ - Spinning up dev infrastructure
111
+ - Syncing the database
112
+ - Mitigates progress from being blocked by waiting for APIs
113
+
114
+ ### Time travel
115
+ If you commit the mocks to your repo, you don’t have to downgrade backends when:
116
+ - Checking out long-lived branches
117
+ - Bisecting bugs
118
+
119
+ ### Deterministic and comprehensive states
120
+ - Ideal for setting up screenshot tests, e.g., with [pixaton](https://github.com/ericfortis/pixaton)
121
+ - Spot inadvertent regressions during development. For example, the demo app in
122
+ this repo has a list of colors containing all of their possible states, such as
123
+ permutations for out-of-stock, new-arrival, and discontinued. This way you’ll
124
+ indirectly notice if something else broke.
125
125
 
126
+ <img src="./demo-app-vite/pixaton-tests/pic-for-readme.vp740x880.light.gold.png" alt="Mockaton Demo App Screenshot" width="740" />
126
127
 
128
+ <br/>
127
129
 
128
- ## Use Cases
129
- <details>
130
- <summary>Use Cases…</summary>
131
-
132
- ### Testing Backend or Frontend
133
- - Empty responses
134
- - Errors such as _Bad Request_ and _Internal Server Error_
135
- - Mocking third-party APIs
136
- - Polled resources (for triggering their different states)
137
- - alerts
138
- - notifications
139
- - slow to build resources
140
-
141
- ### Testing Frontend
142
- - Spinners by delaying responses
143
- - Setting up UI tests
144
-
145
- ### Demoing complex backend states
146
- Sometimes, the ideal flow you need is too difficult to reproduce from the actual backend.
147
- For this, you can **Bulk Select** mocks by comments to simulate the complete states
148
- you want. For example, by adding `(demo-part1)`, `(demo-part2)` to the filenames.
149
-
150
- Similarly, you can deploy a **Standalone Demo Server** by compiling the frontend app and
151
- putting its built assets in `config.staticDir`. And simulate the flow by Bulk Selecting mocks.
152
- The [aot-fetch-demo repo](https://github.com/ericfortis/aot-fetch-demo) has a working example.
130
+ ### Standalone demo server (Docker)
131
+ You can demo your app by compiling the frontend and putting
132
+ its built assets in `config.staticDir`. For example, this
133
+ repo includes a demo which builds and runs a docker container.
153
134
 
154
- </details>
135
+ ```sh
136
+ git clone https://github.com/ericfortis/mockaton.git --depth 1
137
+ cd mockaton/demo-app-vite
138
+ make start-standalone-demo
139
+ ```
140
+ - App: http://localhost:4040
141
+ - Dashboard: http://localhost:4040/mockaton
142
+
143
+
144
+ ### Privacy and security
145
+ - Does not write to disk. Except when you select ✅ **Save Mocks** for scraping mocks from a backend
146
+ - Does not initiate network connections (no logs, no telemetry)
147
+ - Does not hijack your HTTP client
148
+ - Auditable, organized, and small. 4 KLoC (half is UI and tests)
149
+ - Zero dependencies. No runtime and no build packages.
155
150
 
156
151
  <br/>
157
152
 
153
+ ## Quick Start (Docker)
154
+ This will spin up Mockaton with the mocks included in this repo:
155
+ [mockaton-mocks/](./mockaton-mocks) and [mockaton-static-mocks/](./mockaton-static-mocks)
156
+
157
+ ```sh
158
+ git clone https://github.com/ericfortis/mockaton.git --depth 1
159
+ make docker
160
+ ```
161
+ Dashboard: http://localhost:2020/mockaton
162
+
158
163
 
164
+ Test it:
165
+ ```shell
166
+ curl localhost:2020/api/user
167
+ ```
159
168
 
160
- <br/>
161
169
 
162
- ## Basic Usage
170
+ ## Usage Without Docker
163
171
 
164
- 1. Install Node.js (v22.18+ support writing mocks in TypeScript)
172
+ Requires Node.js. **v22.18+** support writing mocks in TypeScript.
165
173
 
166
- 2. Create a sample mock in the default mocks directory (`./mockaton-mocks`)
174
+ 1. Create a mock in the default mocks directory (`./mockaton-mocks`)
167
175
  ```sh
168
176
  mkdir -p mockaton-mocks/api
169
177
  echo "[1,2,3]" > mockaton-mocks/api/foo.GET.200.json
170
178
  ```
171
- 3. Run Mockaton (`npx` comes with Node, and installs Mockaton if needed)
179
+ 2. Run Mockaton (`npx` comes with Node, and installs Mockaton if needed)
172
180
  ```shell
173
- npx mockaton --port 2345
181
+ npx mockaton --port 4040
174
182
  ```
175
183
 
176
- 4. Test it
184
+ 3. Test it
177
185
  ```shell
178
- curl localhost:2345/api/foo
186
+ curl localhost:4040/api/foo
179
187
  ```
180
188
 
181
- 5. Optionally, use a `mockaton.config.js`
182
- ```js
183
- import { defineConfig } from 'mockaton'
184
-
185
- export default defineConfig({
186
- port: 2345,
187
- })
188
- ```
189
189
 
190
-
191
- ### Alternative Installations
192
- <details>
193
- <summary>With NPM (package.json)…</summary>
194
-
195
- ```shell
190
+ ## Or, on Node Projects
191
+ ```sh
196
192
  npm install mockaton --save-dev
197
193
  ```
198
194
 
199
- Then, add the script to your `package.json`:
195
+ In your `package.json`:
200
196
  ```json
201
- {
202
- "scripts": {
203
- "mockaton": "mockaton --port 2345"
204
- }
197
+ "scripts": {
198
+ "mockaton": "mockaton --port 4040"
205
199
  }
206
200
  ```
207
- </details>
208
-
209
-
210
- <details>
211
- <summary>Without NPM…</summary>
212
-
213
- Since Mockaton has no dependencies, you can create an executable
214
- by linking to `src/cli.js`.
215
-
216
- ```shell
217
- git clone https://github.com/ericfortis/mockaton.git --depth 1
218
- ln -s `realpath mockaton/src/cli.js` ~/bin/mockaton # some dir in your $PATH
219
- ```
220
-
221
- </details>
222
-
223
201
  <br/>
224
202
 
225
203
 
226
204
  ## CLI Options
227
205
  The CLI options override their counterparts in `mockaton.config.js`
228
206
 
229
- <details>
230
- <summary>CLI Options…</summary>
231
-
232
207
  ```txt
233
208
  -c, --config <file> (default: ./mockaton.config.js)
234
209
 
@@ -241,10 +216,9 @@ The CLI options override their counterparts in `mockaton.config.js`
241
216
  -q, --quiet Errors only
242
217
  --no-open Don’t open dashboard in a browser (noops onReady callback)
243
218
 
244
- -h, --help Show this help
245
- -v, --version Show version
219
+ -h, --help
220
+ -v, --version
246
221
  ```
247
- </details>
248
222
 
249
223
 
250
224
  ## mockaton.config.js (Optional)
@@ -271,9 +245,9 @@ export default defineConfig({
271
245
 
272
246
  host: '127.0.0.1',
273
247
  port: 0,
274
-
248
+
275
249
  logLevel: 'normal',
276
-
250
+
277
251
  delay: 1200,
278
252
  delayJitter: 0,
279
253
 
@@ -292,8 +266,8 @@ export default defineConfig({
292
266
  corsExposedHeaders: [],
293
267
  corsCredentials: true,
294
268
  corsMaxAge: 0,
295
-
296
-
269
+
270
+
297
271
  plugins: [
298
272
  [/\.(js|ts)$/, jsToJsonPlugin]
299
273
  ],
@@ -308,7 +282,7 @@ export default defineConfig({
308
282
  <summary><b>Config Documentation…</b></summary>
309
283
 
310
284
  ### `mocksDir?: string`
311
- Defaults to `'mockaton-mocks'`.
285
+ Defaults to `'mockaton-mocks'`.
312
286
 
313
287
  ### `staticDir?: string`
314
288
  Defaults to `'mockaton-static-mocks'`.
@@ -338,7 +312,7 @@ The regex rule is tested against the basename (filename without directory path).
338
312
 
339
313
 
340
314
  ### `watcherEnabled?: boolean`
341
- Defaults to `true`
315
+ Defaults to `true`
342
316
 
343
317
  When `false`, if you **add**, **delete**, or **rename** you’ll need to click **"Reset"**
344
318
  on the Dashboard, or call `commander.reset()` in order to re-initialize the collection.
@@ -497,7 +471,7 @@ config.plugins = [
497
471
  // IOW, your plugins array overwrites the default list. This way you can remove it.
498
472
  [/\.(js|ts)$/, jsToJsonPlugin],
499
473
 
500
-
474
+
501
475
  [/\.yml$/, yamlToJsonPlugin],
502
476
 
503
477
 
@@ -555,7 +529,7 @@ At any rate, you can trigger any command besides opening a browser.
555
529
 
556
530
  <br/>
557
531
 
558
- ### `logLevel?: 'quiet' | 'normal' | 'verbose'`
532
+ ### `logLevel?: 'quiet' | 'normal' | 'verbose'`
559
533
  Defaults to `'normal'`.
560
534
 
561
535
  - `quiet`: only errors (stderr)
@@ -580,53 +554,39 @@ const server = await Mockaton(
580
554
  </details>
581
555
 
582
556
 
583
-
584
557
  <br/>
585
558
 
586
- ## Demo App (Vite + React)
587
-
588
- ```sh
589
- git clone https://github.com/ericfortis/mockaton.git --depth 1
590
- cd mockaton/demo-app-vite
591
- npm install
592
-
593
- npm run mockaton
594
- npm run start # in another terminal
595
- ```
596
-
597
- The demo app has a list of colors containing all of their possible states. For example,
598
- permutations for out-of-stock, new-arrival, and discontinued.
599
-
600
- <img src="./demo-app-vite/pixaton-tests/pic-for-readme.vp740x880.light.gold.png" alt="Mockaton Demo App Screenshot" width="740" />
601
-
602
- <br/>
603
- <br/>
604
-
605
-
606
559
 
607
560
  ## You can write JSON mocks in JavaScript or TypeScript
561
+ _TypeScript mocks need **Node 22.18+ or 23.6+**_
562
+
608
563
  For example, `api/foo.GET.200.js`
609
564
 
610
- **Option A:** An Object, Array, or String is sent as JSON.
565
+ ### Option A: An Object, Array, or String is sent as JSON
611
566
 
612
567
  ```js
613
568
  export default { foo: 'bar' }
614
569
  ```
615
570
 
616
- **Option B:** Function
571
+ ### Option B: Function (async or sync)
617
572
 
618
- Return a `string | Buffer | Uint8Array`, but don’t call `response.end()`
573
+ **Return** a `string | Buffer | Uint8Array`, but **don’t call** `response.end()`
619
574
 
620
575
  ```js
621
576
  export default (request, response) =>
622
577
  JSON.stringify({ foo: 'bar' })
623
578
  ```
624
579
 
625
- Think of these functions as HTTP handlers. For example,
626
- you can intercept requests to write to a database.
580
+ #### About Custom HTTP Handlers
581
+
582
+ For example, you can intercept requests to write to a database. Or
583
+ act based on some query string value, etc. In summary, you get Node’s
584
+ `request`, `response` as arguments, so you can think of Mockaton as a
585
+ router, but in the handlers you return, instead of ending the response.
586
+
627
587
 
628
588
  <details>
629
- <summary><b>See Intercepting Requests Examples</b></summary>
589
+ <summary><b>Examples…</b></summary>
630
590
 
631
591
  Imagine you have an initial list of colors, and
632
592
  you want to concatenate newly added colors.
@@ -668,9 +628,12 @@ export default function listColors() {
668
628
  **What if I need to serve a static .js or .ts?**
669
629
 
670
630
  **Option A:** Put it in your `config.staticDir` without the `.GET.200.js` extension.
631
+ In other words, mocks in `staticDir` take precedence over `mocksDir/*`.
671
632
 
672
633
  **Option B:** Read it and return it. For example:
673
634
  ```js
635
+ import { readFileSync } from 'node:fs'
636
+
674
637
  export default function (_, response) {
675
638
  response.setHeader('Content-Type', 'application/javascript')
676
639
  return readFileSync('./some-dir/foo.js', 'utf8')
@@ -715,7 +678,7 @@ want a `Content-Type` header in the response.
715
678
  <br/>
716
679
 
717
680
  ### Dynamic parameters
718
- Anything within square brackets is always matched.
681
+ Anything within square brackets is always matched.
719
682
 
720
683
  For example, for <a href="#">/api/company/<b>123</b>/user/<b>789</b></a>,
721
684
  the filename could be:
@@ -786,7 +749,7 @@ All of its methods return their `fetch` response promise.
786
749
  import { Commander } from 'mockaton'
787
750
 
788
751
 
789
- const myMockatonAddr = 'http://localhost:2345'
752
+ const myMockatonAddr = 'http://localhost:4040'
790
753
  const mockaton = new Commander(myMockatonAddr)
791
754
  ```
792
755
 
@@ -872,7 +835,6 @@ await mockaton.setCorsAllowed(true)
872
835
  <br/>
873
836
 
874
837
 
875
-
876
838
  ### Reset
877
839
  Re-initialize the collection. The selected mocks, cookies, and delays go back to
878
840
  default, but the `proxyFallback`, `colledProxied`, and `corsAllowed` are not affected.
@@ -882,16 +844,6 @@ await mockaton.reset()
882
844
  </details>
883
845
 
884
846
 
885
- <br/>
886
-
887
- ## Privacy and Security
888
- - Zero dependencies (no runtime and no build packages).
889
- - Does not write to disk. Except when you select ✅ **Save Mocks** for scraping mocks from a backend.
890
- - Does not initiate network connections (no logs, no telemetry).
891
- - Does not hijack your HTTP client.
892
- - Auditable. Organized and small &mdash; under 4 KLoC (half is UI and tests).
893
-
894
-
895
847
  <br/>
896
848
 
897
849
  ## Alternatives worth learning as well
@@ -901,12 +853,13 @@ These are similar to Mockaton in the sense that you can modify the
901
853
  mock response without loosing or risking your frontend code state. For
902
854
  example, if you are polling, and you want to test the state change.
903
855
 
904
- - Chrome DevTools allows for [overriding responses](https://developer.chrome.com/docs/devtools/overrides)
905
- - Reverse Proxies such as [Burp](https://portswigger.net/burp) are also handy for overriding responses
856
+ - Chrome DevTools allows for [overriding responses](https://developer.chrome.com/docs/devtools/overrides).
857
+ - Reverse Proxies such as [Burp](https://portswigger.net/burp) are also handy for overriding responses. Not easy but
858
+ very powerful.
906
859
 
907
860
  ### Client Side
908
- In contrast to Mockaton, which is an HTTP Server, these programs
909
- hijack the HTTP client in Node.js and browsers.
861
+ In contrast to Mockaton, which is an HTTP Server, these
862
+ programs hijack your browser’s HTTP client (and Node’s).
910
863
 
911
864
  - [Mock Server Worker (MSW)](https://mswjs.io)
912
865
  - [Nock](https://github.com/nock/nock)
@@ -919,8 +872,9 @@ hijack the HTTP client in Node.js and browsers.
919
872
  - [Mock](https://github.com/dhuan/mock)
920
873
  - [Swagger](https://swagger.io/)
921
874
 
875
+
876
+ <br/>
922
877
  <br/>
923
878
 
924
- ---
925
879
 
926
880
  ![](mockaton-mocks/api/user/avatar.GET.200.png)
package/package.json CHANGED
@@ -2,9 +2,14 @@
2
2
  "name": "mockaton",
3
3
  "description": "HTTP Mock Server",
4
4
  "type": "module",
5
- "version": "11.1.2",
6
- "main": "index.js",
7
- "types": "index.d.ts",
5
+ "version": "11.1.3",
6
+ "types": "./index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./index.js",
10
+ "types": "./index.d.ts"
11
+ }
12
+ },
8
13
  "license": "MIT",
9
14
  "repository": "https://github.com/ericfortis/mockaton",
10
15
  "keywords": [
package/src/Dashboard.css CHANGED
@@ -356,7 +356,6 @@ main {
356
356
  border-color: var(--colorSecondaryActionBorder);
357
357
  }
358
358
  }
359
-
360
359
  }
361
360
  }
362
361
 
@@ -377,11 +376,11 @@ table {
377
376
  tr.animIn {
378
377
  opacity: 0;
379
378
  transform: scaleY(0);
380
- animation: _kfAnimIn 180ms ease-in-out forwards;
379
+ animation: _kfRowIn 180ms ease-in-out forwards;
381
380
  }
382
381
  }
383
382
 
384
- @keyframes _kfAnimIn {
383
+ @keyframes _kfRowIn {
385
384
  to {
386
385
  opacity: 1;
387
386
  transform: scaleY(1);
@@ -31,7 +31,7 @@ export async function dispatchMock(req, response) {
31
31
  if (cookie.getCurrent())
32
32
  response.setHeader('Set-Cookie', cookie.getCurrent())
33
33
 
34
- for (let i = 0; i < config.extraHeaders.length; i += 2)
34
+ for (let i = 0; i < config.extraHeaders.length; i += 2) // TESTME
35
35
  response.setHeader(config.extraHeaders[i], config.extraHeaders[i + 1])
36
36
 
37
37
  response.statusCode = broker.auto500 ? 500 : broker.status // TESTME plugins can change it
@@ -9,18 +9,19 @@ import { config, calcDelay } from './config.js'
9
9
  import { sendMockNotFound, sendPartialContent } from './utils/http-response.js'
10
10
 
11
11
 
12
+ // TODO HEAD
12
13
  export async function dispatchStatic(req, response) {
13
14
  const broker = brokerByRoute(req.url)
14
15
 
15
16
  setTimeout(async () => {
16
- if (!broker || broker.status === 404) { // TESTME
17
+ if (!broker || broker.status === 404) {
17
18
  sendMockNotFound(response)
18
19
  return
19
20
  }
20
21
 
21
22
  const file = join(config.staticDir, broker.route)
22
23
  if (!isFile(file)) {
23
- sendMockNotFound(response) // TESTME
24
+ sendMockNotFound(response)
24
25
  return
25
26
  }
26
27
 
@@ -70,7 +70,7 @@ function filenameIsValid(file) {
70
70
 
71
71
  export function unregisterMock(file) {
72
72
  const broker = brokerByFilename(file)
73
- if (!broker)
73
+ if (!broker) // TESTME
74
74
  return
75
75
  const isEmpty = broker.unregister(file)
76
76
  if (isEmpty) {