diff --git a/packages/bruno-cli/src/commands/run.js b/packages/bruno-cli/src/commands/run.js index 57e334e86..0ef587a9c 100644 --- a/packages/bruno-cli/src/commands/run.js +++ b/packages/bruno-cli/src/commands/run.js @@ -12,7 +12,7 @@ const { rpad } = require('../utils/common'); const { bruToJson, getOptions, collectionBruToJson } = require('../utils/bru'); const { dotenvToJson } = require('@usebruno/lang'); const constants = require('../constants'); -const { findItemInCollection } = require('../utils/collection'); +const { findItemInCollection, getAllRequestsInFolder, createCollectionJsonFromPathname } = require('../utils/collection'); const command = 'run [filename]'; const desc = 'Run a request'; @@ -22,6 +22,7 @@ const printRunSummary = (results) => { passedRequests, failedRequests, skippedRequests, + errorRequests, totalAssertions, passedAssertions, failedAssertions, @@ -36,6 +37,9 @@ const printRunSummary = (results) => { if (failedRequests > 0) { requestSummary += `, ${chalk.red(`${failedRequests} failed`)}`; } + if (errorRequests > 0) { + requestSummary += `, ${chalk.red(`${errorRequests} error`)}`; + } if (skippedRequests > 0) { requestSummary += `, ${chalk.magenta(`${skippedRequests} skipped`)}`; } @@ -62,6 +66,7 @@ const printRunSummary = (results) => { passedRequests, failedRequests, skippedRequests, + errorRequests, totalAssertions, passedAssertions, failedAssertions, @@ -71,163 +76,6 @@ const printRunSummary = (results) => { } }; -const createCollectionFromPath = (collectionPath) => { - const environmentsPath = path.join(collectionPath, `environments`); - const getFilesInOrder = (collectionPath) => { - let collection = { - pathname: collectionPath - }; - const traverse = (currentPath) => { - const filesInCurrentDir = fs.readdirSync(currentPath); - - if (currentPath.includes('node_modules')) { - return; - } - const currentDirItems = []; - for (const file of filesInCurrentDir) { - const filePath = path.join(currentPath, file); - const stats = fs.lstatSync(filePath); - if ( - stats.isDirectory() && - filePath !== environmentsPath && - !filePath.startsWith('.git') && - !filePath.startsWith('node_modules') - ) { - let folderItem = { name: file, pathname: filePath, type: 'folder', items: traverse(filePath) } - const folderBruFilePath = path.join(filePath, 'folder.bru'); - const folderBruFileExists = fs.existsSync(folderBruFilePath); - if(folderBruFileExists) { - const folderBruContent = fs.readFileSync(folderBruFilePath, 'utf8'); - let folderBruJson = collectionBruToJson(folderBruContent); - folderItem.root = folderBruJson; - } - currentDirItems.push(folderItem); - } - } - - for (const file of filesInCurrentDir) { - if (['collection.bru', 'folder.bru'].includes(file)) { - continue; - } - const filePath = path.join(currentPath, file); - const stats = fs.lstatSync(filePath); - - if (!stats.isDirectory() && path.extname(filePath) === '.bru') { - const bruContent = fs.readFileSync(filePath, 'utf8'); - const bruJson = bruToJson(bruContent); - currentDirItems.push({ - name: file, - pathname: filePath, - ...bruJson - }); - } - } - return currentDirItems; - }; - collection.items = traverse(collectionPath); - return collection; - }; - return getFilesInOrder(collectionPath); -}; - -const getBruFilesRecursively = (dir, testsOnly) => { - const environmentsPath = 'environments'; - const collection = {}; - - const getFilesInOrder = (dir) => { - let bruJsons = []; - - const traverse = (currentPath) => { - const filesInCurrentDir = fs.readdirSync(currentPath); - - if (currentPath.includes('node_modules')) { - return; - } - - for (const file of filesInCurrentDir) { - const filePath = path.join(currentPath, file); - const stats = fs.statSync(filePath); - - // todo: we might need a ignore config inside bruno.json - if ( - stats.isDirectory() && - filePath !== environmentsPath && - !filePath.startsWith('.git') && - !filePath.startsWith('node_modules') - ) { - traverse(filePath); - } - } - - const currentDirBruJsons = []; - for (const file of filesInCurrentDir) { - if (['collection.bru', 'folder.bru'].includes(file)) { - continue; - } - const filePath = path.join(currentPath, file); - const stats = fs.lstatSync(filePath); - - if (!stats.isDirectory() && path.extname(filePath) === '.bru') { - const bruContent = fs.readFileSync(filePath, 'utf8'); - const bruJson = bruToJson(bruContent); - const requestHasTests = bruJson.request?.tests; - const requestHasActiveAsserts = bruJson.request?.assertions.some((x) => x.enabled) || false; - - if (testsOnly) { - if (requestHasTests || requestHasActiveAsserts) { - currentDirBruJsons.push({ - bruFilepath: filePath, - bruJson - }); - } - } else { - currentDirBruJsons.push({ - bruFilepath: filePath, - bruJson - }); - } - } - } - - // order requests by sequence - currentDirBruJsons.sort((a, b) => { - const aSequence = a.bruJson.seq || 0; - const bSequence = b.bruJson.seq || 0; - return aSequence - bSequence; - }); - - bruJsons = bruJsons.concat(currentDirBruJsons); - }; - - traverse(dir); - return bruJsons; - }; - - return getFilesInOrder(dir); -}; - -const getCollectionRoot = (dir) => { - const collectionRootPath = path.join(dir, 'collection.bru'); - const exists = fs.existsSync(collectionRootPath); - if (!exists) { - return {}; - } - - const content = fs.readFileSync(collectionRootPath, 'utf8'); - return collectionBruToJson(content); -}; - -const getFolderRoot = (dir) => { - const folderRootPath = path.join(dir, 'folder.bru'); - const exists = fs.existsSync(folderRootPath); - if (!exists) { - return {}; - } - - const content = fs.readFileSync(folderRootPath, 'utf8'); - return collectionBruToJson(content); -}; - const getJsSandboxRuntime = (sandbox) => { return sandbox === 'safe' ? 'quickjs' : 'vm2'; }; @@ -320,7 +168,6 @@ const builder = async (yargs) => { type:"number", description: "Delay between each requests (in miliseconds)" }) - .example('$0 run request.bru', 'Run a request') .example('$0 run request.bru --env local', 'Run a request with the environment set to local') .example('$0 run folder', 'Run all requests in a folder') @@ -390,25 +237,8 @@ const handler = async function (argv) { } = argv; const collectionPath = process.cwd(); - // todo - // right now, bru must be run from the root of the collection - // will add support in the future to run it from anywhere inside the collection - const brunoJsonPath = path.join(collectionPath, 'bruno.json'); - const brunoJsonExists = await exists(brunoJsonPath); - if (!brunoJsonExists) { - console.error(chalk.red(`You can run only at the root of a collection`)); - process.exit(constants.EXIT_STATUS.ERROR_NOT_IN_COLLECTION); - } - - const brunoConfigFile = fs.readFileSync(brunoJsonPath, 'utf8'); - const brunoConfig = JSON.parse(brunoConfigFile); - const collectionRoot = getCollectionRoot(collectionPath); - let collection = createCollectionFromPath(collectionPath); - collection = { - brunoConfig, - root: collectionRoot, - ...collection - } + let collection = createCollectionJsonFromPathname(collectionPath); + const { root: collectionRoot, brunoConfig } = collection; if (clientCertConfig) { try { @@ -444,7 +274,6 @@ const handler = async function (argv) { } } - if (filename && filename.length) { const pathExists = await exists(filename); if (!pathExists) { @@ -566,54 +395,39 @@ const handler = async function (argv) { const _isFile = isFile(filename); let results = []; - let bruJsons = []; + let requestItems = []; if (_isFile) { console.log(chalk.yellow('Running Request \n')); const bruContent = fs.readFileSync(filename, 'utf8'); - const bruJson = bruToJson(bruContent); - bruJsons.push({ - bruFilepath: filename, - bruJson - }); + const requestItem = bruToJson(bruContent); + requestItem.pathname = path.resolve(collectionPath, filename); + requestItems.push(requestItem); } const _isDirectory = isDirectory(filename); if (_isDirectory) { if (!recursive) { console.log(chalk.yellow('Running Folder \n')); - const files = fs.readdirSync(filename); - const bruFiles = files.filter((file) => !['folder.bru'].includes(file) && file.endsWith('.bru')); - - for (const bruFile of bruFiles) { - const bruFilepath = path.join(filename, bruFile); - const bruContent = fs.readFileSync(bruFilepath, 'utf8'); - const bruJson = bruToJson(bruContent); - const requestHasTests = bruJson.request?.tests; - const requestHasActiveAsserts = bruJson.request?.assertions.some((x) => x.enabled) || false; - if (testsOnly) { - if (requestHasTests || requestHasActiveAsserts) { - bruJsons.push({ - bruFilepath, - bruJson - }); - } - } else { - bruJsons.push({ - bruFilepath, - bruJson - }); - } - } - bruJsons.sort((a, b) => { - const aSequence = a.bruJson.seq || 0; - const bSequence = b.bruJson.seq || 0; - return aSequence - bSequence; - }); } else { console.log(chalk.yellow('Running Folder Recursively \n')); + } + const resolvedFilepath = path.resolve(filename); + if (resolvedFilepath === collectionPath) { + requestItems = getAllRequestsInFolder(collection?.items, recursive); + } else { + const folderItem = findItemInCollection(collection, resolvedFilepath); + if (folderItem) { + requestItems = getAllRequestsInFolder(folderItem.items, recursive); + } + } - bruJsons = getBruFilesRecursively(filename, testsOnly); + if (testsOnly) { + requestItems = requestItems.filter((iter) => { + const requestHasTests = iter.request?.tests; + const requestHasActiveAsserts = iter.request?.assertions.some((x) => x.enabled) || false; + return requestHasTests || requestHasActiveAsserts; + }); } } @@ -625,11 +439,10 @@ const handler = async function (argv) { if (itemPathname && !itemPathname?.endsWith('.bru')) { itemPathname = `${itemPathname}.bru`; } - const bruJson = cloneDeep(findItemInCollection(collection, itemPathname)); - if (bruJson) { + const requestItem = cloneDeep(findItemInCollection(collection, itemPathname)); + if (requestItem) { const res = await runSingleRequest( - itemPathname, - bruJson, + requestItem, collectionPath, runtimeVariables, envVars, @@ -648,14 +461,13 @@ const handler = async function (argv) { let currentRequestIndex = 0; let nJumps = 0; // count the number of jumps to avoid infinite loops - while (currentRequestIndex < bruJsons.length) { - const iter = cloneDeep(bruJsons[currentRequestIndex]); - const { bruFilepath, bruJson } = iter; + while (currentRequestIndex < requestItems.length) { + const requestItem = cloneDeep(requestItems[currentRequestIndex]); + const { pathname } = requestItem; const start = process.hrtime(); const result = await runSingleRequest( - bruFilepath, - bruJson, + requestItem, collectionPath, runtimeVariables, envVars, @@ -667,7 +479,7 @@ const handler = async function (argv) { runSingleRequestByPathname ); - const isLastRun = currentRequestIndex === bruJsons.length - 1; + const isLastRun = currentRequestIndex === requestItems.length - 1; const isValidDelay = !Number.isNaN(delay) && delay > 0; if(isValidDelay && !isLastRun){ console.log(chalk.yellow(`Waiting for ${delay}ms or ${(delay/1000).toFixed(3)}s before next request.`)); @@ -681,7 +493,7 @@ const handler = async function (argv) { results.push({ ...result, runtime: process.hrtime(start)[0] + process.hrtime(start)[1] / 1e9, - suitename: bruFilepath.replace('.bru', '') + suitename: pathname.replace('.bru', '') }); if (reporterSkipAllHeaders) { @@ -739,7 +551,7 @@ const handler = async function (argv) { if (nextRequestName === null) { break; } - const nextRequestIdx = bruJsons.findIndex((iter) => iter.bruJson.name === nextRequestName); + const nextRequestIdx = requestItems.findIndex((iter) => iter.name === nextRequestName); if (nextRequestIdx >= 0) { currentRequestIndex = nextRequestIdx; } else { diff --git a/packages/bruno-cli/src/runner/run-single-request.js b/packages/bruno-cli/src/runner/run-single-request.js index 774587614..2bf7bc435 100644 --- a/packages/bruno-cli/src/runner/run-single-request.js +++ b/packages/bruno-cli/src/runner/run-single-request.js @@ -31,8 +31,7 @@ const onConsoleLog = (type, args) => { }; const runSingleRequest = async function ( - filename, - bruJson, + item, collectionPath, runtimeVariables, envVariables, @@ -43,14 +42,12 @@ const runSingleRequest = async function ( collection, runSingleRequestByPathname ) { + const { pathname: itemPathname } = item; + const relativeItemPathname = path.relative(collectionPath, itemPathname); try { let request; let nextRequestName; let shouldStopRunnerExecution = false; - let item = { - pathname: path.join(collectionPath, filename), - ...bruJson - } request = prepareRequest(item, collection); request.__bruno__executionMode = 'cli'; @@ -84,7 +81,7 @@ const runSingleRequest = async function ( if (result?.skipRequest) { return { test: { - filename: filename + filename: relativeItemPathname }, request: { method: request.method, @@ -98,7 +95,8 @@ const runSingleRequest = async function ( data: null, responseTime: 0 }, - error: 'Request has been skipped from pre-request script', + error: null, + status: 'skipped', skipped: true, assertionResults: [], testResults: [], @@ -362,10 +360,10 @@ const runSingleRequest = async function ( responseTime = response.headers.get('request-duration'); response.headers.delete('request-duration'); } else { - console.log(chalk.red(stripExtension(filename)) + chalk.dim(` (${err.message})`)); + console.log(chalk.red(stripExtension(relativeItemPathname)) + chalk.dim(` (${err.message})`)); return { test: { - filename: filename + filename: relativeItemPathname }, request: { method: request.method, @@ -374,13 +372,14 @@ const runSingleRequest = async function ( data: request.data }, response: { - status: null, + status: 'error', statusText: null, headers: null, data: null, responseTime: 0 }, error: err?.message || err?.errors?.map(e => e?.message)?.at(0) || err?.code || 'Request Failed!', + status: 'error', assertionResults: [], testResults: [], nextRequestName: nextRequestName, @@ -392,12 +391,12 @@ const runSingleRequest = async function ( response.responseTime = responseTime; console.log( - chalk.green(stripExtension(filename)) + + chalk.green(stripExtension(relativeItemPathname)) + chalk.dim(` (${response.status} ${response.statusText}) - ${responseTime} ms`) ); // run post-response vars - const postResponseVars = get(bruJson, 'request.vars.res'); + const postResponseVars = get(item, 'request.vars.res'); if (postResponseVars?.length) { const varsRuntime = new VarsRuntime({ runtime: scriptingConfig?.runtime }); varsRuntime.runPostResponseVars( @@ -438,7 +437,7 @@ const runSingleRequest = async function ( // run assertions let assertionResults = []; - const assertions = get(bruJson, 'request.assertions'); + const assertions = get(item, 'request.assertions'); if (assertions) { const assertRuntime = new AssertRuntime({ runtime: scriptingConfig?.runtime }); assertionResults = assertRuntime.runAssertions( @@ -500,7 +499,7 @@ const runSingleRequest = async function ( return { test: { - filename: filename + filename: relativeItemPathname }, request: { method: request.method, @@ -516,16 +515,17 @@ const runSingleRequest = async function ( responseTime }, error: null, + status: 'pass', assertionResults, testResults, nextRequestName: nextRequestName, shouldStopRunnerExecution }; } catch (err) { - console.log(chalk.red(stripExtension(filename)) + chalk.dim(` (${err.message})`)); + console.log(chalk.red(stripExtension(relativeItemPathname)) + chalk.dim(` (${err.message})`)); return { test: { - filename: filename + filename: relativeItemPathname }, request: { method: null, @@ -534,12 +534,13 @@ const runSingleRequest = async function ( data: null }, response: { - status: null, + status: 'error', statusText: null, headers: null, data: null, responseTime: 0 }, + status: 'error', error: err.message, assertionResults: [], testResults: [] diff --git a/packages/bruno-cli/src/utils/bru.js b/packages/bruno-cli/src/utils/bru.js index cb8cee7fe..07844a455 100644 --- a/packages/bruno-cli/src/utils/bru.js +++ b/packages/bruno-cli/src/utils/bru.js @@ -15,6 +15,17 @@ const collectionBruToJson = (bru) => { } }; + // add meta if it exists + // this is only for folder bru file + // in the future, all of this will be replaced by standard bru lang + const sequence = _.get(json, 'meta.seq'); + if (json?.meta) { + transformedJson.meta = { + name: json.meta.name, + seq: !isNaN(sequence) ? Number(sequence) : 1 + }; + } + return transformedJson; } catch (error) { return Promise.reject(error); diff --git a/packages/bruno-cli/src/utils/collection.js b/packages/bruno-cli/src/utils/collection.js index ec2705af3..3616c1f87 100644 --- a/packages/bruno-cli/src/utils/collection.js +++ b/packages/bruno-cli/src/utils/collection.js @@ -4,6 +4,112 @@ const fs = require('fs'); const path = require('path'); const { jsonToBruV2, envJsonToBruV2, jsonToCollectionBru } = require('@usebruno/lang'); const { sanitizeName } = require('./filesystem'); +const { bruToJson, collectionBruToJson } = require('./bru'); +const constants = require('../constants'); +const chalk = require('chalk'); + +const createCollectionJsonFromPathname = (collectionPath) => { + const environmentsPath = path.join(collectionPath, `environments`); + + // get the collection bruno json config [/bruno.json] + const brunoConfig = getCollectionBrunoJsonConfig(collectionPath); + + // get the collection root [/collection.bru] + const collectionRoot = getCollectionRoot(collectionPath); + + // get the collection items recursively + const traverse = (currentPath) => { + const filesInCurrentDir = fs.readdirSync(currentPath); + if (currentPath.includes('node_modules')) { + return; + } + const currentDirItems = []; + for (const file of filesInCurrentDir) { + const filePath = path.join(currentPath, file); + const stats = fs.lstatSync(filePath); + if (stats.isDirectory()) { + if (filePath === environmentsPath) continue; + if (filePath.startsWith('.git') || filePath.startsWith('node_modules')) continue; + + // get the folder root + let folderItem = { name: file, pathname: filePath, type: 'folder', items: traverse(filePath) } + const folderBruJson = getFolderRoot(filePath); + if (folderBruJson) { + folderItem.root = folderBruJson; + folderItem.seq = folderBruJson.meta.seq; + } + currentDirItems.push(folderItem); + } + else { + if (['collection.bru', 'folder.bru'].includes(file)) continue; + if (path.extname(filePath) !== '.bru') continue; + + // get the request item + const bruContent = fs.readFileSync(filePath, 'utf8'); + const requestItem = bruToJson(bruContent); + currentDirItems.push({ + name: file, + pathname: filePath, + ...requestItem + }); + } + } + let currentDirFolderItems = currentDirItems?.filter((iter) => iter.type === 'folder'); + let sortedFolderItems = currentDirFolderItems?.sort((a, b) => a.seq - b.seq); + + let currentDirRequestItems = currentDirItems?.filter((iter) => iter.type !== 'folder'); + let sortedRequestItems = currentDirRequestItems?.sort((a, b) => a.seq - b.seq); + + return sortedFolderItems?.concat(sortedRequestItems); + }; + let collectionItems = traverse(collectionPath); + + let collection = { + brunoConfig, + root: collectionRoot, + pathname: collectionPath, + items: collectionItems + } + + return collection; +}; + +const getCollectionBrunoJsonConfig = (dir) => { + // right now, bru must be run from the root of the collection + // will add support in the future to run it from anywhere inside the collection + const brunoJsonPath = path.join(dir, 'bruno.json'); + const brunoJsonExists = fs.existsSync(brunoJsonPath); + if (!brunoJsonExists) { + console.error(chalk.red(`You can run only at the root of a collection`)); + process.exit(constants.EXIT_STATUS.ERROR_NOT_IN_COLLECTION); + } + + const brunoConfigFile = fs.readFileSync(brunoJsonPath, 'utf8'); + const brunoConfig = JSON.parse(brunoConfigFile); + return brunoConfig; +} + +const getCollectionRoot = (dir) => { + const collectionRootPath = path.join(dir, 'collection.bru'); + const exists = fs.existsSync(collectionRootPath); + if (!exists) { + return {}; + } + + const content = fs.readFileSync(collectionRootPath, 'utf8'); + return collectionBruToJson(content); +}; + +const getFolderRoot = (dir) => { + const folderRootPath = path.join(dir, 'folder.bru'); + const exists = fs.existsSync(folderRootPath); + if (!exists) { + return null; + } + + const content = fs.readFileSync(folderRootPath, 'utf8'); + return collectionBruToJson(content); +}; const mergeHeaders = (collection, request, requestTreePath) => { let headers = new Map(); @@ -204,6 +310,27 @@ const getTreePathFromCollectionToItem = (collection, _item) => { return path; }; +const getAllRequestsInFolder = (folderItems = [], recursive = true) => { + let requests = []; + + if (folderItems && folderItems.length) { + folderItems.forEach((item) => { + if (item.type !== 'folder') { + requests.push(item); + } else { + if (recursive) { + requests = requests.concat(getAllRequestsInFolder(item.items, recursive)); + } + } + }); + } + return requests; +}; + +const getAllRequestsAtFolderRoot = (folderItems = []) => { + return getAllRequestsInFolder(folderItems, false); +} + /** * Safe write file implementation to handle errors * @param {string} filePath - Path to write file @@ -334,11 +461,16 @@ const processCollectionItems = async (items = [], currentPath) => { } }; + + module.exports = { + createCollectionJsonFromPathname, mergeHeaders, mergeVars, mergeScripts, findItemInCollection, getTreePathFromCollectionToItem, + getAllRequestsInFolder, + getAllRequestsAtFolderRoot, createCollectionFromBrunoObject } \ No newline at end of file diff --git a/packages/bruno-cli/tests/runner/collection-json-from-pathname.spec.js b/packages/bruno-cli/tests/runner/collection-json-from-pathname.spec.js new file mode 100644 index 000000000..8cab346cd --- /dev/null +++ b/packages/bruno-cli/tests/runner/collection-json-from-pathname.spec.js @@ -0,0 +1,172 @@ +const path = require("node:path"); +const { describe, it, expect } = require('@jest/globals'); +const constants = require('../../src/constants'); +const { createCollectionJsonFromPathname } = require('../../src/utils/collection'); + +describe('create collection json from pathname', () => { + it("should throw an error when the pathname is not a valid bruno collection root", () => { + const invalidCollectionPathname = path.join(__dirname, './fixtures/collection-invalid'); + jest.spyOn(console, 'error').mockImplementation(() => { }); + let mockProcessExit = jest.spyOn(process, 'exit').mockImplementation((code) => { throw new Error(code); }); + try { createCollectionJsonFromPathname(invalidCollectionPathname); } catch { } + expect(mockProcessExit).toHaveBeenCalledWith(constants.EXIT_STATUS.ERROR_NOT_IN_COLLECTION); + jest.restoreAllMocks(); + }) + + it("creates a bruno collection json from the collection bru files", () => { + const collectionPathname = path.join(__dirname, './fixtures/collection-json-from-pathname/collection'); + const outputCollectionJson = createCollectionJsonFromPathname(collectionPathname); + + let c = outputCollectionJson; + expect(c).toBeDefined(); + + /* collection bruno.json */ + expect(c).toHaveProperty('brunoConfig.version', "1"); + expect(c).toHaveProperty('brunoConfig.name', 'collection'); + expect(c).toHaveProperty('brunoConfig.type', 'collection'); + expect(c).toHaveProperty('brunoConfig.ignore', ["node_modules", ".git"]); + expect(c).toHaveProperty('brunoConfig.proxy.enabled', false); + expect(c).toHaveProperty('brunoConfig.proxy.protocol', 'http'); + expect(c).toHaveProperty('brunoConfig.proxy.hostname', ''); + expect(c).toHaveProperty('brunoConfig.proxy.port', 3000); + expect(c).toHaveProperty('brunoConfig.proxy.auth.enabled', false); + expect(c).toHaveProperty('brunoConfig.proxy.auth.username', ''); + expect(c).toHaveProperty('brunoConfig.proxy.auth.password', ''); + expect(c).toHaveProperty('brunoConfig.proxy.bypassProxy', ''); + expect(c).toHaveProperty('brunoConfig.scripts.moduleWhitelist', ['crypto', 'buffer']); + expect(c).toHaveProperty('brunoConfig.scripts.filesystemAccess.allow', true); + expect(c).toHaveProperty('brunoConfig.clientCertificates.enabled', true); + expect(c).toHaveProperty('brunoConfig.clientCertificates.certs', []); + + /* collection pathname */ + expect(c).toHaveProperty('pathname', collectionPathname); + + /* collection root */ + // headers + expect(c).toHaveProperty('root.request.headers[0].name', 'collection_header'); + expect(c).toHaveProperty('root.request.headers[0].value', 'collection_header_value'); + expect(c).toHaveProperty('root.request.headers[0].enabled', true); + // auth + expect(c).toHaveProperty('root.request.auth.mode', 'basic'); + expect(c).toHaveProperty('root.request.auth.basic.username', 'username'); + expect(c).toHaveProperty('root.request.auth.basic.password', 'password'); + // pre-request scripts + expect(c).toHaveProperty('root.request.script.req', 'const collectionPreRequestScript = true;'); + // collection root - post-response scripts + expect(c).toHaveProperty('root.request.script.res', 'const collectionPostResponseScript = true;'); + // pre-request vars + expect(c).toHaveProperty('root.request.vars.req[0].name', 'collection_pre_var'); + expect(c).toHaveProperty('root.request.vars.req[0].value', 'collection_pre_var_value'); + expect(c).toHaveProperty('root.request.vars.req[0].enabled', true); + // post-response vars + expect(c).toHaveProperty('root.request.vars.res[0].name', 'collection_post_var'); + expect(c).toHaveProperty('root.request.vars.res[0].value', 'collection_post_var_value'); + expect(c).toHaveProperty('root.request.vars.res[0].enabled', true); + // tests + expect(c).toHaveProperty('root.request.tests', 'test(\"collection level script\", function() {\n expect(\"test\").to.equal(\"test\");\n});'); + + /* collection items names and sequences */ + // /folder_2 + expect(c).toHaveProperty('items[0].type', 'folder'); + expect(c).toHaveProperty('items[0].name', 'folder_2'); + expect(c).toHaveProperty('items[0].seq', 1); + + // /folder_2/request_1 + expect(c).toHaveProperty('items[0].items[0].name', 'request_1'); + expect(c).toHaveProperty('items[0].items[0].seq', 1); + + // /folder_2/request_3 + expect(c).toHaveProperty('items[0].items[1].name', 'request_3'); + expect(c).toHaveProperty('items[0].items[1].seq', 2); + + // /folder_2/request_2 + expect(c).toHaveProperty('items[0].items[2].name', 'request_2'); + expect(c).toHaveProperty('items[0].items[2].seq', 3); + + // /folder_1 + expect(c).toHaveProperty('items[1].type', 'folder'); + expect(c).toHaveProperty('items[1].name', 'folder_1'); + expect(c).toHaveProperty('items[1].seq', 5); + + // /folder_1/folder_2 + expect(c).toHaveProperty('items[1].items[0].name', 'folder_2'); + expect(c).toHaveProperty('items[1].items[0].seq', 1); + + // /folder_1/folder_2/request_3 + expect(c).toHaveProperty('items[1].items[0].items[0].name', 'request_3'); + expect(c).toHaveProperty('items[1].items[0].items[0].seq', 1); + + // /folder_1/folder_2/request_1 + expect(c).toHaveProperty('items[1].items[0].items[1].name', 'request_1'); + expect(c).toHaveProperty('items[1].items[0].items[1].seq', 2); + + // /folder_1/folder_2/request_2 + expect(c).toHaveProperty('items[1].items[0].items[2].name', 'request_2'); + expect(c).toHaveProperty('items[1].items[0].items[2].seq', 3); + + // /folder_1/folder_1 + expect(c).toHaveProperty('items[1].items[1].name', 'folder_1'); + expect(c).toHaveProperty('items[1].items[1].seq', 2); + + // /folder_1/folder_1/request_3 + expect(c).toHaveProperty('items[1].items[1].items[0].name', 'request_3'); + expect(c).toHaveProperty('items[1].items[1].items[0].seq', 1); + + // /folder_1/folder_1/request_2 + expect(c).toHaveProperty('items[1].items[1].items[1].name', 'request_2'); + expect(c).toHaveProperty('items[1].items[1].items[1].seq', 2); + + // /folder_1/folder_1/request_1 + expect(c).toHaveProperty('items[1].items[1].items[2].name', 'request_1'); + expect(c).toHaveProperty('items[1].items[1].items[2].seq', 3); + + // /folder_1/request_1 + expect(c).toHaveProperty('items[1].items[2].name', 'request_1'); + expect(c).toHaveProperty('items[1].items[2].seq', 3); + + // /folder_1/request_3 + expect(c).toHaveProperty('items[1].items[3].name', 'request_3'); + expect(c).toHaveProperty('items[1].items[3].seq', 4); + + // /folder_1/request_2 + expect(c).toHaveProperty('items[1].items[4].name', 'request_2'); + expect(c).toHaveProperty('items[1].items[4].seq', 5); + + // /request_2 + expect(c).toHaveProperty('items[2].name', 'request_3'); + expect(c).toHaveProperty('items[2].seq', 2); + + // /request_3 + expect(c).toHaveProperty('items[3].name', 'request_1'); + expect(c).toHaveProperty('items[3].seq', 3); + + // /request_4 + expect(c).toHaveProperty('items[4].name', 'request_2'); + expect(c).toHaveProperty('items[4].seq', 4); + + /* collection request item - /request_4 */ + // /request_4 + // headers + expect(c).toHaveProperty('items[4].request.headers[0].name', 'request_header'); + expect(c).toHaveProperty('items[4].request.headers[0].value', 'request_header_value'); + expect(c).toHaveProperty('items[4].request.headers[0].enabled', true); + // auth + expect(c).toHaveProperty('items[4].request.auth.mode', 'basic'); + expect(c).toHaveProperty('items[4].request.auth.basic.username', 'username'); + expect(c).toHaveProperty('items[4].request.auth.basic.password', 'password'); + // pre-request scripts + expect(c).toHaveProperty('items[4].request.script.req', 'const requestPreRequestScript = true;'); + // request items[4] - post-response scripts + expect(c).toHaveProperty('items[4].request.script.res', 'const requestPostResponseScript = true;'); + // pre-request vars + expect(c).toHaveProperty('items[4].request.vars.req[0].name', 'request_pre_var'); + expect(c).toHaveProperty('items[4].request.vars.req[0].value', 'request_pre_var_value'); + expect(c).toHaveProperty('items[4].request.vars.req[0].enabled', true); + // post-response vars + expect(c).toHaveProperty('items[4].request.vars.res[0].name', 'request_post_var'); + expect(c).toHaveProperty('items[4].request.vars.res[0].value', 'request_post_var_value'); + expect(c).toHaveProperty('items[4].request.vars.res[0].enabled', true); + // tests + expect(c).toHaveProperty('items[4].request.tests', 'test(\"request level script\", function() {\n expect(\"test\").to.equal(\"test\");\n});'); + }); +}); \ No newline at end of file diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/bruno.json b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/bruno.json new file mode 100644 index 000000000..366f84472 --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/bruno.json @@ -0,0 +1,31 @@ +{ + "version": "1", + "name": "collection", + "type": "collection", + "ignore": [ + "node_modules", + ".git" + ], + "proxy": { + "enabled": false, + "protocol": "http", + "hostname": "", + "port": 3000, + "auth": { + "enabled": false, + "username": "", + "password": "" + }, + "bypassProxy": "" + }, + "scripts": { + "moduleWhitelist": ["crypto", "buffer"], + "filesystemAccess": { + "allow": true + } + }, + "clientCertificates": { + "enabled": true, + "certs": [] + } +} \ No newline at end of file diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/collection.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/collection.bru new file mode 100644 index 000000000..bdfbfc430 --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/collection.bru @@ -0,0 +1,38 @@ +headers { + collection_header: collection_header_value +} + +auth { + mode: basic +} + +auth:basic { + username: username + password: password +} + +vars:pre-request { + collection_pre_var: collection_pre_var_value +} + +vars:post-response { + collection_post_var: collection_post_var_value +} + +script:pre-request { + const collectionPreRequestScript = true; +} + +script:post-response { + const collectionPostResponseScript = true; +} + +tests { + test("collection level script", function() { + expect("test").to.equal("test"); + }); +} + +docs { + # docs +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder.bru new file mode 100644 index 000000000..fb30da65c --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder.bru @@ -0,0 +1,4 @@ +meta { + name: folder_1 + seq: 5 +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_1/folder.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_1/folder.bru new file mode 100644 index 000000000..2b5e3cd2f --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_1/folder.bru @@ -0,0 +1,4 @@ +meta { + name: folder_1 + seq: 2 +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_1/request_1.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_1/request_1.bru new file mode 100644 index 000000000..79ff1676a --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_1/request_1.bru @@ -0,0 +1,11 @@ +meta { + name: request_1 + type: http + seq: 3 +} + +get { + url: https://echo.usebruno.com + body: text + auth: none +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_1/request_2.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_1/request_2.bru new file mode 100644 index 000000000..b0b7e046e --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_1/request_2.bru @@ -0,0 +1,11 @@ +meta { + name: request_2 + type: http + seq: 2 +} + +get { + url: https://echo.usebruno.com + body: text + auth: none +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_1/request_3.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_1/request_3.bru new file mode 100644 index 000000000..7953c4499 --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_1/request_3.bru @@ -0,0 +1,11 @@ +meta { + name: request_3 + type: http + seq: 1 +} + +get { + url: https://echo.usebruno.com + body: text + auth: none +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_2/folder.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_2/folder.bru new file mode 100644 index 000000000..674476e89 --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_2/folder.bru @@ -0,0 +1,4 @@ +meta { + name: folder_2 + seq: 1 +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_2/request_1.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_2/request_1.bru new file mode 100644 index 000000000..c93c6cb37 --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_2/request_1.bru @@ -0,0 +1,11 @@ +meta { + name: request_1 + type: http + seq: 2 +} + +get { + url: https://echo.usebruno.com + body: text + auth: none +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_2/request_2.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_2/request_2.bru new file mode 100644 index 000000000..375cc9f6d --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_2/request_2.bru @@ -0,0 +1,11 @@ +meta { + name: request_2 + type: http + seq: 3 +} + +get { + url: https://echo.usebruno.com + body: text + auth: none +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_2/request_3.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_2/request_3.bru new file mode 100644 index 000000000..7953c4499 --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/folder_2/request_3.bru @@ -0,0 +1,11 @@ +meta { + name: request_3 + type: http + seq: 1 +} + +get { + url: https://echo.usebruno.com + body: text + auth: none +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/request_1.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/request_1.bru new file mode 100644 index 000000000..79ff1676a --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/request_1.bru @@ -0,0 +1,11 @@ +meta { + name: request_1 + type: http + seq: 3 +} + +get { + url: https://echo.usebruno.com + body: text + auth: none +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/request_2.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/request_2.bru new file mode 100644 index 000000000..7dac68aed --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/request_2.bru @@ -0,0 +1,11 @@ +meta { + name: request_2 + type: http + seq: 5 +} + +get { + url: https://echo.usebruno.com + body: text + auth: none +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/request_3.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/request_3.bru new file mode 100644 index 000000000..8a818f66c --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_1/request_3.bru @@ -0,0 +1,11 @@ +meta { + name: request_3 + type: http + seq: 4 +} + +get { + url: https://echo.usebruno.com + body: text + auth: none +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_2/folder.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_2/folder.bru new file mode 100644 index 000000000..674476e89 --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_2/folder.bru @@ -0,0 +1,4 @@ +meta { + name: folder_2 + seq: 1 +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_2/request_1.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_2/request_1.bru new file mode 100644 index 000000000..b8fb205ed --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_2/request_1.bru @@ -0,0 +1,11 @@ +meta { + name: request_1 + type: http + seq: 1 +} + +get { + url: https://echo.usebruno.com + body: text + auth: none +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_2/request_2.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_2/request_2.bru new file mode 100644 index 000000000..375cc9f6d --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_2/request_2.bru @@ -0,0 +1,11 @@ +meta { + name: request_2 + type: http + seq: 3 +} + +get { + url: https://echo.usebruno.com + body: text + auth: none +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_2/request_3.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_2/request_3.bru new file mode 100644 index 000000000..a2582cf6c --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/folder_2/request_3.bru @@ -0,0 +1,11 @@ +meta { + name: request_3 + type: http + seq: 2 +} + +get { + url: https://echo.usebruno.com + body: text + auth: none +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/request_1.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/request_1.bru new file mode 100644 index 000000000..79ff1676a --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/request_1.bru @@ -0,0 +1,11 @@ +meta { + name: request_1 + type: http + seq: 3 +} + +get { + url: https://echo.usebruno.com + body: text + auth: none +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/request_2.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/request_2.bru new file mode 100644 index 000000000..1aef2b30e --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/request_2.bru @@ -0,0 +1,58 @@ +meta { + name: request_2 + type: http + seq: 4 +} + +post { + url: https://echo.usebruno.com/:request_path_param?request_query_param=request_query_param_value + body: text + auth: basic +} + +params:query { + request_query_param: request_query_param_value +} + +params:path { + request_path_param: request_path_param_value +} + +headers { + request_header: request_header_value +} + +auth:basic { + username: username + password: password +} + +body:text { + ping +} + +vars:pre-request { + request_pre_var: request_pre_var_value +} + +vars:post-response { + request_post_var: request_post_var_value +} + +assert { + res.status: eq 200 +} + +script:pre-request { + const requestPreRequestScript = true; +} + +script:post-response { + const requestPostResponseScript = true; +} + +tests { + test("request level script", function() { + expect("test").to.equal("test"); + }); +} diff --git a/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/request_3.bru b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/request_3.bru new file mode 100644 index 000000000..a2582cf6c --- /dev/null +++ b/packages/bruno-cli/tests/runner/fixtures/collection-json-from-pathname/collection/request_3.bru @@ -0,0 +1,11 @@ +meta { + name: request_3 + type: http + seq: 2 +} + +get { + url: https://echo.usebruno.com + body: text + auth: none +}