UNPKG

scenario-generator

Version:

From input recipes generate json file containing HTTP requests and responses

370 lines (304 loc) 10.5 kB
import utils from './utils.js' import typeGenerators from './type-generators.js' function toTechnology(technology) { return technology || 'HTTP' } function replaceData(target, config) { let returnTarget = target Object.keys(config) .forEach(key => { returnTarget = returnTarget.replaceAll('{' + key + '}', config[key]) }) return JSON.parse(returnTarget) } function toRuleRange(key, maxNumber) { if (key.startsWith('>')) { return [Number.parseInt(key.replace('>', '')), Number.parseInt(maxNumber)] } if (key.includes('-')) { const numbers = key.split('-') if (numbers[0] > numbers[1]) { throw 'Invalid number range: ' + key } return [Number.parseInt(numbers[0]), Number.parseInt(numbers[1])] } const number = Number.parseInt(key) if (number) { return [number, number] } return [0, 0] } function findReplaceRule(replaceRules, i, numOf) { let entries = Object.entries(replaceRules || {}) if (entries.length <= 0) { return {} } return entries .filter(([key, _value]) => { const range = toRuleRange(key, numOf) return range[0] <= i && range[1] >= i }) .map(([_key, value]) => { return value })[0] || {} } function replaceAlways(target, replace, generateAlways) { const config = { ...replace, ...utils.generateReplace(generateAlways, replace) } const keys = Object.keys(config) let returnTarget = target keys.forEach(key => { returnTarget = returnTarget.replaceAll( '{' + key + '}', () => { const newConfig = { ...replace, ...utils.generateReplace(generateAlways, replace) } return newConfig[key] } ) }) return JSON.parse(returnTarget) } function toInteraction(input) { const interaction = { request: {}, response: {} } Object.keys(input.requestTemplate) .forEach(key => { if (input.generateAlways) { interaction.request[key] = replaceAlways(JSON.stringify(input.requestTemplate[key]), input.replace, input.generateAlways) } else { interaction.request[key] = replaceData(JSON.stringify(input.requestTemplate[key]), input.replace) } }) Object.keys(input.responseTemplate) .forEach(key => { if (input.generateAlways) { interaction.response[key] = replaceAlways(JSON.stringify(input.responseTemplate[key]), input.replace, input.generateAlways) } else { interaction.response[key] = replaceData(JSON.stringify(input.responseTemplate[key]), input.replace) } }) return { [input.technology]: { ...interaction } } } function findGeneratedConstant(generateConstants, key, i) { if (!generateConstants.length) { return undefined } const constant = generateConstants.find(c => c.constant === key) if (!constant) { return undefined } if (constant.generated.length < i + 1) { return undefined } return constant.generated[i] } function toArrayPosition(value) { const start = value.indexOf('[') const end = value.indexOf(']') return value.substring(start + 1, end) } function toFilteredObject(replace, matcher) { let entries = Object.entries(replace || {}) if (entries.length <= 0) { return {} } let filtered = entries .filter(([_key, value]) => matcher(value)) .map(([key, value]) => { return { [key]: value } }) return filtered.length === 0 ? {} : filtered.reduce((a, b) => { return {...a, ...b} }) } function toReplaceEntriesToInject(replace) { return toFilteredObject( replace, value => value.match('^[$][{].*.}$') ) } function toReplaceEntriesToNotInject(replace) { return toFilteredObject( replace, value => !value.match('^[$][{].*.}$') ) } function toConstantName(value) { const start = value.indexOf('{') const end = value.indexOf('[') return value.substring(start + 1, end) } function toInjectGeneratedValues(replace, generateConstants, i) { let entries = Object.entries(replace || {}) if (entries.length <= 0) { return {} } return entries .map(([key, value]) => { const position = toArrayPosition(value) const constantName = toConstantName(value) const constant = findGeneratedConstant(generateConstants, constantName, position === 'N' || position === 'n' ? i : Number.parseInt(position)) if (constant === undefined) { return {} } return { [key]: constant } }) .reduce((a, b) => { return {...a, ...b} }) } function toInteractions(input, numOfInteractions = 1) { const interactions = [] for (let i = 1; i < numOfInteractions + 1; i++) { const replaceRule = findReplaceRule(input.interactionReplaceRules, i, numOfInteractions) input.generateForEach = [ ...(input.generateForEach ? input.generateForEach : []), ...(replaceRule.generateForEach ? replaceRule.generateForEach : []) ] input.generateAlways = [ ...(input.generateAlways ? input.generateAlways : []), ...(replaceRule.generateAlways ? replaceRule.generateAlways : []) ] const generated = utils.generateReplace(input.generateForEach, input.replace) const resolvedReplace = toInjectGeneratedValues( toReplaceEntriesToInject(replaceRule.replace), input?.scenarioReplaceRule?.generateConstants, i ) input.replace = { ...input.replace, ...generated, ...toReplaceEntriesToNotInject(replaceRule.replace), ...resolvedReplace } interactions.push(toInteraction(input)) } return interactions } function toHeaders(headerFile, headers, defaultHeaders) { if (headerFile) { return utils.openFile(headerFile) } return headers ? headers : utils.openFile(defaultHeaders) } function resolveInputData(data) { const extracted = data?.templateFile ? utils.openFile(data.templateFile) : data.template const final = data?.entryName && extracted ? extracted[data?.entryName] : extracted return final || data } function toRequest(request) { const { headerFile, ...outRequest } = request // filter out headerFile outRequest.body = request.body ? resolveInputData(request.body) : {} return outRequest } function toResponse(response) { const {...outResponse} = response outResponse.body = response.body ? resolveInputData(response.body) : {} return outResponse } function toInteractionTemplate(interaction) { const interactionData = resolveInputData(interaction) return interactionData[toTechnology(interaction.technology)] || interactionData } function toGenerateAlways(inputGenerateAlways, interactionGenerateAlways) { return [ ...(inputGenerateAlways ? inputGenerateAlways : []), ...(interactionGenerateAlways ? interactionGenerateAlways : []) ] } function toScenario(input, globalReplace, replaceRule = {}) { replaceRule.generateConstants = toGenerateConstants(replaceRule.generateConstants || []) return input.interactions .map(interaction => { const interactionTemplate = toInteractionTemplate(interaction) if(interactionTemplate === undefined || interactionTemplate.request === undefined) { console.log(interaction) throw new Error("Cannot find interaction template") } return toInteractions( { replace: { ...globalReplace, ...interaction?.replace }, interactionReplaceRules: interaction.replaceRules, scenarioReplaceRule: replaceRule, technology: toTechnology(interaction.technology), generateForEach: interaction.generateForEach || [], generateAlways: toGenerateAlways(input.generateAlways, interaction.generateAlways), requestTemplate: { ...toRequest(interactionTemplate.request), headers: toHeaders( interactionTemplate.request?.headerTemplateFile, interactionTemplate.request?.headers, input?.headerTemplateFile?.[toTechnology(interaction.technology)] || input?.headerTemplateFile ) }, responseTemplate: { ...toResponse(interactionTemplate.response) } }, interaction.numOfInteractions ? Number.parseInt(interaction.numOfInteractions) : 1 ) }) } function toGenerateConstants(generateConstants) { return generateConstants .map(constant => { return { ...constant, generated: typeGenerators.toRandomFromType( constant.type, constant.min, constant.max, constant.numberOf || 1, constant?.decimals ) } }) } export default { createScenarios: (input, numOfScenarios = 1) => { if (!input?.interactions?.length) { return [] } const scenarios = [] for (let i = 0; i < numOfScenarios; i++) { scenarios.push( toScenario( input, utils.toReplace(input.generateForEach, input.replace), findReplaceRule(input.replaceRules, i + 1, numOfScenarios) ) ) } return utils.flattenInputArray(scenarios) }, createScenario: (input, globalReplace = {}) => toScenario(input, globalReplace) }