mockaton 1.1.0 → 2.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-dashboard.png +0 -0
- package/README.md +10 -23
- package/Tests.js +16 -23
- package/package.json +1 -1
- package/sample-mocks/api/user/loves.GET.200.js +7 -0
- package/src/Api.js +0 -14
- package/src/ApiConstants.js +1 -3
- package/src/Config.js +1 -1
- package/src/Dashboard.css +0 -6
- package/src/Dashboard.js +4 -53
- package/src/MockBroker.js +5 -20
- package/src/MockDispatcher.js +12 -22
- package/sample-mocks/api/video/list(concat newly uploaded).GET.200.mjs +0 -8
- package/sample-mocks/api/video/list.GET.200.json +0 -11
- package/sample-mocks/api/video/upload(insert newly uploaded).POST.201.mjs +0 -10
- package/sample-mocks/api/video/upload.POST.201.json +0 -3
- package/sample-mocks/api/video/upload.POST.500.txt +0 -0
- /package/sample-mocks/api/{video/list.GET.500.txt → user/loves.GET.500.txt} +0 -0
package/README-dashboard.png
CHANGED
|
Binary file
|
package/README.md
CHANGED
|
@@ -36,6 +36,15 @@ export default [
|
|
|
36
36
|
]
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
Or, export default a function. There, you
|
|
40
|
+
can override the response status and the default JSON content
|
|
41
|
+
type. But don’t call `response.end()`, just return a string.
|
|
42
|
+
```js
|
|
43
|
+
export default function (req, response) {
|
|
44
|
+
return JSON.stringify({ a: 1 })
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
39
48
|
|
|
40
49
|
### Proxying Routes
|
|
41
50
|
`Config.proxyFallback` lets you specify a target
|
|
@@ -86,10 +95,9 @@ interface Config {
|
|
|
86
95
|
port?: number // defaults to 0, which means auto-assigned
|
|
87
96
|
delay?: number // defaults to 1200 (ms)
|
|
88
97
|
cookies?: object
|
|
89
|
-
database?: object // for "Transforms"
|
|
90
98
|
skipOpen?: boolean // Prevents opening the dashboard in a browser
|
|
91
99
|
proxyFallback?: string // e.g. http://localhost:9999 Target for relaying routes without mocks
|
|
92
|
-
allowedExt?: RegExp // /\.(json|txt|md|js
|
|
100
|
+
allowedExt?: RegExp // /\.(json|txt|md|js)$/ Just for excluding temporary editor files (e.g. JetBrains appends a ~)
|
|
93
101
|
}
|
|
94
102
|
```
|
|
95
103
|
|
|
@@ -175,19 +183,6 @@ api/foo/[user-id].POST.201.md
|
|
|
175
183
|
api/foo/[user-id].POST.201.json
|
|
176
184
|
```
|
|
177
185
|
|
|
178
|
-
## Transforms (.mjs)
|
|
179
|
-
Using the same filename convention, files ending
|
|
180
|
-
with `.mjs` will process the mock before serving it.
|
|
181
|
-
|
|
182
|
-
For example, this handler will capitalize the mock body and increment a counter.
|
|
183
|
-
```js
|
|
184
|
-
export default function capitalizeAllText(mockAsText, requestBody, config) {
|
|
185
|
-
config.database.myCount ??= 0
|
|
186
|
-
config.database.myCount++
|
|
187
|
-
return mockAsText.toUpperCase()
|
|
188
|
-
}
|
|
189
|
-
```
|
|
190
|
-
|
|
191
186
|
|
|
192
187
|
## API
|
|
193
188
|
|
|
@@ -234,14 +229,6 @@ Sends a list of the available cookies along with a flag indicated if it’s the
|
|
|
234
229
|
fetch(addr + '/mockaton/cookies')
|
|
235
230
|
```
|
|
236
231
|
|
|
237
|
-
### Select a Transform
|
|
238
|
-
```js
|
|
239
|
-
fetch(addr + '/mockaton/transform', {
|
|
240
|
-
method: 'PATCH',
|
|
241
|
-
body: JSON.stringify('api/video/list(concat newly uploaded).GET.200.mjs')
|
|
242
|
-
})
|
|
243
|
-
```
|
|
244
|
-
|
|
245
232
|
### Update Fallback Proxy
|
|
246
233
|
```js
|
|
247
234
|
fetch(addr + '/mockaton/fallback', {
|
package/Tests.js
CHANGED
|
@@ -121,8 +121,6 @@ async function runTests() {
|
|
|
121
121
|
for (const [url, file, body] of fixtures)
|
|
122
122
|
await testMockDispatching(url, file, body)
|
|
123
123
|
|
|
124
|
-
await testMockDispatching('/api/object', 'api/object.GET.200.js', { JSON_FROM_JS: true }, undefined, mimeFor('.json'))
|
|
125
|
-
|
|
126
124
|
await testItUpdatesDelayAndFile(
|
|
127
125
|
'/api/alternative',
|
|
128
126
|
'api/alternative(comment-2).GET.200.json',
|
|
@@ -159,9 +157,11 @@ async function runTests() {
|
|
|
159
157
|
await reset()
|
|
160
158
|
for (const [url, file, body] of fixtures)
|
|
161
159
|
await testMockDispatching(url, file, body)
|
|
160
|
+
|
|
161
|
+
await testMockDispatching('/api/object', 'api/object.GET.200.js', { JSON_FROM_JS: true }, mimeFor('.json'))
|
|
162
|
+
await testJsFunctionMocks()
|
|
162
163
|
|
|
163
164
|
await testItUpdatesUserRole()
|
|
164
|
-
await testTransforms()
|
|
165
165
|
await testStaticFileServing()
|
|
166
166
|
await testInvalidFilenamesAreIgnored()
|
|
167
167
|
await testEnableFallbackSoRoutesWithoutMocksGetRelayed()
|
|
@@ -190,11 +190,11 @@ async function test404() {
|
|
|
190
190
|
})
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
async function testMockDispatching(url, file, expectedBody,
|
|
193
|
+
async function testMockDispatching(url, file, expectedBody, forcedMime = void 0) {
|
|
194
194
|
const { urlMask, method, status } = Route.parseFilename(file)
|
|
195
195
|
const mime = forcedMime || mimeFor(file)
|
|
196
196
|
const now = new Date()
|
|
197
|
-
const res = await request(url, { method
|
|
197
|
+
const res = await request(url, { method })
|
|
198
198
|
const body = mime === 'application/json'
|
|
199
199
|
? await res.json()
|
|
200
200
|
: await res.text()
|
|
@@ -305,25 +305,18 @@ async function testItUpdatesUserRole() {
|
|
|
305
305
|
})
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
-
async function
|
|
309
|
-
await describe('
|
|
310
|
-
write('api/
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
body.push(reqBody[0]);
|
|
315
|
-
body.push(config.mocksDir);
|
|
316
|
-
return JSON.stringify(body);
|
|
308
|
+
async function testJsFunctionMocks() {
|
|
309
|
+
await describe('JS Function Mocks', async () => {
|
|
310
|
+
write('api/js-func.POST.200.js', `
|
|
311
|
+
export default function (req, response) {
|
|
312
|
+
response.setHeader('content-type', 'custom-mime')
|
|
313
|
+
return 'SOME_STRING'
|
|
317
314
|
}`)
|
|
318
|
-
await reset() // for registering the
|
|
319
|
-
await
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
await testMockDispatching('/api/transform',
|
|
324
|
-
'api/transform.POST.200.json',
|
|
325
|
-
['initial', 'another', tmpDir],
|
|
326
|
-
JSON.stringify(['another']))
|
|
315
|
+
await reset() // for registering the file
|
|
316
|
+
await testMockDispatching('/api/js-func',
|
|
317
|
+
'api/js-func.POST.200.js',
|
|
318
|
+
'SOME_STRING',
|
|
319
|
+
'custom-mime')
|
|
327
320
|
})
|
|
328
321
|
}
|
|
329
322
|
|
package/package.json
CHANGED
package/src/Api.js
CHANGED
|
@@ -28,7 +28,6 @@ export const apiPatchRequests = new Map([
|
|
|
28
28
|
[API.edit, updateBroker],
|
|
29
29
|
[API.reset, reinitialize],
|
|
30
30
|
[API.cookies, selectCookie],
|
|
31
|
-
[API.transform, updateBrokerTransform],
|
|
32
31
|
[API.fallback, updateProxyFallback]
|
|
33
32
|
])
|
|
34
33
|
|
|
@@ -92,19 +91,6 @@ async function bulkUpdateBrokersByCommentTag(req, response) {
|
|
|
92
91
|
}
|
|
93
92
|
}
|
|
94
93
|
|
|
95
|
-
async function updateBrokerTransform(req, response) {
|
|
96
|
-
try {
|
|
97
|
-
const file = await parseJSON(req)
|
|
98
|
-
const broker = mockBrokersCollection.getBrokerByFilename(file)
|
|
99
|
-
broker.updateTransform(file)
|
|
100
|
-
sendOK(response)
|
|
101
|
-
}
|
|
102
|
-
catch (error) {
|
|
103
|
-
console.error(error)
|
|
104
|
-
sendBadRequest(response)
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
94
|
async function updateProxyFallback(req, response) {
|
|
109
95
|
try {
|
|
110
96
|
Config.proxyFallback = await parseJSON(req)
|
package/src/ApiConstants.js
CHANGED
|
@@ -6,13 +6,11 @@ export const API = {
|
|
|
6
6
|
edit: MOUNT + '/edit',
|
|
7
7
|
mocks: MOUNT + '/mocks',
|
|
8
8
|
reset: MOUNT + '/reset',
|
|
9
|
-
transform: MOUNT + '/transform',
|
|
10
9
|
cookies: MOUNT + '/cookies',
|
|
11
10
|
fallback: MOUNT + '/fallback'
|
|
12
11
|
}
|
|
13
12
|
|
|
14
13
|
export const DF = { // Dashboard Fields (XHR)
|
|
15
14
|
delayed: 'delayed',
|
|
16
|
-
file: 'file'
|
|
17
|
-
isForDashboard: 'mock_request_payload'
|
|
15
|
+
file: 'file'
|
|
18
16
|
}
|
package/src/Config.js
CHANGED
|
@@ -12,7 +12,7 @@ export const Config = {
|
|
|
12
12
|
database: {},
|
|
13
13
|
skipOpen: false,
|
|
14
14
|
proxyFallback: '', // e.g. http://localhost:9999
|
|
15
|
-
allowedExt: /\.(json|txt|md|js
|
|
15
|
+
allowedExt: /\.(json|txt|md|js)$/ // Just for excluding temporary editor files (e.g. JetBrains appends a ~)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function setup(options) {
|
package/src/Dashboard.css
CHANGED
|
@@ -135,17 +135,11 @@ main {
|
|
|
135
135
|
.BulkSelectSection {
|
|
136
136
|
margin: 20px 0;
|
|
137
137
|
}
|
|
138
|
-
.TransformsSection {
|
|
139
|
-
padding-top: 30px;
|
|
140
|
-
border-top: 1px solid #ccc;
|
|
141
|
-
margin: 30px 0;
|
|
142
|
-
}
|
|
143
138
|
|
|
144
139
|
.BulkSelectSection select {
|
|
145
140
|
margin-top: 5px;
|
|
146
141
|
}
|
|
147
142
|
|
|
148
|
-
.TransformSelector,
|
|
149
143
|
.MockSelector {
|
|
150
144
|
width: 300px;
|
|
151
145
|
padding: 8px 1px;
|
package/src/Dashboard.js
CHANGED
|
@@ -10,11 +10,9 @@ const Strings = {
|
|
|
10
10
|
empty_response_body: '/* Empty Response Body */',
|
|
11
11
|
fetching: '⌚ Fetching…',
|
|
12
12
|
mock: 'Mock',
|
|
13
|
-
none: 'None',
|
|
14
13
|
reset: 'Reset',
|
|
15
14
|
select_one: 'Select One',
|
|
16
|
-
title: 'Mockaton'
|
|
17
|
-
transforms: 'Transforms'
|
|
15
|
+
title: 'Mockaton'
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
const CSS = {
|
|
@@ -26,8 +24,6 @@ const CSS = {
|
|
|
26
24
|
PayloadViewer: 'PayloadViewer',
|
|
27
25
|
PreviewLink: 'PreviewLink',
|
|
28
26
|
TitleWrap: 'TitleWrap',
|
|
29
|
-
TransformSelector: 'TransformSelector',
|
|
30
|
-
TransformsSection: 'TransformsSection',
|
|
31
27
|
|
|
32
28
|
bold: 'bold',
|
|
33
29
|
chosen: 'chosen',
|
|
@@ -74,10 +70,7 @@ function DevPanel(brokersByMethod, cookies, comments) {
|
|
|
74
70
|
r('div', { className: CSS.PayloadViewer },
|
|
75
71
|
r('pre', { ref: refDocumentation, className: CSS.Documentation }),
|
|
76
72
|
r('h2', { ref: refPayloadFile }, Strings.mock),
|
|
77
|
-
r('pre', { ref: refPayloadViewer }, Strings.click_link_to_preview)))
|
|
78
|
-
r('div', { className: CSS.TransformsSection },
|
|
79
|
-
r('h2', null, Strings.transforms),
|
|
80
|
-
r(Transforms, { brokersByMethod }))))
|
|
73
|
+
r('pre', { ref: refPayloadViewer }, Strings.click_link_to_preview)))))
|
|
81
74
|
}
|
|
82
75
|
|
|
83
76
|
|
|
@@ -142,7 +135,7 @@ function SectionByMethod({ method, brokers }) {
|
|
|
142
135
|
r('th', null, method),
|
|
143
136
|
Object.entries(brokers)
|
|
144
137
|
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
145
|
-
.filter(([, broker]) => broker.mocks.length) // handles Markdown doc
|
|
138
|
+
.filter(([, broker]) => broker.mocks.length) // handles Markdown doc
|
|
146
139
|
.map(([urlMask, broker]) =>
|
|
147
140
|
r('tr', null,
|
|
148
141
|
r('td', null, r(PreviewLink, { method, urlMask, documentation: broker.documentation })),
|
|
@@ -168,8 +161,7 @@ function PreviewLink({ method, urlMask, documentation }) {
|
|
|
168
161
|
|
|
169
162
|
const spinner = setTimeout(() => refPayloadViewer.current.innerText = Strings.fetching, 180)
|
|
170
163
|
const res = await fetch(this.href, {
|
|
171
|
-
method: this.getAttribute('data-method')
|
|
172
|
-
headers: { [DF.isForDashboard]: '1' }
|
|
164
|
+
method: this.getAttribute('data-method')
|
|
173
165
|
})
|
|
174
166
|
document.querySelector(`.${CSS.PreviewLink}.${CSS.chosen}`)?.classList.remove(CSS.chosen)
|
|
175
167
|
this.classList.add(CSS.chosen)
|
|
@@ -246,47 +238,6 @@ function TimerIcon() {
|
|
|
246
238
|
}
|
|
247
239
|
|
|
248
240
|
|
|
249
|
-
function Transforms({ brokersByMethod }) {
|
|
250
|
-
const brokersWithTransforms = []
|
|
251
|
-
for (const brokers of Object.values(brokersByMethod))
|
|
252
|
-
for (const [urlMask, broker] of Object.entries(brokers))
|
|
253
|
-
if (broker.transforms.length)
|
|
254
|
-
brokersWithTransforms.push([urlMask, broker])
|
|
255
|
-
return (
|
|
256
|
-
r('table', null, brokersWithTransforms.map(([urlMask, broker]) =>
|
|
257
|
-
r('tr', null,
|
|
258
|
-
r('td', null, r(PreviewLink, { method: broker.method, urlMask })),
|
|
259
|
-
r('td', null, r(TransformSelector, {
|
|
260
|
-
items: ['', ...broker.transforms],
|
|
261
|
-
selected: broker.currentTransform
|
|
262
|
-
})))
|
|
263
|
-
)))
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
function TransformSelector({ items, selected }) {
|
|
267
|
-
const className = defaultIsSelected => cssClass(
|
|
268
|
-
CSS.TransformSelector,
|
|
269
|
-
!defaultIsSelected && CSS.bold)
|
|
270
|
-
return (
|
|
271
|
-
r('select', {
|
|
272
|
-
className: className(selected === items[0]),
|
|
273
|
-
autocomplete: 'off',
|
|
274
|
-
onChange() {
|
|
275
|
-
fetch(API.transform, {
|
|
276
|
-
method: 'PATCH',
|
|
277
|
-
body: JSON.stringify(this.value)
|
|
278
|
-
}).then(() => {
|
|
279
|
-
this.closest('tr').querySelector('a').click()
|
|
280
|
-
this.className = className(this.value === this.options[0].value)
|
|
281
|
-
})
|
|
282
|
-
}
|
|
283
|
-
}, items.map(item =>
|
|
284
|
-
r('option', {
|
|
285
|
-
value: item,
|
|
286
|
-
selected: item === selected
|
|
287
|
-
}, item || Strings.none))))
|
|
288
|
-
}
|
|
289
|
-
|
|
290
241
|
|
|
291
242
|
/* === Utils === */
|
|
292
243
|
function cssClass(...args) {
|
package/src/MockBroker.js
CHANGED
|
@@ -5,9 +5,9 @@ import { Route } from './Route.js'
|
|
|
5
5
|
import { Config } from './Config.js'
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
// MockBroker is a state for a particular route. It knows the available
|
|
9
|
-
// that can be served for the route, the currently selected
|
|
10
|
-
// knows if the route has
|
|
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).
|
|
11
11
|
export class MockBroker {
|
|
12
12
|
#route
|
|
13
13
|
|
|
@@ -17,23 +17,18 @@ export class MockBroker {
|
|
|
17
17
|
|
|
18
18
|
this.documentation = '' // .md
|
|
19
19
|
|
|
20
|
-
this.mocks = [] // *.json,txt
|
|
20
|
+
this.mocks = [] // *.json,txt,js
|
|
21
21
|
this.currentMock = {
|
|
22
22
|
file: '',
|
|
23
23
|
delay: 0
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
this.transforms = [] // *.mjs
|
|
27
|
-
this.currentTransform = ''
|
|
28
|
-
|
|
29
26
|
this.register(file)
|
|
30
27
|
}
|
|
31
28
|
|
|
32
29
|
register(file) {
|
|
33
30
|
if (file.endsWith('.md'))
|
|
34
31
|
this.documentation = file
|
|
35
|
-
else if (file.endsWith('.mjs'))
|
|
36
|
-
this.transforms.push(file)
|
|
37
32
|
else {
|
|
38
33
|
if (!this.mocks.length)
|
|
39
34
|
this.currentMock.file = file // The first mock file option for a particular route becomes the default
|
|
@@ -55,26 +50,17 @@ export class MockBroker {
|
|
|
55
50
|
this.currentMock.delay = Number(delayed) * Config.delay
|
|
56
51
|
}
|
|
57
52
|
|
|
58
|
-
updateTransform(filename) {
|
|
59
|
-
this.currentTransform = filename
|
|
60
|
-
}
|
|
61
|
-
|
|
62
53
|
setByMatchingComment(comment) {
|
|
63
54
|
for (const file of this.mocks)
|
|
64
55
|
if (Route.hasInParentheses(file, comment)) {
|
|
65
56
|
this.updateFile(file)
|
|
66
57
|
break
|
|
67
58
|
}
|
|
68
|
-
for (const file of this.transforms)
|
|
69
|
-
if (Route.hasInParentheses(file, comment)) {
|
|
70
|
-
this.updateTransform(file)
|
|
71
|
-
break
|
|
72
|
-
}
|
|
73
59
|
}
|
|
74
60
|
|
|
75
61
|
extractComments() {
|
|
76
62
|
let comments = []
|
|
77
|
-
for (const file of
|
|
63
|
+
for (const file of this.mocks)
|
|
78
64
|
comments = comments.concat(Route.extractComments(file))
|
|
79
65
|
return comments
|
|
80
66
|
}
|
|
@@ -90,7 +76,6 @@ export class MockBroker {
|
|
|
90
76
|
}
|
|
91
77
|
|
|
92
78
|
#write500() {
|
|
93
|
-
// TODO handle route with transforms but without mocks
|
|
94
79
|
const { urlMask, method } = Route.parseFilename(this.mocks[0])
|
|
95
80
|
let mask = urlMask
|
|
96
81
|
const t = join(Config.mocksDir, urlMask)
|
package/src/MockDispatcher.js
CHANGED
|
@@ -28,25 +28,25 @@ export async function dispatchMock(req, response) {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
try {
|
|
31
|
-
const { file, status, delay
|
|
31
|
+
const { file, status, delay } = broker
|
|
32
32
|
console.log('\n', req.url, '→\n ', file)
|
|
33
33
|
|
|
34
|
-
const shouldJavaScriptToJSON = file.endsWith('.js')
|
|
35
34
|
response.statusCode = status
|
|
36
|
-
response.setHeader('content-type', mimeFor(
|
|
35
|
+
response.setHeader('content-type', mimeFor(file))
|
|
37
36
|
if (cookie.getCurrent())
|
|
38
37
|
response.setHeader('set-cookie', cookie.getCurrent())
|
|
39
38
|
|
|
40
|
-
let
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
mockAsText = transformFunc(mockAsText, body, Config)
|
|
39
|
+
let mockText
|
|
40
|
+
if (file.endsWith('.js')) {
|
|
41
|
+
response.setHeader('content-type', mimeFor('.json'))
|
|
42
|
+
const jsExport = await importDefault(file)
|
|
43
|
+
mockText = typeof jsExport === 'function'
|
|
44
|
+
? jsExport(req, response)
|
|
45
|
+
: JSON.stringify(jsExport)
|
|
48
46
|
}
|
|
49
|
-
|
|
47
|
+
else
|
|
48
|
+
mockText = readMock(file)
|
|
49
|
+
setTimeout(() => response.end(mockText), delay)
|
|
50
50
|
}
|
|
51
51
|
catch (error) {
|
|
52
52
|
console.error(error)
|
|
@@ -59,16 +59,6 @@ export async function dispatchMock(req, response) {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
const nonSafeMethods = ['PATCH', 'POST', 'PUT', 'DELETE', 'CONNECT']
|
|
63
|
-
|
|
64
|
-
async function requestBodyForTransform(req, mockAsText) {
|
|
65
|
-
if (nonSafeMethods.includes(req.method))
|
|
66
|
-
return req.headers[DF.isForDashboard] // TODO unit TESTME
|
|
67
|
-
? JSON.parse(mockAsText)
|
|
68
|
-
: await parseJSON(req)
|
|
69
|
-
return ''
|
|
70
|
-
}
|
|
71
|
-
|
|
72
62
|
function readMock(file) {
|
|
73
63
|
return readFileSync(join(Config.mocksDir, file), 'utf8')
|
|
74
64
|
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
// This is an example "transform". It takes the mock for the same route as
|
|
2
|
-
// input, so you can modify it. In this case, it uses the `database` field.
|
|
3
|
-
|
|
4
|
-
export default function concatNewlyUploadedVideos(mockAsText, _, config) {
|
|
5
|
-
const mockList = JSON.parse(mockAsText)
|
|
6
|
-
mockList.videos = mockList.videos.concat(config.database.videos || [])
|
|
7
|
-
return JSON.stringify(mockList, null, 2)
|
|
8
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
// An example "transform" for saving a POST request payload into the `config.database`
|
|
2
|
-
|
|
3
|
-
export default function concatNewlyUploadedVideos(mockAsText, requestBody, config) {
|
|
4
|
-
config.database.videos ??= []
|
|
5
|
-
config.database.videos.push({
|
|
6
|
-
createdAt: Date.now(),
|
|
7
|
-
...requestBody
|
|
8
|
-
})
|
|
9
|
-
return JSON.stringify({})
|
|
10
|
-
}
|
|
File without changes
|
|
File without changes
|