mockaton 11.2.1 → 11.2.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/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  <img src="src/Logo.svg" alt="Mockaton Logo" width="210" style="margin-top: 30px"/>
2
2
 
3
3
  ![NPM Version](https://img.shields.io/npm/v/mockaton)
4
- ![NPM Version](https://img.shields.io/npm/l/mockaton)
5
4
  [![Test](https://github.com/ericfortis/mockaton/actions/workflows/test.yml/badge.svg)](https://github.com/ericfortis/mockaton/actions/workflows/test.yml)
6
5
  [![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
6
  [![codecov](https://codecov.io/github/ericfortis/mockaton/graph/badge.svg?token=90NYLMMG1J)](https://codecov.io/github/ericfortis/mockaton)
@@ -17,16 +16,17 @@ following a convention similar to the URLs.
17
16
  For example, for [/api/company/123](#), the filename could be:
18
17
 
19
18
  <pre>
20
- <code>my-mocks-dir/<b>api/company</b>/[company-id].GET.200.json</code>
19
+ <code>my-mocks-dir/<b>api/company</b>/[id].GET.200.json</code>
21
20
  </pre>
22
21
 
23
22
  <br/>
24
23
 
25
24
 
26
25
  ## Quick Start (Docker)
27
- This will spin up Mockaton with the mock directories included in this repo:
28
- [mockaton-mocks/](./mockaton-mocks) and [mockaton-static-mocks/](./mockaton-static-mocks)
29
- mounted on the container.
26
+ This will spin up Mockaton with the sample directories
27
+ included in this repo mounted on the container.
28
+
29
+ _[mockaton-mocks/](./mockaton-mocks) and [mockaton-static-mocks/](./mockaton-static-mocks)_
30
30
 
31
31
  ```sh
32
32
  git clone https://github.com/ericfortis/mockaton.git --depth 1
@@ -117,7 +117,6 @@ They will be saved in your `config.mocksDir` following the filename convention.
117
117
  </details>
118
118
 
119
119
  <br/>
120
-
121
120
  <br/>
122
121
 
123
122
 
@@ -156,9 +155,9 @@ make run-standalone-demo
156
155
 
157
156
  ### Testing scenarios that would otherwise be skipped
158
157
  - Trigger dynamic states on an API. You can do this by using comments on mock filenames, for example, for polled alerts or notifications.
159
- - Testing retries, on-the-fly you can change an endpoint from a 500 to a 200.
158
+ - Testing retries, you can change an endpoint from a 500 to a 200 on the fly.
160
159
  - Simulate errors on third-party APIs, or on your project’s backend (if you are a frontend dev, or unfamiliar with that code)
161
- - Generating dynamic responses on the fly. Mockaton lets you use Node’s HTTP handlers (see function mocks) when using function mocks.
160
+ - Generating dynamic responses. Mockaton lets you use Node’s HTTP handlers (see function mocks) when using function mocks.
162
161
  So you can, e.g.:
163
162
  - have an in-memory database
164
163
  - read from disk
@@ -194,9 +193,9 @@ backends when checking out long-lived branches or bisecting bugs.
194
193
 
195
194
  _For Docker, see the Quick-Start section above._
196
195
 
197
- Requires Node.js **v22.18+**, which supports mocks in TypeScript.
196
+ Requires Node.js **v22.18+**, which supports TypeScript mocks.
198
197
 
199
- 1. Create a mock in the default mocks directory (`./mockaton-mocks`)
198
+ 1. Create a mock in the default directory (`./mockaton-mocks`)
200
199
  ```sh
201
200
  mkdir -p mockaton-mocks/api
202
201
  echo "[1,2,3]" > mockaton-mocks/api/foo.GET.200.json
@@ -239,7 +238,7 @@ The CLI options override their counterparts in `mockaton.config.js`
239
238
  -p, --port <port> (default: 0) which means auto-assigned
240
239
 
241
240
  -q, --quiet Errors only
242
- --no-open Don’t open dashboard in a browser (noops onReady callback)
241
+ --no-open Don’t open dashboard in a browser
243
242
 
244
243
  -h, --help
245
244
  -v, --version
@@ -266,7 +265,7 @@ export default defineConfig({
266
265
 
267
266
  logLevel: 'normal',
268
267
 
269
- delay: 1200, // Global value in ms. But only applied to routes with the Delayed checkbox "ON"
268
+ delay: 1200, // ms. Applies to routes with the Delay Checkbox "ON"
270
269
  delayJitter: 0,
271
270
 
272
271
  proxyFallback: '',
@@ -285,7 +284,6 @@ export default defineConfig({
285
284
  corsCredentials: true,
286
285
  corsMaxAge: 0,
287
286
 
288
-
289
287
  plugins: [
290
288
  [/\.(js|ts)$/, jsToJsonPlugin]
291
289
  ],
@@ -575,7 +573,7 @@ const server = await Mockaton(
575
573
 
576
574
 
577
575
  ## You can write JSON mocks in JavaScript or TypeScript
578
- _TypeScript mocks need **Node 22.18+ or 23.6+**_
576
+ _TypeScript needs **Node 22.18+ or 23.6+**_
579
577
 
580
578
  For example, `api/foo.GET.200.js`
581
579
 
@@ -675,7 +673,6 @@ want a `Content-Type` header in the response.
675
673
 
676
674
  <details>
677
675
  <summary>Supported Methods</summary>
678
- <p>From <code>require('node:http').METHODS</code></p>
679
676
  <p>
680
677
  ACL, BIND, CHECKOUT,
681
678
  CONNECT, COPY, DELETE,
@@ -715,8 +712,6 @@ api/foo.GET.200.json
715
712
 
716
713
  A filename can have many comments.
717
714
 
718
- <br/>
719
-
720
715
  ### Default mock for a route
721
716
  You can add the comment: `(default)`.
722
717
  Otherwise, the first file in **alphabetical order** wins.
@@ -736,7 +731,7 @@ api/video<b>?limit=[limit]</b>.GET.200.json
736
731
 
737
732
  On Windows, filenames containing "?" are [not
738
733
  permitted](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file), but since that’s part of the query
739
- string it’s ignored anyway.
734
+ string, it’s ignored anyway.
740
735
 
741
736
  <br/>
742
737
 
@@ -864,6 +859,9 @@ await mockaton.reset()
864
859
 
865
860
  ## Alternatives worth learning as well
866
861
 
862
+ <details>
863
+ <summary>Learn more…</summary>
864
+
867
865
  ### Proxy-like
868
866
  These are similar to Mockaton in the sense that you can modify the
869
867
  mock response without loosing or risking your frontend code state. For
@@ -889,6 +887,7 @@ programs hijack your browser’s HTTP client (and Node’s).
889
887
  - [Swagger](https://swagger.io/)
890
888
  - [Mockoon](https://mockoon.com)
891
889
 
890
+ </details>
892
891
 
893
892
  <br/>
894
893
  <br/>
package/index.d.ts CHANGED
@@ -43,6 +43,8 @@ export interface Config {
43
43
  plugins?: [filenameTester: RegExp, plugin: Plugin][]
44
44
 
45
45
  onReady?: (address: string) => void
46
+
47
+ hotReload?: boolean // For UI dev purposes only
46
48
  }
47
49
 
48
50
 
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.2.1",
5
+ "version": "11.2.2",
6
6
  "types": "./index.d.ts",
7
7
  "exports": {
8
8
  ".": {
package/src/Api.js CHANGED
@@ -6,6 +6,7 @@
6
6
  import { join } from 'node:path'
7
7
 
8
8
  import { cookie } from './cookie.js'
9
+ import { devWatcher } from './WatcherDev.js'
9
10
  import { parseJSON } from './utils/http-request.js'
10
11
  import { uiSyncVersion } from './Watcher.js'
11
12
  import * as staticCollection from './staticCollection.js'
@@ -16,23 +17,31 @@ import { sendOK, sendJSON, sendUnprocessable, sendFile, sendHTML } from './utils
16
17
  import { API, LONG_POLL_SERVER_TIMEOUT, HEADER_SYNC_VERSION } from './ApiConstants.js'
17
18
 
18
19
 
20
+ const DEV = process.env.NODE_ENV === 'development'
21
+
22
+ export const DASHBOARD_ASSETS = [
23
+ 'Dashboard.css',
24
+ 'Dashboard.js',
25
+ 'DashboardDom.js',
26
+ 'DashboardStore.js',
27
+ 'DashboardDevHotReload.js',
28
+ 'ApiCommander.js',
29
+ 'Logo.svg',
30
+ 'Filename.js', // used on server too
31
+ 'ApiConstants.js', // used on server too
32
+ ]
33
+
19
34
  export const apiGetRequests = new Map([
20
35
  [API.dashboard, serveDashboard],
21
- ...[
22
- 'Logo.svg',
23
- 'Dashboard.css',
24
- 'ApiCommander.js',
25
- 'ApiConstants.js',
26
- 'Dashboard.js',
27
- 'DashboardDom.js',
28
- 'DashboardStore.js',
29
- 'Filename.js'
30
- ].map(f => [API.dashboard + '/' + f, serveStatic(f)]),
31
-
36
+ ...DASHBOARD_ASSETS.map(f => [API.dashboard + '/' + f, serveStatic(f)]),
37
+
32
38
  [API.state, getState],
33
39
  [API.syncVersion, longPollClientSyncVersion],
34
- [API.throws, () => { throw new Error('Test500') }]
35
40
  ])
41
+ if (DEV) {
42
+ apiGetRequests.set(API.throws, () => { throw new Error('Test500') })
43
+ apiGetRequests.set(API.watchHotReload, longPollDevHotReload)
44
+ }
36
45
 
37
46
  export const apiPatchRequests = new Map([
38
47
  [API.cors, setCorsAllowed],
@@ -54,7 +63,7 @@ export const apiPatchRequests = new Map([
54
63
  /** # GET */
55
64
 
56
65
  function serveDashboard(_, response) {
57
- sendHTML(response, DashboardHtml, CSP)
66
+ sendHTML(response, DashboardHtml(config.hotReload), CSP)
58
67
  }
59
68
 
60
69
  function serveStatic(f) {
@@ -101,6 +110,23 @@ function longPollClientSyncVersion(req, response) {
101
110
  }
102
111
 
103
112
 
113
+ function longPollDevHotReload(req, response) {
114
+ function onDevChange(file) {
115
+ devWatcher.unsubscribe(onDevChange)
116
+ sendJSON(response, file)
117
+ }
118
+ response.setTimeout(LONG_POLL_SERVER_TIMEOUT, () => {
119
+ devWatcher.unsubscribe(onDevChange)
120
+ sendJSON(response, '')
121
+ })
122
+ req.on('error', () => {
123
+ devWatcher.unsubscribe(onDevChange)
124
+ response.destroy()
125
+ })
126
+ devWatcher.subscribe(onDevChange)
127
+ }
128
+
129
+
104
130
 
105
131
  /** # PATCH */
106
132
 
@@ -17,7 +17,8 @@ export const API = {
17
17
  staticStatus: MOUNT + '/static-status',
18
18
  syncVersion: MOUNT + '/sync-version',
19
19
  throws: MOUNT + '/throws',
20
- toggle500: MOUNT + '/toggle500'
20
+ toggle500: MOUNT + '/toggle500',
21
+ watchHotReload: MOUNT + '/watch-hot-reload',
21
22
  }
22
23
 
23
24
  export const HEADER_502 = 'Mockaton502'
package/src/Dashboard.js CHANGED
@@ -737,7 +737,7 @@ function SettingsIcon() {
737
737
  * The version increments when a mock file is added, removed, or renamed.
738
738
  */
739
739
  function initRealTimeUpdates() {
740
- let oldVersion = undefined // undefined waits until next event or timeout
740
+ let oldVersion = undefined // undefined so it waits until next event or timeout
741
741
  let controller = new AbortController()
742
742
 
743
743
  longPoll()
@@ -823,8 +823,12 @@ function initKeyboardNavigation() {
823
823
 
824
824
 
825
825
  function SyntaxJSON(json) {
826
+ // Capture groups: [string, optional colon, punc]
827
+ const regex = /("(?:\\u[a-fA-F0-9]{4}|\\[^u]|[^\\"])*")(\s*:)?|([{}\[\],:\s]+)|\S+/g
828
+
826
829
  const MAX_NODES = 50_000
827
830
  let nNodes = 0
831
+
828
832
  const frag = new DocumentFragment()
829
833
 
830
834
  function span(className, textContent) {
@@ -842,8 +846,7 @@ function SyntaxJSON(json) {
842
846
 
843
847
  let match
844
848
  let lastIndex = 0
845
- SyntaxJSON.regex.lastIndex = 0 // resets regex
846
- while ((match = SyntaxJSON.regex.exec(json)) !== null) {
849
+ while ((match = regex.exec(json)) !== null) {
847
850
  if (nNodes > MAX_NODES)
848
851
  break
849
852
 
@@ -865,13 +868,15 @@ function SyntaxJSON(json) {
865
868
  text(json.slice(lastIndex))
866
869
  return frag
867
870
  }
868
- SyntaxJSON.regex = /("(?:\\u[a-fA-F0-9]{4}|\\[^u]|[^\\"])*")(\s*:)?|([{}\[\],:\s]+)|\S+/g
869
- // Capture group order: [string, optional colon, punc]
870
871
 
871
872
 
872
873
  function SyntaxXML(xml) {
874
+ // Capture groups: [tagPunc, tagName, attrName, attrVal]
875
+ const regex = /(<\/?|\/?>|\?>)|(?<=<\??\/?)([A-Za-z_:][\w:.-]*)|([A-Za-z_:][\w:.-]*)(?==)|("(?:[^"\\]|\\.)*")/g
876
+
873
877
  const MAX_NODES = 50_000
874
878
  let nNodes = 0
879
+
875
880
  const frag = new DocumentFragment()
876
881
 
877
882
  function span(className, textContent) {
@@ -889,8 +894,7 @@ function SyntaxXML(xml) {
889
894
 
890
895
  let match
891
896
  let lastIndex = 0
892
- SyntaxXML.regex.lastIndex = 0
893
- while ((match = SyntaxXML.regex.exec(xml)) !== null) {
897
+ while ((match = regex.exec(xml)) !== null) {
894
898
  if (nNodes > MAX_NODES)
895
899
  break
896
900
 
@@ -908,6 +912,4 @@ function SyntaxXML(xml) {
908
912
  frag.normalize()
909
913
  return frag
910
914
  }
911
- SyntaxXML.regex = /(<\/?|\/?>|\?>)|(?<=<\??\/?)([A-Za-z_:][\w:.-]*)|([A-Za-z_:][\w:.-]*)(?==)|("(?:[^"\\]|\\.)*")/g
912
- // Capture groups order: [tagPunc, tagName, attrName, attrVal]
913
915
 
@@ -0,0 +1,34 @@
1
+ import { API } from './ApiConstants.js'
2
+
3
+
4
+ longPoll()
5
+ async function longPoll() {
6
+ try {
7
+ const response = await fetch(API.watchHotReload)
8
+ if (response.ok) {
9
+ const editedFile = await response.json() || ''
10
+ if (editedFile.endsWith('.css')) {
11
+ hotReloadCSS(editedFile)
12
+ longPoll()
13
+ }
14
+ else if (editedFile)
15
+ location.reload()
16
+ else
17
+ longPoll()
18
+ }
19
+ else
20
+ throw response.statusText
21
+ }
22
+ catch (error) {
23
+ console.error('hot reload', error?.message || error)
24
+ setTimeout(longPoll, 3000)
25
+ }
26
+ }
27
+
28
+ function hotReloadCSS(editedFile) {
29
+ const link = document.querySelector(`link[href*="${editedFile}"]`)
30
+ if (link) {
31
+ const href = link.href.split('?')[0]
32
+ link.href = href + '?t=' + Date.now()
33
+ }
34
+ }
@@ -6,7 +6,7 @@ export const CSP = [
6
6
  ].join(';')
7
7
 
8
8
 
9
- export const DashboardHtml = `<!DOCTYPE html>
9
+ export const DashboardHtml = hotReloadEnabled => `<!DOCTYPE html>
10
10
  <html lang="en-US">
11
11
  <head>
12
12
  <meta charset="UTF-8">
@@ -30,6 +30,7 @@ export const DashboardHtml = `<!DOCTYPE html>
30
30
  <title>Mockaton</title>
31
31
  </head>
32
32
  <body>
33
+ ${hotReloadEnabled ? `<script type="module" src="DashboardDevHotReload.js"></script>` : '' }
33
34
  </body>
34
35
  </html>
35
36
  `
@@ -31,8 +31,8 @@ export async function dispatchMock(req, response) {
31
31
  if (cookie.getCurrent())
32
32
  response.setHeader('Set-Cookie', cookie.getCurrent())
33
33
 
34
- response.statusCode = broker.auto500
35
- ? 500
34
+ response.statusCode = broker.auto500
35
+ ? 500
36
36
  : broker.status
37
37
  const { mime, body } = broker.auto500
38
38
  ? { mime: '', body: '' }
@@ -40,10 +40,13 @@ export async function dispatchMock(req, response) {
40
40
 
41
41
  response.setHeader('Content-Type', mime)
42
42
  response.setHeader('Content-Length', length(body))
43
-
44
- setTimeout(() => response.end(isHead ? null : body),
45
- Number(broker.delayed && calcDelay()))
46
-
43
+
44
+ setTimeout(() =>
45
+ response.end(isHead
46
+ ? null
47
+ : body
48
+ ), Number(broker.delayed && calcDelay()))
49
+
47
50
  logger.accessMock(req.url, broker.file)
48
51
  }
49
52
  catch (error) { // TESTME
@@ -77,7 +80,6 @@ export async function jsToJsonPlugin(filePath, req, response) {
77
80
 
78
81
  function length(body) {
79
82
  if (typeof body === 'string') return Buffer.byteLength(body)
80
- if (Buffer.isBuffer(body)) return body.length // TESTME
81
- if (body instanceof Uint8Array) return body.byteLength
83
+ if (body instanceof Uint8Array) return body.byteLength // Buffers are u8
82
84
  return 0
83
85
  }
package/src/Mockaton.js CHANGED
@@ -9,15 +9,18 @@ import { dispatchStatic } from './StaticDispatcher.js'
9
9
  import * as staticCollection from './staticCollection.js'
10
10
  import * as mockBrokerCollection from './mockBrokersCollection.js'
11
11
  import { setCorsHeaders, isPreflight } from './utils/http-cors.js'
12
- import { watchMocksDir, watchStaticDir } from './Watcher.js'
13
12
  import { apiPatchRequests, apiGetRequests } from './Api.js'
14
13
  import { BodyReaderError, hasControlChars } from './utils/http-request.js'
15
14
  import {
16
15
  setHeaders, sendNoContent, sendInternalServerError,
17
16
  sendUnprocessable, sendTooLongURI, sendBadRequest
18
17
  } from './utils/http-response.js'
18
+ import { watchDevSPA } from './WatcherDev.js'
19
+ import { watchMocksDir, watchStaticDir } from './Watcher.js'
19
20
 
20
21
 
22
+ const DEV = process.env.NODE_ENV === 'development'
23
+
21
24
  export function Mockaton(options) {
22
25
  return new Promise((resolve, reject) => {
23
26
  setup(options)
@@ -29,6 +32,8 @@ export function Mockaton(options) {
29
32
  watchMocksDir()
30
33
  watchStaticDir()
31
34
  }
35
+ if (DEV && config.hotReload)
36
+ watchDevSPA()
32
37
 
33
38
  const server = createServer(onRequest)
34
39
  server.on('error', reject)
@@ -45,7 +50,7 @@ export function Mockaton(options) {
45
50
 
46
51
  async function onRequest(req, response) {
47
52
  response.on('error', logger.warn)
48
-
53
+
49
54
  setHeaders(response, ['Server', `Mockaton ${pkgJSON.version}`])
50
55
  setHeaders(response, config.extraHeaders)
51
56
 
package/src/Watcher.js CHANGED
@@ -30,7 +30,7 @@ export const uiSyncVersion = new class extends EventEmitter {
30
30
  this.removeListener('ARR', listener)
31
31
  }
32
32
 
33
- #debounce(fn) {
33
+ #debounce(fn) { // TESTME
34
34
  let timer
35
35
  return () => {
36
36
  clearTimeout(timer)
@@ -45,7 +45,7 @@ export function watchMocksDir() {
45
45
  if (!file)
46
46
  return
47
47
 
48
- if (isDirectory(join(dir, file))) { // TESTME
48
+ if (isDirectory(join(dir, file))) {
49
49
  mockBrokerCollection.init()
50
50
  uiSyncVersion.increment()
51
51
  }
@@ -61,7 +61,7 @@ export function watchMocksDir() {
61
61
  })
62
62
  }
63
63
 
64
- export function watchStaticDir() { // TESTME
64
+ export function watchStaticDir() {
65
65
  const dir = config.staticDir
66
66
  if (!dir)
67
67
  return
@@ -0,0 +1,19 @@
1
+ import { watch } from 'node:fs'
2
+ import { EventEmitter } from 'node:events'
3
+ import { DASHBOARD_ASSETS } from './Api.js'
4
+
5
+
6
+ export const devWatcher = new class extends EventEmitter {
7
+ emit(file) { super.emit('RELOAD', file) }
8
+ subscribe(listener) { this.once('RELOAD', listener) }
9
+ unsubscribe(listener) { this.removeListener('RELOAD', listener) }
10
+ }
11
+
12
+ // DashboardHtml.js is not watched.
13
+ // It would need dynamic import + cache busting
14
+ export function watchDevSPA() {
15
+ watch('src', (_, file) => {
16
+ if (DASHBOARD_ASSETS.includes(file))
17
+ devWatcher.emit(file)
18
+ })
19
+ }
package/src/cli.js CHANGED
@@ -53,7 +53,7 @@ Options:
53
53
  -p, --port <port> (default: 0) which means auto-assigned
54
54
 
55
55
  -q, --quiet Errors only
56
- --no-open Don’t open dashboard in a browser (noops onReady callback)
56
+ --no-open Don’t open dashboard in a browser
57
57
 
58
58
  -h, --help Show this help
59
59
  -v, --version Show version
package/src/config.js CHANGED
@@ -50,7 +50,9 @@ const schema = {
50
50
  [/\.(js|ts)$/, jsToJsonPlugin]
51
51
  ], Array.isArray],
52
52
 
53
- onReady: [await openInBrowser, is(Function)]
53
+ onReady: [await openInBrowser, is(Function)],
54
+
55
+ hotReload: [false, is(Boolean)]
54
56
  }
55
57
 
56
58
 
@@ -68,17 +70,17 @@ export const config = Object.seal(defaults)
68
70
  export const ConfigValidator = Object.freeze(validators)
69
71
 
70
72
 
71
- /** @param {Partial<Config>} options */
72
- export function setup(options) {
73
- if (options.mocksDir)
74
- options.mocksDir = resolve(options.mocksDir)
73
+ /** @param {Partial<Config>} opts */
74
+ export function setup(opts) {
75
+ if (opts.mocksDir)
76
+ opts.mocksDir = resolve(opts.mocksDir)
75
77
 
76
- if (options.staticDir)
77
- options.staticDir = resolve(options.staticDir)
78
+ if (opts.staticDir)
79
+ opts.staticDir = resolve(opts.staticDir)
78
80
  else if (!isDirectory(defaults.staticDir))
79
- options.staticDir = ''
81
+ opts.staticDir = ''
80
82
 
81
- Object.assign(config, options)
83
+ Object.assign(config, opts)
82
84
  validate(config, ConfigValidator)
83
85
  logger.setLevel(config.logLevel)
84
86
  }
package/Makefile DELETED
@@ -1,53 +0,0 @@
1
- docker: docker-build docker-run
2
-
3
- docker-build:
4
- @docker build --no-cache --tag mockaton $(PWD)
5
-
6
- docker-run: docker-stop
7
- @docker run --name mockaton \
8
- --publish 127.0.0.1:2020:2020 \
9
- --volume $(PWD)/mockaton.config.js:/app/mockaton.config.js \
10
- --volume $(PWD)/mockaton-mocks:/app/mockaton-mocks \
11
- --volume $(PWD)/mockaton-static-mocks:/app/mockaton-static-mocks \
12
- mockaton
13
-
14
- docker-stop:
15
- @docker stop mockaton >/dev/null 2>&1 || true
16
- @docker rm mockaton >/dev/null 2>&1 || true
17
-
18
-
19
- start:
20
- @node src/cli.js
21
-
22
- watch:
23
- @node --watch src/cli.js
24
-
25
-
26
- test:
27
- @MOCKATON_WATCHER_DEBOUNCE_MS=0 node --test 'src/**/*.test.js'
28
-
29
- test-docker:
30
- @docker run --rm --interactive --tty \
31
- --volume $(PWD):/app \
32
- --workdir /app \
33
- node:24 \
34
- make test
35
-
36
- coverage:
37
- @MOCKATON_WATCHER_DEBOUNCE_MS=0 node --test --experimental-test-coverage \
38
- --test-reporter=spec --test-reporter-destination=stdout \
39
- --test-reporter=lcov --test-reporter-destination=lcov.info \
40
- 'src/**/*.test.js'
41
-
42
- pixaton:
43
- @node --test --experimental-test-isolation=none \
44
- --import=./pixaton-tests/_setup.js \
45
- 'pixaton-tests/**/*.test.js'
46
-
47
-
48
- outdated:
49
- @npm outdated --parseable |\
50
- awk -F: '{ printf "npm i %-30s ;# %s\n", $$4, $$2 }'
51
-
52
-
53
- .PHONY: *