mockaton 11.0.1 → 11.0.2

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
@@ -6,7 +6,7 @@ watch:
6
6
 
7
7
 
8
8
  test:
9
- @node --test 'src/**/*.test.js'
9
+ @MOCKATON_WATCHER_DEBOUNCE_MS=0 node --test 'src/**/*.test.js'
10
10
 
11
11
  test-docker:
12
12
  @docker run --rm --interactive --tty \
@@ -16,7 +16,7 @@ test-docker:
16
16
  make test
17
17
 
18
18
  coverage:
19
- @node --test --experimental-test-coverage \
19
+ @MOCKATON_WATCHER_DEBOUNCE_MS=0 node --test --experimental-test-coverage \
20
20
  --test-reporter=spec --test-reporter-destination=stdout \
21
21
  --test-reporter=lcov --test-reporter-destination=lcov.info \
22
22
  'src/**/*.test.js'
package/README.md CHANGED
@@ -77,7 +77,7 @@ get saved following Mockaton’s filename convention.
77
77
 
78
78
  ### Option 2: Fallback to Your Backend
79
79
  <details>
80
- <summary>Details</summary>
80
+ <summary>Learn more…</summary>
81
81
 
82
82
  This option could be a bit elaborate if your backend uses third-party authentication,
83
83
  because you’d have to manually inject cookies or `sessionStorage` tokens.
@@ -93,7 +93,12 @@ They will be saved in your `config.mocksDir` following the filename convention.
93
93
 
94
94
  <br/>
95
95
 
96
+ <br/>
97
+
98
+
96
99
  ## Motivation
100
+ <details>
101
+ <summary>Motivation…</summary>
97
102
 
98
103
  **No API state should be too hard to test.**
99
104
  With Mockaton, developers can achieve correctness and speed.
@@ -116,15 +121,41 @@ With Mockaton, developers can achieve correctness and speed.
116
121
  - checking out long-lived branches
117
122
  - bisecting bugs
118
123
 
124
+ </details>
125
+
126
+
127
+
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.
153
+
154
+ </details>
119
155
 
120
156
  <br/>
121
157
 
122
- ## Privacy and Security
123
- - Zero dependencies (no runtime and no build packages).
124
- - Does not write to disk. Except when you select ✅ **Save Mocks** for scraping mocks from a backend.
125
- - Does not initiate network connections (no logs, no telemetry).
126
- - Does not hijack your HTTP client.
127
- - Auditable. Organized and small &mdash; under 4 KLoC (half is UI and tests).
158
+
128
159
 
129
160
  <br/>
130
161
 
@@ -147,6 +178,16 @@ npx mockaton --port 2345
147
178
  curl localhost:2345/api/foo
148
179
  ```
149
180
 
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
+
190
+
150
191
  ### Alternative Installations
151
192
  <details>
152
193
  <summary>With NPM (package.json)…</summary>
@@ -185,6 +226,9 @@ ln -s `realpath mockaton/src/cli.js` ~/bin/mockaton # some dir in your $PATH
185
226
  ## CLI Options
186
227
  The CLI options override their counterparts in `mockaton.config.js`
187
228
 
229
+ <details>
230
+ <summary>CLI Options…</summary>
231
+
188
232
  ```txt
189
233
  -c, --config <file> (default: ./mockaton.config.js)
190
234
 
@@ -200,10 +244,17 @@ The CLI options override their counterparts in `mockaton.config.js`
200
244
  -h, --help Show this help
201
245
  -v, --version Show version
202
246
  ```
247
+ </details>
203
248
 
204
249
 
205
250
  ## mockaton.config.js (Optional)
251
+ Mockaton looks for a file `mockaton.config.js` in its current working directory.
252
+
253
+ <details>
254
+ <summary>Defaults Overview… </summary>
255
+
206
256
  As an overview, these are the defaults:
257
+
207
258
  ```js
208
259
  import {
209
260
  defineConfig,
@@ -250,8 +301,10 @@ export default defineConfig({
250
301
  })
251
302
  ```
252
303
 
304
+ </details>
305
+
253
306
  <details>
254
- <summary><b>Config Documentation</b></summary>
307
+ <summary>Config Documentation…</summary>
255
308
 
256
309
  ### `mocksDir?: string`
257
310
  Defaults to `'mockaton-mocks'`.
@@ -499,7 +552,7 @@ Defaults to `'normal'`.
499
552
 
500
553
 
501
554
  <details>
502
- <summary>Programmatic Launch (Optional)</summary>
555
+ <summary>Programmatic Launch (Optional)…</summary>
503
556
 
504
557
 
505
558
  ```js
@@ -536,32 +589,6 @@ permutations for out-of-stock, new-arrival, and discontinued.
536
589
  <br/>
537
590
 
538
591
 
539
- ## Use Cases
540
- ### Testing Backend or Frontend
541
- - Empty responses
542
- - Errors such as _Bad Request_ and _Internal Server Error_
543
- - Mocking third-party APIs
544
- - Polled resources (for triggering their different states)
545
- - alerts
546
- - notifications
547
- - slow to build resources
548
-
549
- ### Testing Frontend
550
- - Spinners by delaying responses
551
- - Setting up UI tests
552
-
553
- ### Demoing complex backend states
554
- Sometimes, the ideal flow you need is too difficult to reproduce from the actual backend.
555
- For this, you can **Bulk Select** mocks by comments to simulate the complete states
556
- you want. For example, by adding `(demo-part1)`, `(demo-part2)` to the filenames.
557
-
558
- Similarly, you can deploy a **Standalone Demo Server** by compiling the frontend app and
559
- putting its built assets in `config.staticDir`. And simulate the flow by Bulk Selecting mocks.
560
- The [aot-fetch-demo repo](https://github.com/ericfortis/aot-fetch-demo) has a working example.
561
-
562
-
563
- <br/>
564
-
565
592
 
566
593
  ## You can write JSON mocks in JavaScript or TypeScript
567
594
  For example, `api/foo.GET.200.js`
@@ -841,6 +868,16 @@ await mockaton.reset()
841
868
  </details>
842
869
 
843
870
 
871
+ <br/>
872
+
873
+ ## Privacy and Security
874
+ - Zero dependencies (no runtime and no build packages).
875
+ - Does not write to disk. Except when you select ✅ **Save Mocks** for scraping mocks from a backend.
876
+ - Does not initiate network connections (no logs, no telemetry).
877
+ - Does not hijack your HTTP client.
878
+ - Auditable. Organized and small &mdash; under 4 KLoC (half is UI and tests).
879
+
880
+
844
881
  <br/>
845
882
 
846
883
  ## Alternatives worth learning as well
@@ -862,6 +899,12 @@ hijack the HTTP client in Node.js and browsers.
862
899
  - [Fetch Mock](https://github.com/wheresrhys/fetch-mock)
863
900
  - [Mentoss](https://github.com/humanwhocodes/mentoss) Has a server side too
864
901
 
902
+ ### Server Side
903
+
904
+ - [Wire Mock](https://github.com/wiremock/wiremock)
905
+ - [Mock](https://github.com/dhuan/mock)
906
+ - [Swagger](https://swagger.io/)
907
+
865
908
  <br/>
866
909
 
867
910
  ---
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "mockaton",
3
3
  "description": "HTTP Mock Server",
4
4
  "type": "module",
5
- "version": "11.0.1",
5
+ "version": "11.0.2",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "license": "MIT",
package/src/Api.js CHANGED
@@ -81,7 +81,8 @@ function getState(_, response) {
81
81
 
82
82
 
83
83
  function longPollClientSyncVersion(req, response) {
84
- if (uiSyncVersion.version !== Number(req.headers[HEADER_SYNC_VERSION])) {
84
+ const clientVersion = req.headers[HEADER_SYNC_VERSION]
85
+ if (clientVersion !== undefined && uiSyncVersion.version !== Number(clientVersion)) {
85
86
  // e.g., tab was hidden while new mocks were added or removed
86
87
  sendJSON(response, uiSyncVersion.version)
87
88
  return
@@ -9,80 +9,49 @@ export class Commander {
9
9
  this.#addr = addr
10
10
  }
11
11
 
12
- #patch = (api, body) =>
13
- fetch(this.#addr + api, {
14
- method: 'PATCH',
15
- body: JSON.stringify(body)
16
- })
17
-
18
12
  /** @returns {JsonPromise<State>} */
19
13
  getState = () =>
20
14
  fetch(this.#addr + API.state)
21
15
 
22
- /** @returns {JsonPromise<number>} */
23
- getSyncVersion = (currSyncVer, abortSignal = undefined) =>
16
+ /**
17
+ * @param {number?} currSyncVer - On mismatch, it responds immediately. Otherwise, long polls.
18
+ * @param {AbortSignal} abortSignal
19
+ * @returns {JsonPromise<number>}
20
+ */
21
+ getSyncVersion = (currSyncVer = undefined, abortSignal = undefined) =>
24
22
  fetch(this.#addr + API.syncVersion, {
25
23
  signal: AbortSignal.any([
26
24
  abortSignal,
27
25
  AbortSignal.timeout(LONG_POLL_SERVER_TIMEOUT + 1000)
28
26
  ].filter(Boolean)),
29
- headers: {
30
- [HEADER_SYNC_VERSION]: currSyncVer
31
- }
27
+ headers: currSyncVer !== undefined
28
+ ? { [HEADER_SYNC_VERSION]: currSyncVer }
29
+ : {}
32
30
  })
33
31
 
34
32
 
35
- reset() {
36
- return this.#patch(API.reset)
37
- }
38
-
39
- setGlobalDelay(delay) {
40
- return this.#patch(API.globalDelay, delay)
41
- }
42
-
43
- bulkSelectByComment(comment) {
44
- return this.#patch(API.bulkSelect, comment)
45
- }
46
-
47
- selectCookie(cookieKey) {
48
- return this.#patch(API.cookies, cookieKey)
49
- }
50
-
51
- setProxyFallback(proxyAddr) {
52
- return this.#patch(API.fallback, proxyAddr)
53
- }
54
-
55
- setCollectProxied(shouldCollect) {
56
- return this.#patch(API.collectProxied, shouldCollect)
57
- }
58
-
59
- setCorsAllowed(value) {
60
- return this.#patch(API.cors, value)
61
- }
62
-
63
-
64
- select(file) {
65
- return this.#patch(API.select, file)
33
+ #patch(api, body) {
34
+ return fetch(this.#addr + api, {
35
+ method: 'PATCH',
36
+ body: JSON.stringify(body)
37
+ })
66
38
  }
67
39
 
68
- toggle500(method, urlMask) {
69
- return this.#patch(API.toggle500, [method, urlMask])
70
- }
40
+ reset = () => this.#patch(API.reset)
71
41
 
72
- setRouteIsDelayed(method, urlMask, delayed) {
73
- return this.#patch(API.delay, [method, urlMask, delayed])
74
- }
42
+ selectCookie = label => this.#patch(API.cookies, label)
43
+ setGlobalDelay = delay => this.#patch(API.globalDelay, delay)
44
+ setCorsAllowed = value => this.#patch(API.cors, value)
45
+ setProxyFallback = proxyAddr => this.#patch(API.fallback, proxyAddr)
46
+ setCollectProxied = shouldCollect => this.#patch(API.collectProxied, shouldCollect)
75
47
 
76
- setRouteIsProxied(method, urlMask, proxied) {
77
- return this.#patch(API.proxied, [method, urlMask, proxied])
78
- }
79
-
48
+ select = file => this.#patch(API.select, file)
49
+ bulkSelectByComment = comment => this.#patch(API.bulkSelect, comment)
80
50
 
81
- setStaticRouteIsDelayed(urlMask, delayed) {
82
- return this.#patch(API.delayStatic, [urlMask, delayed])
83
- }
51
+ toggle500 = (method, urlMask) => this.#patch(API.toggle500, [method, urlMask])
52
+ setRouteIsProxied = (method, urlMask, proxied) => this.#patch(API.proxied, [method, urlMask, proxied])
53
+ setRouteIsDelayed = (method, urlMask, delayed) => this.#patch(API.delay, [method, urlMask, delayed])
84
54
 
85
- setStaticRouteStatus(urlMask, status) {
86
- return this.#patch(API.staticStatus, [urlMask, status])
87
- }
55
+ setStaticRouteStatus = (urlMask, status) => this.#patch(API.staticStatus, [urlMask, status])
56
+ setStaticRouteIsDelayed = (urlMask, delayed) => this.#patch(API.delayStatic, [urlMask, delayed])
88
57
  }
package/src/Dashboard.js CHANGED
@@ -734,7 +734,7 @@ function SettingsIcon() {
734
734
  * The version increments when a mock file is added, removed, or renamed.
735
735
  */
736
736
  function initRealTimeUpdates() {
737
- let oldVersion = -1
737
+ let oldVersion = undefined
738
738
  let controller = new AbortController()
739
739
 
740
740
  longPoll()
@@ -755,11 +755,9 @@ function initRealTimeUpdates() {
755
755
  ErrorToast.close()
756
756
 
757
757
  const version = await response.json()
758
- const skipUpdate = oldVersion === -1
759
758
  if (oldVersion !== version) { // because it could be < or >
760
759
  oldVersion = version
761
- if (!skipUpdate)
762
- store.fetchState()
760
+ store.fetchState()
763
761
  }
764
762
  longPoll()
765
763
  }
package/src/MockBroker.js CHANGED
@@ -114,7 +114,7 @@ class UrlMatcher {
114
114
  }
115
115
 
116
116
  #disregardVariables(str) { // Stars out all parts that are in square brackets
117
- return str.replace(/\[.*?]/g, '[^/]*')
117
+ return str.replace(/\[.*?]/g, '[^/]+')
118
118
  }
119
119
 
120
120
  // Appending a '/' so URLs ending with variables don't match
package/src/Watcher.js CHANGED
@@ -15,6 +15,7 @@ import * as mockBrokerCollection from './mockBrokersCollection.js'
15
15
  * and also renames, which are two events (delete + add).
16
16
  */
17
17
  export const uiSyncVersion = new class extends EventEmitter {
18
+ delay = Number(process.env.MOCKATON_WATCHER_DEBOUNCE_MS ?? 80)
18
19
  version = 0
19
20
 
20
21
  increment = this.#debounce(() => {
@@ -33,7 +34,7 @@ export const uiSyncVersion = new class extends EventEmitter {
33
34
  let timer
34
35
  return () => {
35
36
  clearTimeout(timer)
36
- timer = setTimeout(fn, 80)
37
+ timer = setTimeout(fn, this.delay)
37
38
  }
38
39
  }
39
40
  }
@@ -64,7 +65,7 @@ export function watchStaticDir() {
64
65
  const dir = config.staticDir
65
66
  if (!dir)
66
67
  return
67
-
68
+
68
69
  watch(dir, { recursive: true, persistent: false }, (_, file) => {
69
70
  if (!file)
70
71
  return