mockaton 13.3.0 → 13.3.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/package.json +1 -1
- package/src/client/app-store.js +1 -2
- package/src/client/app.css +32 -14
- package/src/client/app.js +10 -9
- package/src/server/Api.js +1 -0
- package/src/server/MockBroker.js +3 -3
- package/src/server/Mockaton.test.js +24 -5
- package/src/server/mockBrokersCollection.js +19 -13
package/package.json
CHANGED
package/src/client/app-store.js
CHANGED
|
@@ -108,7 +108,6 @@ export const store = {
|
|
|
108
108
|
},
|
|
109
109
|
|
|
110
110
|
setProxyFallback(value) {
|
|
111
|
-
store.skipNextRender = true
|
|
112
111
|
store._request(() => api.setProxyFallback(value), () => {
|
|
113
112
|
store.proxyFallback = value
|
|
114
113
|
})
|
|
@@ -175,7 +174,7 @@ export const store = {
|
|
|
175
174
|
arr.push(...Object.values(brokers))
|
|
176
175
|
return arr
|
|
177
176
|
},
|
|
178
|
-
|
|
177
|
+
|
|
179
178
|
|
|
180
179
|
previewLink(method, urlMask) {
|
|
181
180
|
store.setChosenLink(method, urlMask)
|
package/src/client/app.css
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
--colorText: light-dark(#000, #fff);
|
|
14
14
|
|
|
15
15
|
--colorAccent: light-dark(#0059dd, #2495ff);
|
|
16
|
-
--colorHover: light-dark(#
|
|
16
|
+
--colorHover: light-dark(#c1e2ff, #062d59);
|
|
17
17
|
|
|
18
18
|
--colorRed: light-dark(#da0f00, #f41606);
|
|
19
19
|
--colorPink: light-dark(#ed206a, #f92672);
|
|
@@ -50,6 +50,11 @@ body {
|
|
|
50
50
|
corner-shape: squircle;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
label,
|
|
54
|
+
button {
|
|
55
|
+
user-select: none;
|
|
56
|
+
}
|
|
57
|
+
|
|
53
58
|
a:focus-visible,
|
|
54
59
|
input:focus-visible,
|
|
55
60
|
select:focus-visible,
|
|
@@ -432,7 +437,7 @@ main {
|
|
|
432
437
|
}
|
|
433
438
|
|
|
434
439
|
&.canProxy {
|
|
435
|
-
margin-left:
|
|
440
|
+
margin-left: 124px;
|
|
436
441
|
}
|
|
437
442
|
}
|
|
438
443
|
|
|
@@ -449,6 +454,7 @@ main {
|
|
|
449
454
|
|
|
450
455
|
.FolderGroup {
|
|
451
456
|
position: relative;
|
|
457
|
+
border-radius: var(--radius);
|
|
452
458
|
|
|
453
459
|
> summary {
|
|
454
460
|
left: 0;
|
|
@@ -465,7 +471,6 @@ main {
|
|
|
465
471
|
text-overflow: ellipsis;
|
|
466
472
|
border-radius: var(--radius);
|
|
467
473
|
|
|
468
|
-
|
|
469
474
|
&:active {
|
|
470
475
|
cursor: grabbing;
|
|
471
476
|
}
|
|
@@ -475,13 +480,20 @@ main {
|
|
|
475
480
|
}
|
|
476
481
|
|
|
477
482
|
&:hover {
|
|
478
|
-
|
|
483
|
+
background: var(--colorHover);
|
|
479
484
|
}
|
|
480
485
|
|
|
481
486
|
.FolderName {
|
|
482
487
|
margin-left: 125px;
|
|
488
|
+
&.canProxy {
|
|
489
|
+
margin-left: 155px;
|
|
490
|
+
}
|
|
491
|
+
|
|
483
492
|
&.groupedByMethod {
|
|
484
493
|
margin-left: 79px;
|
|
494
|
+
&.canProxy {
|
|
495
|
+
margin-left: 109px;
|
|
496
|
+
}
|
|
485
497
|
}
|
|
486
498
|
}
|
|
487
499
|
|
|
@@ -503,17 +515,23 @@ main {
|
|
|
503
515
|
}
|
|
504
516
|
}
|
|
505
517
|
|
|
506
|
-
&[open]
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
left: 0;
|
|
510
|
-
width: 16px;
|
|
511
|
-
|
|
512
|
-
.FolderChevron {
|
|
513
|
-
transform: rotate(0deg);
|
|
518
|
+
&[open] {
|
|
519
|
+
&:has(summary:hover) {
|
|
520
|
+
background: linear-gradient(90deg, var(--colorHover), var(--colorBg));
|
|
514
521
|
}
|
|
515
|
-
|
|
516
|
-
|
|
522
|
+
|
|
523
|
+
> summary {
|
|
524
|
+
position: absolute;
|
|
525
|
+
top: 0;
|
|
526
|
+
left: 0;
|
|
527
|
+
width: 16px;
|
|
528
|
+
|
|
529
|
+
.FolderChevron {
|
|
530
|
+
transform: rotate(0deg);
|
|
531
|
+
}
|
|
532
|
+
.FolderName {
|
|
533
|
+
display: none;
|
|
534
|
+
}
|
|
517
535
|
}
|
|
518
536
|
}
|
|
519
537
|
}
|
package/src/client/app.js
CHANGED
|
@@ -106,24 +106,25 @@ function MockList() {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
function FolderGroups(groups) {
|
|
109
|
-
return groups.map(({ folder, children }) =>
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return r('details', {
|
|
109
|
+
return groups.map(({ folder, children }) => children.length === 1
|
|
110
|
+
? Row(children[0], 0)
|
|
111
|
+
: r('details', {
|
|
114
112
|
className: CSS.FolderGroup,
|
|
115
113
|
open: !store.collapsedFolders.has(folder),
|
|
116
114
|
onToggle() {
|
|
117
|
-
// TODO alt+click exclusive open
|
|
118
115
|
store.setFolderCollapsed(folder, !this.open)
|
|
119
116
|
}
|
|
120
117
|
},
|
|
121
118
|
r('summary', null,
|
|
122
119
|
r('span', { className: CSS.FolderChevron }, ChevronDownIcon()),
|
|
123
|
-
r('span', {
|
|
120
|
+
r('span', {
|
|
121
|
+
className: classNames(
|
|
122
|
+
CSS.FolderName,
|
|
123
|
+
store.groupByMethod && CSS.groupedByMethod,
|
|
124
|
+
store.canProxy && CSS.canProxy)
|
|
125
|
+
},
|
|
124
126
|
folder + '…')),
|
|
125
|
-
children.map(Row))
|
|
126
|
-
})
|
|
127
|
+
children.map(Row)))
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
/**
|
package/src/server/Api.js
CHANGED
package/src/server/MockBroker.js
CHANGED
|
@@ -36,10 +36,10 @@ export class MockBroker {
|
|
|
36
36
|
|
|
37
37
|
unregister(file) {
|
|
38
38
|
this.mocks = this.mocks.filter(f => f !== file)
|
|
39
|
-
const
|
|
40
|
-
if (!
|
|
39
|
+
const brokerIsEmpty = !this.mocks.length
|
|
40
|
+
if (!brokerIsEmpty && this.file === file)
|
|
41
41
|
this.selectDefaultFile()
|
|
42
|
-
return
|
|
42
|
+
return brokerIsEmpty
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
hasMock = file => this.mocks.includes(file)
|
|
@@ -7,7 +7,7 @@ import { mkdtempSync } from 'node:fs'
|
|
|
7
7
|
import { randomUUID } from 'node:crypto'
|
|
8
8
|
import { equal, deepEqual, match } from 'node:assert/strict'
|
|
9
9
|
import { describe, test, before, beforeEach, after } from 'node:test'
|
|
10
|
-
import { unlink, mkdir, readFile, rename, readdir, writeFile } from 'node:fs/promises'
|
|
10
|
+
import { unlink, mkdir, readFile, rename, readdir, writeFile, rm } from 'node:fs/promises'
|
|
11
11
|
|
|
12
12
|
import { mimeFor } from './utils/mime.js'
|
|
13
13
|
import { parseFilename } from '../client/Filename.js'
|
|
@@ -26,8 +26,15 @@ const proc = spawn(join(import.meta.dirname, 'cli.js'), [
|
|
|
26
26
|
'--no-open'
|
|
27
27
|
])
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
proc.
|
|
29
|
+
const DEBUG = false
|
|
30
|
+
proc.stdout.on('data', data => {
|
|
31
|
+
stdout.push(data.toString())
|
|
32
|
+
DEBUG && process.stdout.write(stdout.at(-1))
|
|
33
|
+
})
|
|
34
|
+
proc.stderr.on('data', data => {
|
|
35
|
+
stderr.push(data.toString())
|
|
36
|
+
DEBUG && process.stderr.write(stdout.at(-1))
|
|
37
|
+
})
|
|
31
38
|
|
|
32
39
|
const serverAddr = await new Promise((resolve, reject) => {
|
|
33
40
|
proc.stdout.once('data', () => {
|
|
@@ -41,12 +48,14 @@ after(() => proc.kill('SIGUSR2'))
|
|
|
41
48
|
|
|
42
49
|
|
|
43
50
|
const rmFromMocksDir = f => unlink(join(mocksDir, f))
|
|
44
|
-
const listFromMocksDir = d => readdir(join(mocksDir, d))
|
|
45
51
|
const readFromMocksDir = f => readFile(join(mocksDir, f), 'utf8')
|
|
46
52
|
const writeInMocksDir = (f, data) => writeFile(join(mocksDir, f), data)
|
|
47
|
-
const makeDirInMocks = dir => mkdir(join(mocksDir, dir), { recursive: true })
|
|
48
53
|
const renameInMocksDir = (src, target) => rename(join(mocksDir, src), join(mocksDir, target))
|
|
49
54
|
|
|
55
|
+
const listFromMocksDir = d => readdir(join(mocksDir, d))
|
|
56
|
+
const rmDirFromMocks = d => rm(join(mocksDir, d), { recursive: true })
|
|
57
|
+
const makeDirInMocks = dir => mkdir(join(mocksDir, dir), { recursive: true })
|
|
58
|
+
|
|
50
59
|
|
|
51
60
|
const api = new Commander(serverAddr)
|
|
52
61
|
|
|
@@ -1120,6 +1129,16 @@ describe('Registering Mocks', () => {
|
|
|
1120
1129
|
equal(s.brokersByMethod.GET['/reg1/runtime0'].file, 'reg1/runtime0.GET.200.txt')
|
|
1121
1130
|
})
|
|
1122
1131
|
})
|
|
1132
|
+
|
|
1133
|
+
test('deleting a folder unregisters mocks in it', async () => {
|
|
1134
|
+
const fx = new Fixture('api/bulk-delete/bar.GET.200.json')
|
|
1135
|
+
await fx.write()
|
|
1136
|
+
await sleep(0)
|
|
1137
|
+
const nextVerPromise = resolveOnNextSyncVersion()
|
|
1138
|
+
await rmDirFromMocks('api/bulk-delete')
|
|
1139
|
+
await nextVerPromise
|
|
1140
|
+
equal(await fx.fetchBroker(), undefined)
|
|
1141
|
+
})
|
|
1123
1142
|
})
|
|
1124
1143
|
|
|
1125
1144
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { basename } from 'node:path'
|
|
2
2
|
|
|
3
|
-
import { cookie } from './cookie.js'
|
|
4
3
|
import { MockBroker } from './MockBroker.js'
|
|
5
4
|
import { parseFilename } from '../client/Filename.js'
|
|
6
5
|
import { listFilesRecursively } from './utils/fs.js'
|
|
@@ -28,26 +27,22 @@ export const all = () => collection
|
|
|
28
27
|
|
|
29
28
|
export function init() {
|
|
30
29
|
collection = {}
|
|
31
|
-
cookie.init(config.cookies)
|
|
32
|
-
|
|
33
30
|
listFilesRecursively(config.mocksDir)
|
|
34
31
|
.sort()
|
|
35
32
|
.forEach(f => registerMock(f))
|
|
36
|
-
|
|
37
33
|
forEachBroker(b => b.selectDefaultFile())
|
|
38
34
|
}
|
|
39
35
|
|
|
40
36
|
/** @returns {boolean} registered */
|
|
41
37
|
export function registerMock(file, isFromWatcher = false) {
|
|
42
|
-
if (brokerByFilename(file)?.hasMock(file)
|
|
43
|
-
|
|
38
|
+
if (brokerByFilename(file)?.hasMock(file) ||
|
|
39
|
+
!isFileAllowed(basename(file)))
|
|
44
40
|
return false
|
|
45
41
|
|
|
46
42
|
const { method, urlMask } = parseFilename(file)
|
|
47
43
|
collection[method] ??= {}
|
|
48
44
|
|
|
49
45
|
let broker = collection[method][urlMask]
|
|
50
|
-
|
|
51
46
|
if (!broker)
|
|
52
47
|
broker = collection[method][urlMask] = new MockBroker(file)
|
|
53
48
|
else
|
|
@@ -61,15 +56,26 @@ export function registerMock(file, isFromWatcher = false) {
|
|
|
61
56
|
|
|
62
57
|
export function unregisterMock(file) {
|
|
63
58
|
const broker = brokerByFilename(file)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
59
|
+
if (broker) {
|
|
60
|
+
const brokerIsEmpty = broker.unregister(file)
|
|
61
|
+
if (brokerIsEmpty) {
|
|
62
|
+
const { method, urlMask } = parseFilename(file)
|
|
63
|
+
delete collection[method][urlMask]
|
|
64
|
+
if (!Object.keys(collection[method]).length)
|
|
65
|
+
delete collection[method]
|
|
66
|
+
}
|
|
70
67
|
}
|
|
68
|
+
else for (const f of filesInDir(file)) // maybe it was a dir
|
|
69
|
+
unregisterMock(f)
|
|
71
70
|
}
|
|
72
71
|
|
|
72
|
+
function filesInDir(dir) {
|
|
73
|
+
const files = []
|
|
74
|
+
forEachBroker(b => {
|
|
75
|
+
files.push(...(b.mocks.filter(m => m.startsWith(dir + '/'))))
|
|
76
|
+
})
|
|
77
|
+
return files
|
|
78
|
+
}
|
|
73
79
|
|
|
74
80
|
/** @returns {MockBroker | undefined} */
|
|
75
81
|
export function brokerByFilename(file) {
|