mockaton 13.9.2 → 13.9.4
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 +4 -4
- package/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/client/ApiCommander.js +0 -6
- package/src/client/ApiConstants.js +0 -1
- package/src/client/app.css +8 -7
- package/src/server/Api.js +4 -9
- package/src/server/Mockaton.js +5 -2
- package/src/server/Mockaton.test.js +1 -1
- package/src/server/config.js +2 -1
- package/src/server/resolverBypassImportCache.js +19 -0
- package/src/server/{importResolver.js → resolverResolveExtensionless.js} +2 -17
- package/src/server/utils/HttpServerResponse.js +1 -1
- package/src/server/utils/fs.js +2 -2
- package/src/server/utils/fs.test.js +31 -0
package/README.md
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|

|
|
3
3
|
[](https://github.com/ericfortis/mockaton/actions/workflows/test.yml)
|
|
4
4
|
[](https://codecov.io/github/ericfortis/mockaton)
|
|
5
|
-
[](https://opensource.org/licenses/MIT)
|
|
6
5
|
|
|
7
6
|
## [Docs ↗](https://mockaton.com) | [Changelog ↗](https://mockaton.com/changelog) | [Skills](skills/mockaton/SKILL.md)
|
|
8
7
|
|
|
@@ -38,9 +37,10 @@ Dashboard: [localhost:2020/mockaton](http://localhost:2020/mockaton)
|
|
|
38
37
|
npx mockaton --port 2020 my-mocks-dir/
|
|
39
38
|
```
|
|
40
39
|
|
|
41
|
-
Mockaton will serve the files on the given directory. It's a file-system
|
|
42
|
-
|
|
43
|
-
Also, each route can have different mock
|
|
40
|
+
Mockaton will serve the files on the given directory. It's a file-system based router, so filenames can have dynamic
|
|
41
|
+
parameters.
|
|
42
|
+
Also, filenames can have comments, which are anything within parentheses, this way each route can have different mock
|
|
43
|
+
file variants.
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
| Route | Filename | Description |
|
package/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -17,15 +17,10 @@ export class Commander {
|
|
|
17
17
|
reset = () => this.#patch(API.reset)
|
|
18
18
|
|
|
19
19
|
setGlobalDelay = delay => this.#patch(API.globalDelay, delay)
|
|
20
|
-
|
|
21
20
|
setGlobalDelayJitter = jitterPct => this.#patch(API.globalDelayJitter, jitterPct)
|
|
22
|
-
|
|
23
21
|
setCorsAllowed = value => this.#patch(API.cors, value)
|
|
24
|
-
|
|
25
22
|
setWatchMocks = enabled => this.#patch(API.watchMocks, enabled)
|
|
26
|
-
|
|
27
23
|
setProxyFallback = proxyAddr => this.#patch(API.fallback, proxyAddr)
|
|
28
|
-
|
|
29
24
|
setCollectProxied = shouldCollect => this.#patch(API.collectProxied, shouldCollect)
|
|
30
25
|
|
|
31
26
|
/** @returns {JsonPromise<State.cookies>} */
|
|
@@ -50,7 +45,6 @@ export class Commander {
|
|
|
50
45
|
|
|
51
46
|
|
|
52
47
|
writeMock = (file, content) => this.#patch(API.writeMock, [file, content])
|
|
53
|
-
|
|
54
48
|
deleteMock = file => this.#patch(API.deleteMock, file)
|
|
55
49
|
|
|
56
50
|
|
package/src/client/app.css
CHANGED
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
|
|
28
28
|
html,
|
|
29
29
|
body {
|
|
30
|
-
overflow: hidden;
|
|
31
30
|
height: 100%;
|
|
32
31
|
font-size: 12px;
|
|
33
32
|
}
|
|
@@ -45,7 +44,7 @@ body {
|
|
|
45
44
|
border: 0;
|
|
46
45
|
margin: 0;
|
|
47
46
|
letter-spacing: -0.374px;
|
|
48
|
-
line-height:
|
|
47
|
+
line-height: 14px;
|
|
49
48
|
font-family: inherit;
|
|
50
49
|
font-size: 100%;
|
|
51
50
|
scrollbar-width: thin;
|
|
@@ -185,13 +184,13 @@ header {
|
|
|
185
184
|
}
|
|
186
185
|
|
|
187
186
|
.HelpLink {
|
|
188
|
-
opacity: 0.8;
|
|
189
187
|
width: 22px;
|
|
190
188
|
height: 22px;
|
|
191
189
|
flex-shrink: 0;
|
|
192
190
|
align-self: end;
|
|
193
191
|
margin-bottom: 3px;
|
|
194
192
|
margin-left: auto;
|
|
193
|
+
opacity: 0.8;
|
|
195
194
|
border-radius: 50%;
|
|
196
195
|
fill: var(--colorBgHeader);
|
|
197
196
|
background: var(--colorLabel);
|
|
@@ -342,6 +341,7 @@ main {
|
|
|
342
341
|
}
|
|
343
342
|
|
|
344
343
|
.leftSide {
|
|
344
|
+
overflow: hidden;
|
|
345
345
|
width: 50%;
|
|
346
346
|
border-top: 1px solid var(--colorBorder);
|
|
347
347
|
border-right: 1px solid var(--colorBorder);
|
|
@@ -349,6 +349,7 @@ main {
|
|
|
349
349
|
|
|
350
350
|
.rightSide {
|
|
351
351
|
position: relative;
|
|
352
|
+
overflow: hidden;
|
|
352
353
|
min-width: 100px;
|
|
353
354
|
min-height: 0;
|
|
354
355
|
flex: 1;
|
|
@@ -399,8 +400,7 @@ main {
|
|
|
399
400
|
background: var(--colorBgHeader);
|
|
400
401
|
}
|
|
401
402
|
|
|
402
|
-
.GroupByMethod
|
|
403
|
-
.ViewSourceCheckbox {
|
|
403
|
+
.GroupByMethod {
|
|
404
404
|
display: flex;
|
|
405
405
|
align-items: center;
|
|
406
406
|
gap: 6px;
|
|
@@ -426,7 +426,7 @@ main {
|
|
|
426
426
|
height: 100%;
|
|
427
427
|
padding: 16px;
|
|
428
428
|
padding-bottom: 64px;
|
|
429
|
-
padding-left:
|
|
429
|
+
padding-left: 15px;
|
|
430
430
|
user-select: none;
|
|
431
431
|
overflow-y: auto;
|
|
432
432
|
|
|
@@ -482,7 +482,8 @@ main {
|
|
|
482
482
|
cursor: grabbing;
|
|
483
483
|
}
|
|
484
484
|
|
|
485
|
-
&::-webkit-details-marker
|
|
485
|
+
&::-webkit-details-marker,
|
|
486
|
+
&::marker {
|
|
486
487
|
display: none;
|
|
487
488
|
}
|
|
488
489
|
|
package/src/server/Api.js
CHANGED
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { join } from 'node:path'
|
|
7
|
-
import {
|
|
8
|
-
import { write, rm, isFile, resolveIn } from './utils/fs.js'
|
|
7
|
+
import { write, rm, isFile, resolveIn, listFilesRecursively } from './utils/fs.js'
|
|
9
8
|
|
|
10
9
|
import openapi from '../../www/src/assets/openapi.json' with { type: 'json' }
|
|
11
10
|
import pkgJSON from '../../package.json' with { type: 'json' }
|
|
@@ -22,12 +21,11 @@ import * as mockBrokersCollection from './mockBrokersCollection.js'
|
|
|
22
21
|
|
|
23
22
|
|
|
24
23
|
export const CLIENT_DIR = join(import.meta.dirname, '../client')
|
|
25
|
-
const DASHBOARD_ASSETS = readdirSync(CLIENT_DIR, { recursive: true })
|
|
26
|
-
|
|
27
24
|
|
|
28
25
|
export const apiGetReqs = new Map([
|
|
29
26
|
[API.dashboard, serveDashboard],
|
|
30
|
-
...
|
|
27
|
+
...listFilesRecursively(CLIENT_DIR).map(f =>
|
|
28
|
+
[`${API.dashboard}/${f}`, serveStatic(f)]),
|
|
31
29
|
|
|
32
30
|
[API.state, getState],
|
|
33
31
|
[API.syncVersion, sseClientSyncVersion],
|
|
@@ -38,7 +36,6 @@ export const apiGetReqs = new Map([
|
|
|
38
36
|
])
|
|
39
37
|
|
|
40
38
|
|
|
41
|
-
|
|
42
39
|
export const apiPatchReqs = new Map([
|
|
43
40
|
[API.cors, setCorsAllowed],
|
|
44
41
|
[API.reset, reset],
|
|
@@ -69,9 +66,7 @@ function serveDashboard(_, response) {
|
|
|
69
66
|
}
|
|
70
67
|
|
|
71
68
|
function serveStatic(f) {
|
|
72
|
-
return (_, response) => {
|
|
73
|
-
response.file(join(CLIENT_DIR, f))
|
|
74
|
-
}
|
|
69
|
+
return (_, response) => { response.file(join(CLIENT_DIR, f)) }
|
|
75
70
|
}
|
|
76
71
|
|
|
77
72
|
function getState(_, response) {
|
package/src/server/Mockaton.js
CHANGED
|
@@ -25,9 +25,12 @@ export function Mockaton(options) {
|
|
|
25
25
|
setup(options)
|
|
26
26
|
cookie.init(config.cookies)
|
|
27
27
|
mockBrokerCollection.init()
|
|
28
|
-
register('./importResolver.js', import.meta.url)
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
register('./resolverResolveExtensionless.js', import.meta.url)
|
|
30
|
+
if (config.bypassImportCache)
|
|
31
|
+
register('./resolverBypassImportCache.js', import.meta.url)
|
|
32
|
+
|
|
33
|
+
if (config.watcherEnabled)
|
|
31
34
|
watchMocksDir()
|
|
32
35
|
|
|
33
36
|
if (config.hotReload)
|
|
@@ -1047,7 +1047,7 @@ describe('Write and Delete Mock', () => {
|
|
|
1047
1047
|
})
|
|
1048
1048
|
|
|
1049
1049
|
|
|
1050
|
-
describe('import
|
|
1050
|
+
describe('import resolvers', () => {
|
|
1051
1051
|
test('resolves extensionless ts', async () => {
|
|
1052
1052
|
await api.writeMock('_scores.ts', 'export default [1,2,3]')
|
|
1053
1053
|
await api.writeMock('user-scores.GET.200.ts',
|
package/src/server/config.js
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { resolve as _resolve } from 'node:path'
|
|
2
|
+
|
|
3
|
+
const mockatonSrcRoot = `file://${_resolve(import.meta.dirname, '..')}`
|
|
4
|
+
|
|
5
|
+
// We register this hook at runtime so it doesn’t interfere with non-dynamic imports.
|
|
6
|
+
// Cache bust by appending timestamp query param
|
|
7
|
+
export async function resolve(specifier, context, nextResolve) {
|
|
8
|
+
const result = await nextResolve(specifier, context)
|
|
9
|
+
if (result.url?.startsWith('file://') && !result.url.startsWith(mockatonSrcRoot)) {
|
|
10
|
+
const url = new URL(result.url)
|
|
11
|
+
url.searchParams.set('t', performance.now())
|
|
12
|
+
return {
|
|
13
|
+
...result,
|
|
14
|
+
url: url.href,
|
|
15
|
+
shortCircuit: true
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return result
|
|
19
|
+
}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
|
-
import {
|
|
2
|
+
import { join, dirname } from 'node:path'
|
|
3
3
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
4
4
|
|
|
5
|
-
const mockatonSrcRoot = `file://${_resolve(import.meta.dirname, '..')}`
|
|
6
5
|
|
|
7
|
-
// We register this hook at runtime so it doesn’t interfere with non-dynamic imports.
|
|
8
6
|
export async function resolve(specifier, context, nextResolve) {
|
|
9
|
-
let result
|
|
10
7
|
try {
|
|
11
|
-
|
|
8
|
+
return await nextResolve(specifier, context)
|
|
12
9
|
}
|
|
13
10
|
catch (error) {
|
|
14
11
|
// Attempt to resolve imports as .ts and .js
|
|
@@ -20,16 +17,4 @@ export async function resolve(specifier, context, nextResolve) {
|
|
|
20
17
|
}
|
|
21
18
|
throw error
|
|
22
19
|
}
|
|
23
|
-
|
|
24
|
-
// Cache bust by appending timestamp query param
|
|
25
|
-
if (result.url?.startsWith('file://') && !result.url.startsWith(mockatonSrcRoot)) {
|
|
26
|
-
const url = new URL(result.url)
|
|
27
|
-
url.searchParams.set('t', performance.now())
|
|
28
|
-
return {
|
|
29
|
-
...result,
|
|
30
|
-
url: url.href,
|
|
31
|
-
shortCircuit: true
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return result
|
|
35
20
|
}
|
package/src/server/utils/fs.js
CHANGED
|
@@ -34,8 +34,8 @@ export async function rm(path) {
|
|
|
34
34
|
export async function resolveIn(baseDir, file) {
|
|
35
35
|
try {
|
|
36
36
|
const parent = await realpath(baseDir)
|
|
37
|
-
const child = resolve(parent, file)
|
|
38
|
-
return child.startsWith(parent
|
|
37
|
+
const child = resolve(join(parent, file))
|
|
38
|
+
return child.startsWith(join(parent, sep))
|
|
39
39
|
? child
|
|
40
40
|
: null
|
|
41
41
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { join } from 'node:path'
|
|
2
|
+
import { equal } from 'node:assert/strict'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
4
|
+
import { after, describe, test } from 'node:test'
|
|
5
|
+
import { mkdtempSync, rmSync, realpathSync } from 'node:fs'
|
|
6
|
+
|
|
7
|
+
import { resolveIn } from './fs.js'
|
|
8
|
+
|
|
9
|
+
const isNull = v => equal(v, null)
|
|
10
|
+
|
|
11
|
+
describe('resolveIn', () => {
|
|
12
|
+
const baseDir = mkdtempSync(join(tmpdir(), '_resolveIn'))
|
|
13
|
+
const baseParentDir = join(baseDir, '..')
|
|
14
|
+
after(() => rmSync(baseDir, { recursive: true, force: true }))
|
|
15
|
+
|
|
16
|
+
test('null when baseDir does not exist', async () =>
|
|
17
|
+
isNull(await resolveIn(join(baseParentDir, 'missing'), 'file.json')))
|
|
18
|
+
|
|
19
|
+
test('null when relative path escapes baseDir', async () =>
|
|
20
|
+
isNull(await resolveIn(baseDir, '../outside.json')))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
const realBaseDir = realpathSync(baseDir)
|
|
24
|
+
const onReal = f => join(realBaseDir, f)
|
|
25
|
+
|
|
26
|
+
test('resolves a relative file within baseDir', async () =>
|
|
27
|
+
equal(await resolveIn(baseDir, 'file.json'), onReal('file.json')))
|
|
28
|
+
|
|
29
|
+
test('resolves file starting with /', async () =>
|
|
30
|
+
equal(await resolveIn(baseDir, '/file.json'), onReal('file.json')))
|
|
31
|
+
})
|