mockaton 0.9.0 → 0.9.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/.editorconfig ADDED
@@ -0,0 +1,8 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ indent_size = 2
7
+ indent_style = tab
8
+ insert_final_newline = true
package/ApiConstants.js CHANGED
@@ -14,7 +14,6 @@ export const DF = { // Dashboard Fields (XHR)
14
14
  comment: 'comment',
15
15
  delayed: 'delayed',
16
16
  file: 'file',
17
- isAdmin: 'is_admin',
18
17
  currentCookieKey: 'current_cookie_key',
19
18
  isForDashboard: 'mock_request_payload',
20
19
  method: 'method',
package/Dashboard.html CHANGED
@@ -1,10 +1,10 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en-US">
3
3
  <head>
4
- <link rel="stylesheet" href="../Dashboard.css">
5
- <link rel="icon" href="data:">
6
- <meta name="viewport" content="width=device-width, initial-scale=1">
7
- <title>Mock Server</title>
4
+ <link rel="stylesheet" href="../Dashboard.css">
5
+ <link rel="icon" href="data:">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1">
7
+ <title>Mock Server</title>
8
8
  </head>
9
9
  <body>
10
10
  <script src="../Dashboard.js" type="module"></script>
package/MockBroker.js CHANGED
@@ -89,7 +89,7 @@ export class MockBroker {
89
89
  }
90
90
 
91
91
  #has501() {
92
- return this.mocks.some(mock =>
92
+ return this.mocks.some(mock =>
93
93
  Route.parseFilename(mock).status === 501)
94
94
  }
95
95
 
package/Mockaton.js CHANGED
@@ -17,13 +17,13 @@ export function Mockaton(options) {
17
17
  const { url, method } = req
18
18
  if (method === 'GET' && apiGetRequests.has(url))
19
19
  apiGetRequests.get(url)(req, response)
20
-
20
+
21
21
  else if (method === 'PATCH' && apiPatchRequests.has(url))
22
22
  await apiPatchRequests.get(url)(req, response)
23
-
23
+
24
24
  else if (isStatic(req))
25
25
  await dispatchStatic(req, response)
26
-
26
+
27
27
  else
28
28
  await dispatchMock(req, response)
29
29
  })
package/README.md CHANGED
@@ -10,17 +10,22 @@ api/user/
10
10
  api/user/[user-id].GET.200.json
11
11
  ```
12
12
 
13
+ By the way, this [browser
14
+ extension](https://github.com/ericfortis/devtools-ext-tar-http-requests) can
15
+ be used for downloading a tar of your XHR requests following that convention.
16
+
17
+
13
18
  ### Mock Variants
14
- Each route can have different mocks and those variants could either be:
15
- - a different response status code, (e.g. 200, 401),
16
- - or a comment on the filename, which is anything within parentheses.
17
-
18
- The variants can be manually selected via the dashboard
19
- UI, or programmatically for instance for setting up tests.
19
+ Each route can have different mocks and those variants could either be:
20
+ - a different response status code, (e.g. 200, 401), or
21
+ - a comment on the filename, which is anything within parentheses.
22
+
23
+ Those variants can be manually selected in the dashboard
24
+ UI, or programmatically, for instance, for setting up tests.
20
25
 
21
26
 
22
27
  ## Getting Started
23
- The best way to learn mockaton is by checking out this repo and
28
+ The best way to learn _Mockaton_ is by checking out this repo and
24
29
  exploring its [sample-mocks/](./sample-mocks) directory. Then run
25
30
  [`./_usage_example.js`](./_usage_example.js) and you’ll see this dashboard:
26
31
 
@@ -29,12 +34,12 @@ exploring its [sample-mocks/](./sample-mocks) directory. Then run
29
34
 
30
35
  ### Mock Variants of Status Code
31
36
  The **sample-mocks/** directory has three mock alternatives for serving
32
- `/api/user/friends`.
33
- - with an HTTP status of _200 - OK_,
34
- - another one with _204 - No Content_ of an empty list of friends, and
37
+ `/api/user/friends`:
38
+ - an HTTP status of _200 - OK_,
39
+ - another one with _204 - No Content_ of an empty list of friends, and
35
40
  - a _501 - Internal Server Error_
36
- - By the way, 501 mocks get autogenerated for routes that have no 501’s.
37
-
41
+ - 501 mocks get autogenerated for routes that have no 501’s.
42
+
38
43
  ![](./README-dashboard-dropdown.png)
39
44
 
40
45
  ### Mock Variants with Comments
@@ -45,19 +50,20 @@ Comments are anything within parentheses, including them.
45
50
 
46
51
  ## Delay
47
52
  The clock icon next to the mock selector dropdown is a checkbox for delaying a
48
- particular response. They are handy for testing spinners when developing UIs. By the
49
- way, the milliseconds for the delay is globally configurable via `Config.delay`.
53
+ particular response. They are handy for testing spinners when developing UIs.
54
+
55
+ The milliseconds for the delay is globally configurable via `Config.delay = 1200`
50
56
 
51
57
  ---
52
58
 
53
59
  ## Basic Usage (see [_usage_example.js](./_usage_example.js))
54
60
  ```
55
- npm install @ericfortis/mockaton
61
+ npm install mockaton
56
62
  ```
57
63
  Create a `my-mockaton.js` file
58
64
  ```js
59
65
  import { resolve } from 'node:path'
60
- import { Mockaton } from '@ericfortis/mockaton'
66
+ import { Mockaton } from 'mockaton'
61
67
 
62
68
  Mockaton({ // Config options
63
69
  port: 2345,
@@ -69,19 +75,49 @@ Mockaton({ // Config options
69
75
  node my-mockaton.js
70
76
  ```
71
77
 
78
+ ## Config Options
79
+ ```ts
80
+ interface Config {
81
+ mocksDir: string
82
+ staticDir?: string
83
+ host?: string,
84
+ port?: number
85
+
86
+ cookies?(): object
87
+
88
+ skipOpen?: boolean
89
+ allowedExt?: RegExp
90
+ delayMilliseconds?: number
91
+ database?: object
92
+ }
93
+ ```
94
+
95
+ ## Cookies
96
+ ```js
97
+ import { jwtCookie } from 'mockaton'
98
+
99
+ Config.cookies = {
100
+ 'My Admin User': 'my-cookie=1;Path=/;SameSite=strict',
101
+ 'My Normal User': 'my-cookie=0;Path=/;SameSite=strict',
102
+ 'My JWT': jwtCookie('my-cookie', { foo: 'bar' })
103
+ }
104
+ ```
105
+
106
+ That `jwtCookie` has a hardcoded header and signature. In other
107
+ words, it’s useful iff you care about its payload in frontend.
108
+
72
109
  ---
73
110
 
74
111
  ## File Name Convention
75
112
 
76
113
 
77
-
78
114
  ### Extension
79
115
  `.Method.HttpResponseStatusCode.FileExt`
80
116
 
81
117
  The **file extension** can anything, but `.md` and `.mjs` are reserved
82
118
  for documentation, and mock processors (more on that later).
83
119
 
84
- By the way, the `Config.allowedExt` regex defaults to: `/\.(json|txt|md|mjs)$/`
120
+ The `Config.allowedExt` regex defaults to: `/\.(json|txt|md|mjs)$/`
85
121
 
86
122
 
87
123
  ### Dynamic Parameters
@@ -121,31 +157,6 @@ api/foo/(my comment).GET.200.json
121
157
 
122
158
  ---
123
159
 
124
- ## Config Options
125
- ```ts
126
- interface Config {
127
- mocksDir: string
128
- staticDir?: string
129
- host?: string,
130
- port?: number
131
-
132
- cookies?(): object
133
-
134
- skipOpen?: boolean
135
- allowedExt?: RegExp
136
- delayMilliseconds?: number
137
- database?: object
138
- }
139
- ```
140
- ---
141
-
142
- ## Cookies
143
- ```
144
- Config.cookies = {
145
- 'My Admin User': 'my-cookie=1;Path=/;SameSite=strict',
146
- 'My Normal User': 'my-cookie=0;Path=/;SameSite=strict'
147
- }
148
- ```
149
160
 
150
161
  ---
151
162
  ## Mock Precedence
@@ -197,7 +208,23 @@ other words, only one transform per route is supported in demo mode.
197
208
 
198
209
  ---
199
210
 
200
- ## Bulk Selecting Mocks by Matching comments
211
+ ## API
212
+
213
+ ### Changing a mock for one route
214
+ ```
215
+ PATCH http://localhost:2345/mockaton/edit
216
+ {
217
+ "file": "api/foo.200.GET.json"
218
+ "delayed": true // optional
219
+ }
220
+ ```
221
+
222
+ ### Bulk Selecting Mocks by Matching comments
223
+ ```
224
+ PATCH http://localhost:2345/mockaton/bulk-select
225
+ { "comment": "demo-a" }
226
+ ```
227
+
201
228
  Many mocks can be changed at once. We do that by searching the
202
229
  comments on the filename. For example, `api/foo(demo-a).GET.200.json`
203
230
 
@@ -209,3 +236,4 @@ Similarly, if there’s no demo mock at all for
209
236
  a route, the first dev mock (a-z) will be served.
210
237
 
211
238
 
239
+
package/Route.js CHANGED
@@ -44,19 +44,19 @@ export class Route {
44
44
 
45
45
  static parseFilename(file) {
46
46
  const tokens = file.replace(Route.reComments, '').split('.')
47
-
47
+
48
48
  let error = ''
49
49
  if (tokens.length < 4)
50
50
  error = 'Invalid Filename Convention'
51
-
51
+
52
52
  const method = tokens.at(-3)
53
53
  if (!httpMethods.includes(method))
54
54
  error = `Unrecognized HTTP Method: "${method}"`
55
-
55
+
56
56
  const status = Number(tokens.at(-2))
57
57
  if (!responseStatusIsValid(status))
58
58
  error = `Invalid HTTP Response Status: "${status}"`
59
-
59
+
60
60
  return {
61
61
  error,
62
62
  urlMask: '/' + removeTrailingSlash(tokens.at(-4)),
@@ -84,7 +84,7 @@ function removeTrailingSlash(url = '') {
84
84
  }
85
85
 
86
86
  function responseStatusIsValid(status) {
87
- return Number.isInteger(status)
88
- && status >= 100
87
+ return Number.isInteger(status)
88
+ && status >= 100
89
89
  && status <= 599
90
- }
90
+ }
package/_usage_example.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { resolve } from 'node:path'
4
- import { Mockaton } from './index.js' // from 'mockaton'
4
+ import { Mockaton, jwtCookie } from './index.js' // from 'mockaton'
5
5
 
6
6
  Mockaton({
7
7
  port: 2345,
@@ -11,4 +11,4 @@ Mockaton({
11
11
  'Admin User': 'my-cookie=1;Path=/;SameSite=strict',
12
12
  'Normal User': 'my-cookie=0;Path=/;SameSite=strict'
13
13
  }
14
- })
14
+ })
package/index.d.ts CHANGED
@@ -1,15 +1,17 @@
1
1
  import { Server } from 'node:http';
2
2
 
3
3
  interface Config {
4
- mocksDir: string
5
- staticDir?: string
6
- host?: string,
7
- port?: number
8
- delay?: number
9
- cookies?(): object
10
- database?: object
11
- skipOpen?: boolean
12
- allowedExt?: RegExp
4
+ mocksDir: string
5
+ staticDir?: string
6
+ host?: string,
7
+ port?: number
8
+ delay?: number
9
+
10
+ cookies?(): object
11
+
12
+ database?: object
13
+ skipOpen?: boolean
14
+ allowedExt?: RegExp
13
15
  }
14
16
 
15
17
  export function Mockaton(options: Config): Server
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
- "name": "mockaton",
3
- "description": "A deterministic server-side for developing frontend clients",
4
- "type": "module",
5
- "version": "0.9.0",
6
- "main": "index.js",
7
- "types": "index.d.ts",
8
- "license": "MIT",
9
- "repository": "https://github.com/ericfortis/mockaton",
10
- "scripts": {
11
- "test": "./Tests.js",
12
- "demo": "_usage_example.js"
13
- }
2
+ "name": "mockaton",
3
+ "description": "A deterministic server-side for developing and testing frontend clients",
4
+ "type": "module",
5
+ "version": "0.9.2",
6
+ "main": "index.js",
7
+ "types": "index.d.ts",
8
+ "license": "MIT",
9
+ "repository": "https://github.com/ericfortis/mockaton",
10
+ "scripts": {
11
+ "test": "./Tests.js",
12
+ "demo": "_usage_example.js"
13
+ }
14
14
  }
@@ -1 +1,3 @@
1
- { "renamed": "OK" }
1
+ {
2
+ "renamed": "OK"
3
+ }
@@ -1,4 +1,4 @@
1
1
  {
2
- "_": "An example response of a user without friends. Uses HTTP Status: 204 - No Content",
3
- "friends": []
4
- }
2
+ "_": "An example response of a user without friends. Uses HTTP Status: 204 - No Content",
3
+ "friends": []
4
+ }
@@ -1,13 +1,13 @@
1
1
  {
2
- "_": "This file has a comment: `(assorted)`. i.e. the route is /api/user/videos",
3
- "videos": [
4
- {
5
- "url": "https://example.com/1",
6
- "verified": true
7
- },
8
- {
9
- "url": "https://example.com/2",
10
- "verified": false
11
- }
12
- ]
13
- }
2
+ "_": "This file has a comment: `(assorted)`. i.e. the route is /api/user/videos",
3
+ "videos": [
4
+ {
5
+ "url": "https://example.com/1",
6
+ "verified": true
7
+ },
8
+ {
9
+ "url": "https://example.com/2",
10
+ "verified": false
11
+ }
12
+ ]
13
+ }
@@ -1,13 +1,13 @@
1
1
  {
2
- "_": "This file has a comment: `(entirely unverified)`. i.e. the route is /api/user/videos",
3
- "videos": [
4
- {
5
- "url": "https://example.com/1",
6
- "verified": false
7
- },
8
- {
9
- "url": "https://example.com/2",
10
- "verified": false
11
- }
12
- ]
13
- }
2
+ "_": "This file has a comment: `(entirely unverified)`. i.e. the route is /api/user/videos",
3
+ "videos": [
4
+ {
5
+ "url": "https://example.com/1",
6
+ "verified": false
7
+ },
8
+ {
9
+ "url": "https://example.com/2",
10
+ "verified": false
11
+ }
12
+ ]
13
+ }
@@ -1,13 +1,13 @@
1
1
  {
2
- "_": "This file has two comments: `(entirely verified)` and `(another comment)`. i.e. the route is /api/user/videos",
3
- "videos": [
4
- {
5
- "url": "https://example.com/1",
6
- "verified": true
7
- },
8
- {
9
- "url": "https://example.com/2",
10
- "verified": true
11
- }
12
- ]
13
- }
2
+ "_": "This file has two comments: `(entirely verified)` and `(another comment)`. i.e. the route is /api/user/videos",
3
+ "videos": [
4
+ {
5
+ "url": "https://example.com/1",
6
+ "verified": true
7
+ },
8
+ {
9
+ "url": "https://example.com/2",
10
+ "verified": true
11
+ }
12
+ ]
13
+ }
@@ -1,4 +1,4 @@
1
1
  {
2
- "_": "This route has a dynamic param `<id>`. i.e. /api/video/123",
3
- "url": "https://example.com/123"
4
- }
2
+ "_": "This route has a dynamic param `<id>`. i.e. /api/video/123",
3
+ "url": "https://example.com/123"
4
+ }
@@ -1,11 +1,11 @@
1
1
  {
2
- "_": "This file has query string params, but they are fully ignored. i.e. /api/video/list and /api/video/list?page_num=1 would match as well",
3
- "videos": [
4
- {
5
- "url": "https://example.com/1"
6
- },
7
- {
8
- "url": "https://example.com/2"
9
- }
10
- ]
11
- }
2
+ "_": "This file has query string params, but they are fully ignored. i.e. /api/video/list and /api/video/list?page_num=1 would match as well",
3
+ "videos": [
4
+ {
5
+ "url": "https://example.com/1"
6
+ },
7
+ {
8
+ "url": "https://example.com/2"
9
+ }
10
+ ]
11
+ }
@@ -1,4 +1,4 @@
1
1
  {
2
- "_": "Example filename with a query string. BTW, it doesn't work on Windows, because '?' is an illegal character. At any rate, the full query string is ignored.",
3
- "data": []
4
- }
2
+ "_": "Example filename with a query string. BTW, it doesn't work on Windows, because '?' is an illegal character. At any rate, the full query string is ignored.",
3
+ "data": []
4
+ }
@@ -1,3 +1,3 @@
1
1
  {
2
- "created": "OK"
3
- }
2
+ "created": "OK"
3
+ }
package/utils/jwt.js CHANGED
@@ -1,21 +1,21 @@
1
1
  export function jwtCookie(cookieName, payload) {
2
- return [
3
- `${cookieName}=${jwt(payload)}`,
4
- 'Path=/',
5
- 'SameSite=strict'
6
- ].join(';')
2
+ return [
3
+ `${cookieName}=${jwt(payload)}`,
4
+ 'Path=/',
5
+ 'SameSite=strict'
6
+ ].join(';')
7
7
  }
8
8
 
9
9
  function jwt(payload) {
10
- return [
11
- 'Header_Not_In_Use',
12
- toBase64Url(payload),
13
- 'Signature_Not_In_Use'
14
- ].join('.')
10
+ return [
11
+ 'Header_Not_In_Use',
12
+ toBase64Url(payload),
13
+ 'Signature_Not_In_Use'
14
+ ].join('.')
15
15
  }
16
16
 
17
17
  function toBase64Url(obj) {
18
- return btoa(JSON.stringify(obj))
19
- .replace('+', '-')
20
- .replace('/', '_')
18
+ return btoa(JSON.stringify(obj))
19
+ .replace('+', '-')
20
+ .replace('/', '_')
21
21
  }