Skip to content

Commit

Permalink
feat: add responseDelay_ms option
Browse files Browse the repository at this point in the history
  • Loading branch information
anoack93 committed Sep 18, 2023
1 parent c1927d1 commit cbc5856
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 33 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ import { createServeMocksExpressApp } from 'servemocks';
const mainApp = express();

const options = {
responseDelay_ms: 100,
// enable javascript code to be executed from a mock file with
// .mjs file extension
// eval can be used as alternative strategy if dynamicImport does not work
Expand Down
69 changes: 36 additions & 33 deletions src/serve-mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,33 @@ import Ajv from 'ajv'
import { mockFileTypes } from './mock-file-types.js'
import { extractHttpMethod, HttpMethod } from './utilities/http-method.js'
import { runInNewContext } from 'vm'
import { sleep } from './utilities/async-utilities.js'

const ajv = new Ajv()

/**
* @param {object} mapping
* @return {string}
* @typedef {Object} ServemocksOptions
* @property {number} responseDelay_ms - default delay which will be added before sending a response
* @property {'eval' | 'dynamicImport' | 'disabled'} dynamicMockResponsesMode
*/

// String which will be replaced by '/' in api endpoint
// this is being used for directories which have the same name as a file like /test.jpg/medium
// you would name that file /test.jpg---medium.jpg
const SLASH_ALIAS = '---'

/**
* @type {ServemocksOptions}
*/
export const defaultServeMocksOptions = {
//
// possible values: 'dynamicImport', 'disabled', 'eval
//
dynamicMockResponsesMode: 'dynamicImport'
responseDelay_ms: 100,
dynamicMockResponsesMode: 'eval',
}

/**
* @param {string} mockDirectory
* @param {object} options
* @return {express}
* @return {Express}
*/
export function createServeMocksExpressApp (mockDirectory, options = {}) {
const effectiveOptions = {
Expand Down Expand Up @@ -83,9 +86,10 @@ export function createServeMocksExpressApp (mockDirectory, options = {}) {
switch (httpMethod) {
case HttpMethod.GET:
app.get(apiPath, async function (req, res) {
console.log(chalk.blueBright(`receiving GET request on ${apiPath}`))
await sleep(effectiveOptions.responseDelay_ms)
let responseBody
let errorObject
console.log(chalk.blueBright(`receiving GET request on ${apiPath}`))
if (fileType.extension === '.mjs' && effectiveOptions.dynamicMockResponsesMode !== 'disabled') {
const context = {
query: req.query || {},
Expand All @@ -106,7 +110,6 @@ export function createServeMocksExpressApp (mockDirectory, options = {}) {
fileName + ' for GET endpoint ' + apiPath)
}
} else {
console.log('ENTER eval')
let scriptContent = readFileSync(fileName, fileType.encoding).toString()
if (scriptContent.includes('export default function')) {
scriptContent = scriptContent.replace('export default function', 'globalThis.responseBody = function')
Expand Down Expand Up @@ -137,38 +140,38 @@ export function createServeMocksExpressApp (mockDirectory, options = {}) {
})
break
case HttpMethod.POST:
app.post(apiPath, function (req, res) {
app.post(apiPath, async function (req, res) {
const endpointParams = JSON.parse(readFileSync(fileName, 'utf8'))
const responseOptions = endpointParams.responseOptions ? endpointParams.responseOptions : {}
const requestOptions = endpointParams.requestOptions ? endpointParams.requestOptions : {}
const requestValidation = requestOptions.validation ? requestOptions.validation : {}
const responseDelay = responseOptions.delay_ms ? responseOptions.delay_ms : 2000
const responseDelay = responseOptions.delay_ms ? responseOptions.delay_ms : effectiveOptions.responseDelay_ms
const statusCode = responseOptions.statusCode ? responseOptions.statusCode : 200
let response = endpointParams.response ? endpointParams.response : { success: true }
console.log(`receiving POST request on ${apiPath} with body:`, req.body)

setTimeout(() => {
// validate request body against json schema if provided in requestOptions
if (requestValidation.jsonSchema) {
const isValid = ajv.compile(requestValidation.jsonSchema)
if (!isValid(req.body)) {
const errors = isValid.errors
console.info('validation of request body failed; errors:', errors)
res.status(422).send({
message: 'request body is not compliant to the expected schema',
errors
})
return
}
console.log(chalk.blueBright(`receiving POST request on ${apiPath} with body:`), req.body)

await sleep(responseDelay)

// validate request body against json schema if provided in requestOptions
if (requestValidation.jsonSchema) {
const isValid = ajv.compile(requestValidation.jsonSchema)
if (!isValid(req.body)) {
const errors = isValid.errors
console.info('validation of request body failed; errors:', errors)
res.status(422).send({
message: 'request body is not compliant to the expected schema',
errors
})
return
}
}

if (responseOptions.respondWithRequestBody === true) {
res.set('Content-Type', req.get('Content-Type'))
response = req.body
}
if (responseOptions.respondWithRequestBody === true) {
res.set('Content-Type', req.get('Content-Type'))
response = req.body
}

res.status(statusCode).send(response)
}, responseDelay)
res.status(statusCode).send(response)
})
break
default:
Expand All @@ -192,7 +195,7 @@ export function createServeMocksExpressApp (mockDirectory, options = {}) {
* @param {number} [port]
* @param {string} hostname
* @param {object} options
* @return {express}
* @return {Express}
*/
export function serveMocks (mockDirectory, port, hostname, options = {}) {
const app = createServeMocksExpressApp(mockDirectory, options)
Expand Down
7 changes: 7 additions & 0 deletions src/utilities/async-utilities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* @param {number} ms
* @return {Promise}
*/
export function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}

0 comments on commit cbc5856

Please sign in to comment.