mockaton 8.2.20 → 8.2.22

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 CHANGED
@@ -17,20 +17,21 @@ By the way, [this browser
17
17
  extension](https://github.com/ericfortis/devtools-ext-tar-http-requests)
18
18
  can create a TAR of your requests following that convention.
19
19
 
20
- Nonetheless, you don’t need to mock all your APIs. Mockaton can request from your backend
21
- the routes you don’t have mocks for. That’s done with `config.proxyFallback = 'http://mybackend'`
20
+ Nonetheless, you don’t need to mock all your APIs. Mockaton
21
+ can request from your backend the routes you don’t have mocks for.
22
+ That’s done with `config.proxyFallback = 'http://mybackend'`
22
23
 
23
24
  ## Multiple Mock Variants
24
25
  Each route can have many mocks, which could either be:
25
26
  - Different response __status code__. For example, for triggering errors.
26
27
  - __Comment__ on the filename, which is anything within parentheses.
27
- For example, `api/login(locked out user).POST.423.json`
28
+ - e.g. `api/login(locked out user).POST.423.json`
28
29
 
29
30
 
30
31
  ## Dashboard UI
31
32
 
32
33
  In the dashboard, you can select a mock variant for a particular
33
- route, among other options. But there’s also a programmatic API,
34
+ route, among other options. In addition, there’s a programmatic API,
34
35
  which is handy for setting up tests (see **Commander API** below).
35
36
 
36
37
  <picture>
@@ -64,7 +65,7 @@ node --import=tsx my-mockaton.js
64
65
 
65
66
 
66
67
  ## Running the Demo Example
67
- This demo uses the [sample-mocks/](./sample-mocks) directory of this repository.
68
+ This demo uses the [sample-mocks/](./sample-mocks) of this repository.
68
69
 
69
70
  ```sh
70
71
  git clone https://github.com/ericfortis/mockaton.git
@@ -95,9 +96,9 @@ The _Reset_ button is for registering newly added, removed, or renamed mocks.
95
96
  - slow to build assets
96
97
 
97
98
  ### Time Travel
98
- If you commit the mocks in the repo, when bisecting a bug, you don’t
99
- have to sync the frontend with many backend repos. Similarly, it
100
- allows for checking out long-lived branches with old API contracts.
99
+ If you commit the mocks to your repo, it’s straightforward to bisect bugs and
100
+ checking out long-lived branches. In other words, you don’t have to downgrade
101
+ backends to old API contracts or databases.
101
102
 
102
103
  ### Deterministic Standalone Demo Server
103
104
  Perhaps you need to demo your app, but the ideal flow is too complex to
@@ -122,15 +123,6 @@ filename, such as `(demo-part1)`, `(demo-part2)`.
122
123
  - Reverse Proxies such as [Burp](https://portswigger.net/burp) are also handy for overriding responses.
123
124
  - [Mock Server Worker](https://mswjs.io)
124
125
 
125
- ---
126
- ## Default Mock for a Route
127
- You can add the comment: `(default)` to a filename.
128
- Otherwise, the first file in **alphabetical order** wins.
129
-
130
- ```
131
- api/user(default).GET.200.json
132
- ```
133
-
134
126
  ---
135
127
 
136
128
  ## You can write JSON mocks in JavaScript or TypeScript
@@ -226,6 +218,15 @@ api/foo<b>(my comment)</b>.GET.200.json
226
218
  api/foo.GET.200.json
227
219
  </pre>
228
220
 
221
+ ### Default Mock for a Route
222
+ You can add the comment: `(default)`.
223
+ Otherwise, the first file in **alphabetical order** wins.
224
+
225
+ <pre>
226
+ api/user<b>(default)</b>.GET.200.json
227
+ </pre>
228
+
229
+
229
230
  ### Query String Params
230
231
  The query string is ignored when routing to it. In other words, it’s only used for
231
232
  documenting the URL contract.
@@ -233,13 +234,12 @@ documenting the URL contract.
233
234
  api/video<b>?limit=[limit]</b>.GET.200.json
234
235
  </pre>
235
236
 
236
- Speaking of which, in Windows, filenames containing "?" are [not
237
+ Speaking of which, on Windows filenames containing "?" are [not
237
238
  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.
238
239
 
239
240
 
240
- ### Index-like route
241
- For instance, if you have `api/foo/bar` and
242
- `api/foo`, you have two options:
241
+ ### Index-like routes
242
+ If you have `api/foo` and `api/foo/bar`, you have two options:
243
243
 
244
244
  **Option A:**
245
245
  ```
@@ -272,8 +272,7 @@ Defaults to `/(\.DS_Store|~)$/`
272
272
 
273
273
 
274
274
  ### `delay?: number` 🕓
275
- The clock icon next to the mock selector is a checkbox for delaying a particular
276
- response. The delay is globally configurable via `config.delay = 1200` (milliseconds).
275
+ The delay is globally configurable, it defaults to `1200` (milliseconds).
277
276
 
278
277
 
279
278
  ### `proxyFallback?: string`
@@ -309,15 +308,13 @@ config.cookies = {
309
308
  })
310
309
  }
311
310
  ```
312
- The selected cookie is sent in every response in a `Set-Cookie` header.
311
+ The selected cookie, which is the first one by default, is sent in every
312
+ response in a `Set-Cookie` header. If you need to send more
313
+ cookies, inject them globally in `config.extraHeaders`.
313
314
 
314
315
  By the way, the `jwtCookie` helper has a hardcoded header and signature.
315
316
  In other words, it’s useful only if you care about the payload.
316
317
 
317
- If you need to send more than one cookie,
318
- inject them globally in `config.extraHeaders`.
319
-
320
-
321
318
 
322
319
  ### `extraHeaders?: string[]`
323
320
  Note it’s a unidimensional array. The header name goes at even indices.
@@ -337,6 +334,8 @@ config.extraMimes = {
337
334
  jpe: 'application/jpeg'
338
335
  }
339
336
  ```
337
+ These media types take precedence over the built-in
338
+ [utils/mime.js](src/utils/mime.js), so you can override them.
340
339
 
341
340
 
342
341
  ### `plugins?: [filenameTester: RegExp, plugin: Plugin][]`
@@ -352,7 +351,7 @@ type Plugin = (
352
351
  ```
353
352
  Plugins are for processing mocks before sending them.
354
353
 
355
- Note: don’t call `response.end()`
354
+ Note: don’t call `response.end()` on them.
356
355
 
357
356
  <details>
358
357
  <summary><b> See Plugin Examples </b></summary>
@@ -366,7 +365,7 @@ import { readFileSync } from 'node:js'
366
365
  import { jsToJsonPlugin } from 'mockaton'
367
366
 
368
367
  config.plugins = [
369
- [/\.(js|ts)$/, jsToJsonPlugin], // Default
368
+ [/\.(js|ts)$/, jsToJsonPlugin], // Default but you need to add it to your list if you need it
370
369
  [/\.yml$/, yamlToJsonPlugin],
371
370
  [/foo\.GET\.200\.txt$/, capitalizePlugin], // e.g. GET /api/foo would be capitalized
372
371
  ]
@@ -401,7 +400,7 @@ config.corsExposedHeaders = [] // headers you need to access in client-side JS
401
400
 
402
401
 
403
402
  ### `onReady?: (dashboardUrl: string) => void`
404
- This defaults to trying to open the dashboard in your default browser in macOS and
403
+ This defaults to trying to open the dashboard in your default browser on macOS and
405
404
  Windows. For a more cross-platform utility, you could `npm install open` and pass it.
406
405
  ```js
407
406
  import open from 'open'
@@ -434,7 +433,7 @@ await mockaton.select('api/foo.200.GET.json')
434
433
  ```js
435
434
  await mockaton.bulkSelectByComment('(demo-a)')
436
435
  ```
437
- Parentheses are optional. You can pass a partial match.
436
+ Parentheses are optional, so you can pass a partial match.
438
437
  For example, passing `'demo-'` (without the final `a`), selects the
439
438
  first mock in alphabetical order that matches.
440
439
 
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.2.20",
5
+ "version": "8.2.22",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "license": "MIT",
package/src/Dashboard.css CHANGED
@@ -218,7 +218,6 @@ main {
218
218
  .MockSelector {
219
219
  width: 300px;
220
220
  height: 30px;
221
- padding: 8px 1px;
222
221
  border: 0;
223
222
  border-left: 3px solid transparent;
224
223
  text-align: right;
package/src/Dashboard.js CHANGED
@@ -60,8 +60,7 @@ init()
60
60
 
61
61
  function App(apiResponses) {
62
62
  empty(document.body)
63
- createRoot(document.body)
64
- .render(DevPanel(apiResponses))
63
+ document.body.appendChild(DevPanel(apiResponses))
65
64
  }
66
65
 
67
66
  function DevPanel([brokersByMethod, cookies, comments, corsAllowed, fallbackAddress, staticFiles]) {
@@ -404,14 +403,6 @@ function empty(node) {
404
403
  // These are simplified React-compatible implementations.
405
404
  // IOW, for switching to React, remove the `createRoot`, `createElement`, `useRef`
406
405
 
407
- function createRoot(root) {
408
- return {
409
- render(app) {
410
- root.appendChild(app)
411
- }
412
- }
413
- }
414
-
415
406
  function createElement(elem, props = null, ...children) {
416
407
  if (typeof elem === 'function')
417
408
  return elem(props)
@@ -3,7 +3,7 @@ import { join } from 'node:path'
3
3
  import { proxy } from './ProxyRelay.js'
4
4
  import { cookie } from './cookie.js'
5
5
  import { Config } from './Config.js'
6
- import { preprocessPlugins } from './MockDispatcherPlugins.js'
6
+ import { applyPlugins } from './MockDispatcherPlugins.js'
7
7
  import * as mockBrokerCollection from './mockBrokersCollection.js'
8
8
  import { JsonBodyParserError } from './utils/http-request.js'
9
9
  import { sendInternalServerError, sendNotFound, sendBadRequest } from './utils/http-response.js'
@@ -31,7 +31,7 @@ export async function dispatchMock(req, response) {
31
31
 
32
32
  const { mime, body } = broker.isTemp500
33
33
  ? { mime: '', body: '' }
34
- : await preprocessPlugins(join(Config.mocksDir, broker.file), req, response)
34
+ : await applyPlugins(join(Config.mocksDir, broker.file), req, response)
35
35
 
36
36
  response.setHeader('Content-Type', mime)
37
37
  setTimeout(() => response.end(body), broker.delay)
@@ -3,7 +3,7 @@ import { mimeFor } from './utils/mime.js'
3
3
  import { Config } from './Config.js'
4
4
 
5
5
 
6
- export async function preprocessPlugins(filePath, req, response) {
6
+ export async function applyPlugins(filePath, req, response) {
7
7
  for (const [regex, plugin] of Config.plugins) // TESTME capitalizePlugin
8
8
  if (regex.test(filePath))
9
9
  return await plugin(filePath, req, response)
package/src/Mockaton.js CHANGED
@@ -13,10 +13,8 @@ import { apiPatchRequests, apiGetRequests } from './Api.js'
13
13
  export function Mockaton(options) {
14
14
  setup(options)
15
15
  mockBrokerCollection.init()
16
-
17
- const server = createServer(onRequest)
18
- server.listen(Config.port, Config.host, (error) => {
19
- const { address, port } = server.address()
16
+ return createServer(onRequest).listen(Config.port, Config.host, function (error) {
17
+ const { address, port } = this.address()
20
18
  const url = `http://${address}:${port}`
21
19
  console.log('Listening', url)
22
20
  console.log('Dashboard', url + API.dashboard)
@@ -25,7 +23,6 @@ export function Mockaton(options) {
25
23
  else
26
24
  Config.onReady(url + API.dashboard)
27
25
  })
28
- return server
29
26
  }
30
27
 
31
28
  async function onRequest(req, response) {
@@ -98,6 +98,7 @@ const fixtures = [
98
98
  ],
99
99
 
100
100
  // Query String
101
+ // TODO ignore on Windows (because of ?)
101
102
  [
102
103
  '/api/my-query-string?foo=[foo]&bar=[bar]',
103
104
  'api/my-query-string?foo=[foo]&bar=[bar].GET.200.json',
package/src/utils/fs.js CHANGED
@@ -1,4 +1,4 @@
1
- import { join } from 'node:path'
1
+ import path, { join } from 'node:path'
2
2
  import { lstatSync, readFileSync, readdirSync } from 'node:fs'
3
3
 
4
4
 
@@ -9,4 +9,5 @@ export const read = path => readFileSync(path)
9
9
 
10
10
  /** @returns {Array<string>} paths relative to `dir` */
11
11
  export const listFilesRecursively = dir => readdirSync(dir, { recursive: true })
12
+ .map(f => f.replaceAll(path.sep, path.posix.sep)) // TESTME
12
13
  .filter(f => isFile(join(dir, f)))
@@ -6,7 +6,7 @@ export function openInBrowser(address) {
6
6
  case 'darwin':
7
7
  exec(`open ${address}`)
8
8
  break
9
- case 'win32': // TESTME
9
+ case 'win32':
10
10
  exec(`start ${address}`)
11
11
  break
12
12
  }