mockaton 13.4.1 → 13.5.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 CHANGED
@@ -79,7 +79,7 @@ export default {
79
79
 
80
80
  <br/>
81
81
 
82
- Similarly, you can handle logic with [Functional Mocks](https://mockaton.com/functional-mocks):
82
+ Similarly, you can handle logic with [Function Mocks](https://mockaton.com/function-mocks):
83
83
 
84
84
  <code>my_mocks_dir/<b>api/company/[companyId]/user/[userId]</b>.GET.200.ts</code>
85
85
  ```ts
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "mockaton",
3
3
  "description": "HTTP Mock Server",
4
4
  "type": "module",
5
- "version": "13.4.1",
5
+ "version": "13.5.0",
6
6
  "exports": {
7
7
  ".": {
8
8
  "import": "./index.js",
@@ -65,4 +65,6 @@ export class Commander {
65
65
  * @returns {Promise<Response>}
66
66
  */
67
67
  getSyncVersion = () => fetch(this.addr + API.syncVersion)
68
+
69
+ getOpenAPI = () => fetch(this.addr + API.openAPI)
68
70
  }
@@ -4,25 +4,33 @@ const MOUNT = '/mockaton'
4
4
 
5
5
  export const API = {
6
6
  dashboard: MOUNT,
7
+
8
+ reset: MOUNT + '/reset',
9
+
10
+ select: MOUNT + '/select',
7
11
  bulkSelect: MOUNT + '/bulk-select-by-comment',
8
- collectProxied: MOUNT + '/collect-proxied',
9
- cookies: MOUNT + '/cookies',
10
- cors: MOUNT + '/cors',
12
+
11
13
  delay: MOUNT + '/delay',
14
+ proxied: MOUNT + '/proxied',
15
+ toggleStatus: MOUNT + '/toggle-status',
16
+
17
+ cors: MOUNT + '/cors',
18
+ cookies: MOUNT + '/cookies',
12
19
  fallback: MOUNT + '/fallback',
20
+ collectProxied: MOUNT + '/collect-proxied',
13
21
  globalDelay: MOUNT + '/global-delay',
14
22
  globalDelayJitter: MOUNT + '/global-delay-jitter',
15
- proxied: MOUNT + '/proxied',
16
- reset: MOUNT + '/reset',
17
- select: MOUNT + '/select',
23
+
24
+ writeMock: MOUNT + '/write-mock',
25
+ deleteMock: MOUNT + '/delete-mock',
26
+ watchMocks: MOUNT + '/watch-mocks',
27
+
18
28
  state: MOUNT + '/state',
19
- syncVersion: MOUNT + '/sync-version',
20
29
  throws: MOUNT + '/throws',
21
- toggleStatus: MOUNT + '/toggle-status',
30
+ syncVersion: MOUNT + '/sync-version',
22
31
  watchHotReload: MOUNT + '/watch-hot-reload',
23
- watchMocks: MOUNT + '/watch-mocks',
24
- writeMock: MOUNT + '/write-mock',
25
- deleteMock: MOUNT + '/delete-mock',
32
+
33
+ openAPI: MOUNT + '/openapi'
26
34
  }
27
35
 
28
36
  export const DEFAULT_MOCK_COMMENT = '(default)'
package/src/server/Api.js CHANGED
@@ -7,6 +7,7 @@ import { join } from 'node:path'
7
7
  import { readdirSync } from 'node:fs'
8
8
  import { write, rm, isFile, resolveIn } from './utils/fs.js'
9
9
 
10
+ import openapi from '../../www/src/assets/openapi.json' with { type: 'json' }
10
11
  import pkgJSON from '../../package.json' with { type: 'json' }
11
12
 
12
13
  import { sseClientHotReload } from './utils/WatcherDevClient.js'
@@ -24,7 +25,6 @@ export const CLIENT_DIR = join(import.meta.dirname, '../client')
24
25
  const DASHBOARD_ASSETS = readdirSync(CLIENT_DIR, { recursive: true })
25
26
 
26
27
 
27
-
28
28
  export const apiGetReqs = new Map([
29
29
  [API.dashboard, serveDashboard],
30
30
  ...DASHBOARD_ASSETS.map(f => [API.dashboard + '/' + f, serveStatic(f)]),
@@ -33,7 +33,8 @@ export const apiGetReqs = new Map([
33
33
  [API.syncVersion, sseClientSyncVersion],
34
34
 
35
35
  [API.watchHotReload, onDevWatch],
36
- [API.throws, () => { throw new Error('Test500') }]
36
+ [API.throws, () => { throw new Error('Test500') }],
37
+ [API.openAPI, (_, response) => response.json(openapi)]
37
38
  ])
38
39
 
39
40
 
@@ -96,7 +97,6 @@ function onDevWatch(req, response) {
96
97
  else
97
98
  response.notFound()
98
99
  }
99
-
100
100
  /** # PATCH */
101
101
 
102
102
  function reset(_, response) {
@@ -74,7 +74,7 @@ function request(path, options = {}) {
74
74
  class Fixture {
75
75
  constructor(file, body = '') {
76
76
  this.file = file
77
- this.body = body || `Body for ${file}`
77
+ this.body = body || `Body for: ${file}`
78
78
  const t = parseFilename(file)
79
79
  this.urlMask = t.urlMask
80
80
  this.method = t.method
@@ -227,6 +227,14 @@ describe('Dashboard', () => {
227
227
  })
228
228
 
229
229
 
230
+ describe('OpenAPI', () => {
231
+ test('serves the json spec', async () => {
232
+ const r = await request(API.openAPI)
233
+ match(await r.text(), new RegExp('"openapi":'))
234
+ })
235
+ })
236
+
237
+
230
238
  describe('Cookie', () => {
231
239
  test('422 when trying to select non-existing cookie', async () => {
232
240
  const r = await api.selectCookie('non-existing-cookie-key')
@@ -336,7 +344,8 @@ describe('Proxy Fallback', () => {
336
344
  response.writeHead(423, {
337
345
  'custom_header': 'my_custom_header',
338
346
  'content-type': mimeFor('.json'),
339
- 'set-cookie': CUSTOM_COOKIES
347
+ 'set-cookie': CUSTOM_COOKIES,
348
+ 'cache-control': 'public'
340
349
  })
341
350
  response.end(JSON.stringify(BODY_PAYLOAD))
342
351
  })
@@ -360,6 +369,9 @@ describe('Proxy Fallback', () => {
360
369
  equal(r1.headers.get('set-cookie'), CUSTOM_COOKIES.join(', '))
361
370
  equal(r2.headers.get('set-cookie'), CUSTOM_COOKIES.join(', '))
362
371
 
372
+ equal(r1.headers.get('cache-control'), 'no-cache') // unsets cache
373
+ equal(r2.headers.get('cache-control'), 'no-cache')
374
+
363
375
  deepEqual(await r2.json(), BODY_PAYLOAD)
364
376
  deepEqual(await r1.json(), BODY_PAYLOAD)
365
377
 
@@ -34,7 +34,8 @@ export async function proxy(req, response, delay) {
34
34
 
35
35
  response.writeHead(proxyResponse.status, {
36
36
  ...Object.fromEntries(proxyResponse.headers),
37
- 'Set-Cookie': proxyResponse.headers.getSetCookie() // parses multiple into an array
37
+ 'set-cookie': proxyResponse.headers.getSetCookie(), // parses multiple into an array
38
+ 'cache-control': 'no-cache'
38
39
  })
39
40
  const body = await proxyResponse.text()
40
41
  setTimeout(() => response.end(body), delay) // TESTME
@@ -1,8 +1,8 @@
1
1
  {
2
- "openapi": "3.1.2",
2
+ "openapi": "3.2.0",
3
3
  "info": {
4
4
  "title": "Mockaton Control API",
5
- "version": "1.0.0"
5
+ "version": "1.0.1"
6
6
  },
7
7
  "servers": [
8
8
  {
@@ -10,6 +10,26 @@
10
10
  }
11
11
  ],
12
12
  "paths": {
13
+ "/mockaton/openapi": {
14
+ "get": {
15
+ "summary": "Get this OpenAPI spec",
16
+ "x-js-client-example": "await mockaton.getOpenAPI()",
17
+ "responses": {
18
+ "200": {
19
+ "description": "OpenAPI spec",
20
+ "content": {
21
+ "application/json": {
22
+ "schema": {
23
+ "type": "object",
24
+ "additionalProperties": true
25
+ }
26
+ }
27
+ }
28
+ }
29
+ }
30
+ }
31
+ },
32
+
13
33
  "/mockaton/state": {
14
34
  "get": {
15
35
  "summary": "Get complete Mockaton state",
@@ -488,29 +508,17 @@
488
508
  },
489
509
  "/mockaton/sync-version": {
490
510
  "get": {
491
- "summary": "Get sync version for long‑polling updates",
511
+ "summary": "Get sync version as SSE",
492
512
  "description": "A counter that’s incremented when a new mock is added, removed, or renamed. Also, when the internal state changes, e.g., when changing the mock file for a route.",
493
513
  "x-js-client-example": "await mockaton.getSyncVersion()",
494
- "parameters": [
495
- {
496
- "name": "sync_version",
497
- "in": "header",
498
- "required": false,
499
- "example": -1,
500
- "schema": {
501
- "type": "number"
502
- },
503
- "description": "When not present, or when the version mismatches it responds right away. Otherwise, it long polls. Times out in 8s."
504
- }
505
- ],
506
514
  "responses": {
507
515
  "200": {
508
- "description": "Sync version value",
516
+ "description": "Stream of sync version updates (SSE)",
509
517
  "content": {
510
- "application/json": {
518
+ "text/event-stream": {
511
519
  "schema": {
512
- "type": "number",
513
- "description": "Incremental integer"
520
+ "type": "integer",
521
+ "description": "Incremental sync version emitted per event"
514
522
  }
515
523
  }
516
524
  }