Merge pull request #241 from tpyle/bug/correct-result-reporting

Handle failed requests and reduce duplication
This commit is contained in:
Anoop M D
2023-10-05 19:40:28 +05:30
committed by GitHub
7 changed files with 410 additions and 261 deletions

View File

@@ -12,17 +12,56 @@ const { dotenvToJson } = require('@usebruno/lang');
const command = 'run [filename]';
const desc = 'Run a request';
const printRunSummary = (assertionResults, testResults) => {
// display assertion results and test results summary
const totalAssertions = assertionResults.length;
const passedAssertions = assertionResults.filter((result) => result.status === 'pass').length;
const failedAssertions = totalAssertions - passedAssertions;
const printRunSummary = (results) => {
let totalRequests = 0;
let passedRequests = 0;
let failedRequests = 0;
let totalAssertions = 0;
let passedAssertions = 0;
let failedAssertions = 0;
let totalTests = 0;
let passedTests = 0;
let failedTests = 0;
for (const result of results) {
totalRequests += 1;
totalTests += result.testResults.length;
totalAssertions += result.assertionResults.length;
let anyFailed = false;
let hasAnyTestsOrAssertions = false;
for (const testResult of result.testResults) {
hasAnyTestsOrAssertions = true;
if (testResult.status === 'pass') {
passedTests += 1;
} else {
anyFailed = true;
failedTests += 1;
}
}
for (const assertionResult of result.assertionResults) {
hasAnyTestsOrAssertions = true;
if (assertionResult.status === 'pass') {
passedAssertions += 1;
} else {
anyFailed = true;
failedAssertions += 1;
}
}
if (!hasAnyTestsOrAssertions && result.error) {
failedRequests += 1;
} else {
passedRequests += 1;
}
}
const totalTests = testResults.length;
const passedTests = testResults.filter((result) => result.status === 'pass').length;
const failedTests = totalTests - passedTests;
const maxLength = 12;
let requestSummary = `${rpad('Requests:', maxLength)} ${chalk.green(`${passedRequests} passed`)}`;
if (failedRequests > 0) {
requestSummary += `, ${chalk.red(`${failedRequests} failed`)}`;
}
requestSummary += `, ${totalRequests} total`;
let assertSummary = `${rpad('Tests:', maxLength)} ${chalk.green(`${passedTests} passed`)}`;
if (failedTests > 0) {
assertSummary += `, ${chalk.red(`${failedTests} failed`)}`;
@@ -35,10 +74,14 @@ const printRunSummary = (assertionResults, testResults) => {
}
testSummary += `, ${totalAssertions} total`;
console.log('\n' + chalk.bold(assertSummary));
console.log('\n' + chalk.bold(requestSummary));
console.log(chalk.bold(assertSummary));
console.log(chalk.bold(testSummary));
return {
totalRequests,
passedRequests,
failedRequests,
totalAssertions,
passedAssertions,
failedAssertions,
@@ -255,9 +298,7 @@ const handler = async function (argv) {
}
const _isFile = await isFile(filename);
let assertionResults = [];
let testResults = [];
let testrunResults = [];
let results = [];
let bruJsons = [];
@@ -311,16 +352,10 @@ const handler = async function (argv) {
brunoConfig
);
if (result) {
testrunResults.push(result);
const { assertionResults: _assertionResults, testResults: _testResults } = result;
assertionResults = assertionResults.concat(_assertionResults);
testResults = testResults.concat(_testResults);
}
results.push(result);
}
const summary = printRunSummary(assertionResults, testResults);
const summary = printRunSummary(results);
console.log(chalk.dim(chalk.grey('Ran all requests.')));
if (outputPath && outputPath.length) {
@@ -333,14 +368,14 @@ const handler = async function (argv) {
const outputJson = {
summary,
results: testrunResults
results
};
fs.writeFileSync(outputPath, JSON.stringify(outputJson, null, 2));
console.log(chalk.dim(chalk.grey(`Wrote results to ${outputPath}`)));
}
if (summary.failedAssertions > 0 || summary.failedTests > 0) {
if (summary.failedAssertions + summary.failedTests + summary.failedRequests > 0) {
process.exit(1);
}
} catch (err) {
@@ -354,5 +389,6 @@ module.exports = {
command,
desc,
builder,
handler
handler,
printRunSummary
};

View File

@@ -0,0 +1,67 @@
const { describe, it, expect } = require('@jest/globals');
const { printRunSummary } = require('./run');
describe('printRunSummary', () => {
// Suppress console.log output
jest.spyOn(console, 'log').mockImplementation(() => {});
it('should produce the correct summary for a successful run', () => {
const results = [
{
testResults: [{ status: 'pass' }, { status: 'pass' }, { status: 'pass' }],
assertionResults: [{ status: 'pass' }, { status: 'pass' }],
error: null
},
{
testResults: [{ status: 'pass' }, { status: 'pass' }],
assertionResults: [{ status: 'pass' }, { status: 'pass' }, { status: 'pass' }],
error: null
}
];
const summary = printRunSummary(results);
expect(summary.totalRequests).toBe(2);
expect(summary.passedRequests).toBe(2);
expect(summary.failedRequests).toBe(0);
expect(summary.totalAssertions).toBe(5);
expect(summary.passedAssertions).toBe(5);
expect(summary.failedAssertions).toBe(0);
expect(summary.totalTests).toBe(5);
expect(summary.passedTests).toBe(5);
expect(summary.failedTests).toBe(0);
});
it('should produce the correct summary for a failed run', () => {
const results = [
{
testResults: [{ status: 'fail' }, { status: 'pass' }, { status: 'pass' }],
assertionResults: [{ status: 'pass' }, { status: 'fail' }],
error: null
},
{
testResults: [{ status: 'pass' }, { status: 'fail' }],
assertionResults: [{ status: 'pass' }, { status: 'fail' }, { status: 'fail' }],
error: null
},
{
testResults: [],
assertionResults: [],
error: new Error('Request failed')
}
];
const summary = printRunSummary(results);
expect(summary.totalRequests).toBe(3);
expect(summary.passedRequests).toBe(2);
expect(summary.failedRequests).toBe(1);
expect(summary.totalAssertions).toBe(5);
expect(summary.passedAssertions).toBe(2);
expect(summary.failedAssertions).toBe(3);
expect(summary.totalTests).toBe(5);
expect(summary.passedTests).toBe(3);
expect(summary.failedTests).toBe(2);
});
});

View File

@@ -20,9 +20,9 @@ const runSingleRequest = async function (
processEnvVars,
brunoConfig
) {
let request;
try {
let request;
request = prepareRequest(bruJson.request);
// make axios work in node using form data
@@ -122,8 +122,34 @@ const runSingleRequest = async function (
request.data = qs.stringify(request.data);
}
// run request
const response = await axios(request);
let response;
try {
// run request
response = await axios(request);
} catch (err) {
if (err && err.response) {
response = err.response;
} else {
console.log(chalk.red(stripExtension(filename)) + chalk.dim(` (${err.message})`));
return {
request: {
method: request.method,
url: request.url,
headers: request.headers,
data: request.data
},
response: {
status: null,
statusText: null,
headers: null,
data: null
},
error: err.message,
assertionResults: [],
testResults: []
};
}
}
console.log(chalk.green(stripExtension(filename)) + chalk.dim(` (${response.status} ${response.statusText})`));
@@ -223,100 +249,28 @@ const runSingleRequest = async function (
headers: response.headers,
data: response.data
},
error: null,
assertionResults,
testResults
};
} catch (err) {
if (err && err.response) {
console.log(
chalk.green(stripExtension(filename)) + chalk.dim(` (${err.response.status} ${err.response.statusText})`)
);
// run post-response vars
const postResponseVars = get(bruJson, 'request.vars.res');
if (postResponseVars && postResponseVars.length) {
const varsRuntime = new VarsRuntime();
varsRuntime.runPostResponseVars(
postResponseVars,
request,
err.response,
envVariables,
collectionVariables,
collectionPath,
processEnvVars
);
}
// run post response script
const responseScriptFile = get(bruJson, 'request.script.res');
if (responseScriptFile && responseScriptFile.length) {
const scriptRuntime = new ScriptRuntime();
await scriptRuntime.runResponseScript(
responseScriptFile,
request,
err.response,
envVariables,
collectionVariables,
collectionPath,
null,
processEnvVars
);
}
// run assertions
let assertionResults = [];
const assertions = get(bruJson, 'request.assertions');
if (assertions) {
const assertRuntime = new AssertRuntime();
assertionResults = assertRuntime.runAssertions(
assertions,
request,
err.response,
envVariables,
collectionVariables,
collectionPath
);
each(assertionResults, (r) => {
if (r.status === 'pass') {
console.log(chalk.green(``) + chalk.dim(`assert: ${r.lhsExpr}: ${r.rhsExpr}`));
} else {
console.log(chalk.red(``) + chalk.red(`assert: ${r.lhsExpr}: ${r.rhsExpr}`));
console.log(chalk.red(` ${r.error}`));
}
});
}
// run tests
let testResults = [];
const testFile = get(bruJson, 'request.tests');
if (typeof testFile === 'string') {
const testRuntime = new TestRuntime();
const result = await testRuntime.runTests(
testFile,
request,
err.response,
envVariables,
collectionVariables,
collectionPath,
null,
processEnvVars
);
testResults = get(result, 'results', []);
}
if (testResults && testResults.length) {
each(testResults, (testResult) => {
if (testResult.status === 'pass') {
console.log(chalk.green(``) + chalk.dim(testResult.description));
} else {
console.log(chalk.red(``) + chalk.red(testResult.description));
}
});
}
} else {
console.log(chalk.red(stripExtension(filename)) + chalk.dim(` (${err.message})`));
}
return {
request: {
method: null,
url: null,
headers: null,
data: null
},
response: {
status: null,
statusText: null,
headers: null,
data: null
},
error: err.message,
assertionResults: [],
testResults: []
};
}
};