mockaton 5.0.3 → 6.0.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
@@ -48,10 +48,10 @@ interface Config {
48
48
  host?: string, // defaults to 'localhost'
49
49
  port?: number // defaults to 0, which means auto-assigned
50
50
  delay?: number // defaults to 1200 (ms)
51
- onReady?: (dashboardUrl: string) => void // defaults to openInBrowser. pass a noop to prevent opening the dashboard
51
+ onReady?: (dashboardUrl: string) => void // defaults to trying to open macOS default browser. pass a noop to prevent opening the dashboard
52
52
  cookies?: object
53
53
  proxyFallback?: string // e.g. http://localhost:9999 Target for relaying routes without mocks
54
- allowedExt?: RegExp // /\.(md|json|txt|js)$/ Just for excluding temporary editor files (e.g. JetBrains appends a ~)
54
+ allowedExt?: RegExp // /\.(json|js|txt)$/ Just for excluding temporary editor files (e.g. JetBrains appends a ~)
55
55
  extraHeaders?: []
56
56
  }
57
57
  ```
@@ -149,18 +149,20 @@ permitted](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file)
149
149
  but since that’s part of the query string, it’s ignored anyway.
150
150
 
151
151
 
152
-
153
152
  ### Default (index-like) route
154
- For the default route of a directory, omit the mock filename name
155
- (<b>just use the extension</b>). For example, the following files will be
156
- routed to `api/foo` because comments and the query string are ignored.
153
+ **Option A.** Place it outside the directory:
154
+ ```
155
+ api/foo/
156
+ api/foo.GET.200.json
157
+ ```
158
+
159
+ **Option B.** Omit the filename:
157
160
  ```text
158
161
  api/foo/.GET.200.json
159
- api/foo/?bar=[bar].GET.200.json
160
- api/foo/(my comment).GET.200.json
161
162
  ```
162
163
 
163
164
 
165
+
164
166
  ## `Config.cookies`
165
167
  The selected cookie is sent in every response in the `Set-Cookie` header.
166
168
 
@@ -197,15 +199,6 @@ Config.extraHeaders = [
197
199
  ]
198
200
  ```
199
201
 
200
- ## Documenting Contracts (.md)
201
- This is handy for documenting request payload parameters. The
202
- dashboard prints the Markdown document as plain text (I know, I know).
203
-
204
- ```text
205
- api/foo/[user-id].POST.md
206
- api/foo/[user-id].POST.201.json
207
- ```
208
-
209
202
  ---
210
203
 
211
204
  ## API
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": "5.0.3",
5
+ "version": "6.0.0",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "license": "MIT",
@@ -0,0 +1 @@
1
+ "This mock is for /api/user"
package/src/Config.js CHANGED
@@ -12,7 +12,7 @@ export const Config = {
12
12
  cookies: {}, // defaults to the first kv
13
13
  onReady: openInBrowser,
14
14
  proxyFallback: '', // e.g. http://localhost:9999
15
- allowedExt: /\.(md|json|txt|js)$/, // Just for excluding temporary editor files (e.g. JetBrains appends a ~)
15
+ allowedExt: /\.(json|js|txt)$/, // Just for excluding temporary editor files (e.g. JetBrains appends a ~)
16
16
  extraHeaders: []
17
17
  }
18
18
 
package/src/Dashboard.css CHANGED
@@ -107,6 +107,10 @@ menu {
107
107
  top: 0;
108
108
  width: 50%;
109
109
  margin-left: 16px;
110
+
111
+ h2 {
112
+ padding-top: 20px;
113
+ }
110
114
 
111
115
  pre {
112
116
  tab-size: 2;
@@ -119,10 +123,6 @@ menu {
119
123
  background: var(--colorLightGrey);
120
124
  font-family: monospace;
121
125
  }
122
-
123
- &.Documentation {
124
- margin-bottom: 12px;
125
- }
126
126
  }
127
127
  }
128
128
 
package/src/Dashboard.js CHANGED
@@ -19,7 +19,6 @@ const Strings = {
19
19
  const CSS = {
20
20
  DelayToggler: 'DelayToggler',
21
21
  InternalServerErrorToggler: 'InternalServerErrorToggler',
22
- Documentation: 'Documentation',
23
22
  MockSelector: 'MockSelector',
24
23
  PayloadViewer: 'PayloadViewer',
25
24
  PreviewLink: 'PreviewLink',
@@ -30,7 +29,6 @@ const CSS = {
30
29
  }
31
30
 
32
31
  const r = createElement
33
- const refDocumentation = useRef()
34
32
  const refPayloadViewer = useRef()
35
33
  const refPayloadFile = useRef()
36
34
 
@@ -64,7 +62,6 @@ function DevPanel(brokersByMethod, cookies, comments) {
64
62
  r('table', null, Object.entries(brokersByMethod).map(([method, brokers]) =>
65
63
  r(SectionByMethod, { method, brokers }))),
66
64
  r('div', { className: CSS.PayloadViewer },
67
- r('pre', { ref: refDocumentation, className: CSS.Documentation }),
68
65
  r('h2', { ref: refPayloadFile }, Strings.mock),
69
66
  r('pre', { ref: refPayloadViewer }, Strings.click_link_to_preview)))))
70
67
  }
@@ -134,14 +131,14 @@ function SectionByMethod({ method, brokers }) {
134
131
  .filter(([, broker]) => broker.mocks.length > 1) // Excludes Markdown only routes (>1 because of the autogen500)
135
132
  .map(([urlMask, broker]) =>
136
133
  r('tr', null,
137
- r('td', null, r(PreviewLink, { method, urlMask, documentation: broker.documentation })),
134
+ r('td', null, r(PreviewLink, { method, urlMask })),
138
135
  r('td', null, r(MockSelector, { broker })),
139
136
  r('td', null, r(DelayToggler, { broker })),
140
137
  r('td', null, r(InternalServerErrorToggler, { broker }))
141
138
  ))))
142
139
  }
143
140
 
144
- function PreviewLink({ method, urlMask, documentation }) {
141
+ function PreviewLink({ method, urlMask }) {
145
142
  return (
146
143
  r('a', {
147
144
  className: CSS.PreviewLink,
@@ -150,13 +147,6 @@ function PreviewLink({ method, urlMask, documentation }) {
150
147
  async onClick(event) {
151
148
  event.preventDefault()
152
149
  try {
153
- if (documentation) {
154
- const r = await fetch(documentation)
155
- refDocumentation.current.innerText = await r.text()
156
- }
157
- else
158
- refDocumentation.current.innerText = ''
159
-
160
150
  const spinner = setTimeout(() => refPayloadViewer.current.innerText = Strings.fetching, 180)
161
151
  const res = await fetch(this.href, {
162
152
  method: this.getAttribute('data-method')
package/src/MockBroker.js CHANGED
@@ -5,19 +5,15 @@ import { isDirectory } from './utils/fs.js'
5
5
  import { DEFAULT_500_COMMENT } from './ApiConstants.js'
6
6
 
7
7
 
8
- // MockBroker is a state for a particular route. It knows the available
9
- // mock files that can be served for the route, the currently selected
10
- // file, and its delay. Also, knows if the route has documentation (md)
8
+ // MockBroker is a state for a particular route. It knows the available mock files
9
+ // that can be served for the route, the currently selected file, and its delay.
11
10
  export class MockBroker {
12
11
  #route
13
12
 
14
13
  constructor(file) {
15
14
  this.#route = new Route(file)
16
15
  this.method = this.#route.method
17
-
18
- this.documentation = '' // .md
19
-
20
- this.mocks = [] // *.json,txt,js
16
+ this.mocks = []
21
17
  this.currentMock = {
22
18
  file: '',
23
19
  delay: 0
@@ -27,13 +23,9 @@ export class MockBroker {
27
23
  }
28
24
 
29
25
  register(file) {
30
- if (file.endsWith('.md'))
31
- this.documentation = file
32
- else {
33
- if (!this.mocks.length)
34
- this.currentMock.file = file // The first mock file option for a particular route becomes the default
35
- this.mocks.push(file)
36
- }
26
+ if (!this.mocks.length)
27
+ this.currentMock.file = file // The first mock file option for a particular route becomes the default
28
+ this.mocks.push(file)
37
29
  }
38
30
 
39
31
  urlMaskMatches(url) { return this.#route.urlMaskMatches(url) }
@@ -77,7 +69,7 @@ export class MockBroker {
77
69
  }
78
70
 
79
71
  #registerTemp500() {
80
- const { urlMask, method } = Route.parseFilename(this.mocks[0] || this.documentation)
72
+ const { urlMask, method } = Route.parseFilename(this.mocks[0])
81
73
  let mask = urlMask
82
74
  if (isDirectory(join(Config.mocksDir, urlMask)))
83
75
  mask = urlMask + '/'
@@ -7,16 +7,10 @@ import { Config } from './Config.js'
7
7
  import { mimeFor } from './utils/mime.js'
8
8
  import * as mockBrokerCollection from './mockBrokersCollection.js'
9
9
  import { JsonBodyParserError } from './utils/http-request.js'
10
- import { sendInternalServerError, sendNotFound, sendFile, sendBadRequest } from './utils/http-response.js'
10
+ import { sendInternalServerError, sendNotFound, sendBadRequest } from './utils/http-response.js'
11
11
 
12
12
 
13
13
  export async function dispatchMock(req, response) {
14
- /* Serve Documentation */
15
- if (req.method === 'GET' && req.url.endsWith('.md')) {
16
- sendFile(response, join(Config.mocksDir, decodeURIComponent(req.url)))
17
- return
18
- }
19
-
20
14
  const broker = mockBrokerCollection.getBrokerForUrl(req.method, req.url)
21
15
  if (!broker) {
22
16
  if (Config.proxyFallback)
package/src/Route.js CHANGED
@@ -44,43 +44,22 @@ export class Route {
44
44
 
45
45
  static parseFilename(file) {
46
46
  const tokens = file.replace(Route.reComments, '').split('.')
47
- return file.endsWith('.md')
48
- ? parseDocumentation(tokens)
49
- : parseMock(tokens)
50
- }
51
- }
52
-
53
- function parseDocumentation(tokens) { // TESTME
54
- if (tokens.length < 3)
55
- return { error: 'Invalid Documentation Filename Convention' }
56
-
57
- const method = tokens.at(-2)
58
- if (!httpMethods.includes(method))
59
- return { error: `Unrecognized HTTP Method: "${method}"` }
60
-
61
- return {
62
- urlMask: '/' + removeTrailingSlash(tokens.at(-3)),
63
- method,
64
- status: 200
65
- }
66
- }
67
-
68
- function parseMock(tokens) {
69
- if (tokens.length < 4)
70
- return { error: 'Invalid Filename Convention' }
71
-
72
- const status = Number(tokens.at(-2))
73
- if (!responseStatusIsValid(status))
74
- return { error: `Invalid HTTP Response Status: "${status}"` }
75
-
76
- const method = tokens.at(-3)
77
- if (!httpMethods.includes(method))
78
- return { error: `Unrecognized HTTP Method: "${method}"` }
79
-
80
- return {
81
- urlMask: '/' + removeTrailingSlash(tokens.at(-4)),
82
- method,
83
- status
47
+ if (tokens.length < 4)
48
+ return { error: 'Invalid Filename Convention' }
49
+
50
+ const status = Number(tokens.at(-2))
51
+ if (!responseStatusIsValid(status))
52
+ return { error: `Invalid HTTP Response Status: "${status}"` }
53
+
54
+ const method = tokens.at(-3)
55
+ if (!httpMethods.includes(method))
56
+ return { error: `Unrecognized HTTP Method: "${method}"` }
57
+
58
+ return {
59
+ urlMask: '/' + removeTrailingSlash(tokens.at(-4)),
60
+ method,
61
+ status
62
+ }
84
63
  }
85
64
  }
86
65
 
@@ -1 +0,0 @@
1
- "This is an index-like route (i.e. /api/user). This file has no name, only the extension convention is needed for the index path."
@@ -1,9 +0,0 @@
1
- # Request Body
2
-
3
- ```json
4
- {
5
- "new_name": "John"
6
- }
7
- ```
8
-
9
- This is just documentation. In this example, for the request body payload.