Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@reportportal/newman-reporter-agent-js-postman

Package Overview
Dependencies
Maintainers
4
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@reportportal/newman-reporter-agent-js-postman - npm Package Compare versions

Comparing version 5.0.4 to 5.0.5

21

lib/constants/patterns.js

@@ -17,8 +17,19 @@ /*

const testPatterns = [/[\s]*pm.test\("(.*?)",/, /[\s]*pm.test.skip\("(.*?)",/, /[\s]*tests\["(.*?)"\]/];
const pmVariablesTestCaseIdPatterns =
[/[\s]*pm.variables.set\("rp.testCaseId", "(.*?)"\)/, /[\s]*pm.variables.set\("rp.testCaseId","(.*?)"\)/];
const pmVariablesStatusPatterns =
[/[\s]*pm.variables.set\("rp.status", "(.*?)"\)/, /[\s]*pm.variables.set\("rp.status","(.*?)"\)/];
const testPatterns = [
/[\s]*pm.test\("(.*?)",/,
/[\s]*pm.test\(`(.*?)`,/,
/[\s]*pm.test.skip\("(.*?)",/,
/[\s]*tests\["(.*?)"\]/,
];
const pmVariablesTestCaseIdPatterns = [
/[\s]*pm.variables.set\("rp.testCaseId", "(.*?)"\)/,
/[\s]*pm.variables.set\("rp.testCaseId","(.*?)"\)/,
];
const pmVariablesStatusPatterns = [
/[\s]*pm.variables.set\("rp.status", "(.*?)"\)/,
/[\s]*pm.variables.set\("rp.status","(.*?)"\)/,
];
module.exports = { testPatterns, pmVariablesTestCaseIdPatterns, pmVariablesStatusPatterns };

@@ -18,6 +18,10 @@ /*

const RPClient = require('@reportportal/client-javascript');
const StringDecoder = require('string_decoder').StringDecoder;
const { StringDecoder } = require('string_decoder');
const _ = require('lodash');
const utils = require('./utils');
const { testPatterns, pmVariablesTestCaseIdPatterns, pmVariablesStatusPatterns } = require('./constants/patterns');
const {
testPatterns,
pmVariablesTestCaseIdPatterns,
pmVariablesStatusPatterns,
} = require('./constants/patterns');

@@ -29,6 +33,6 @@ /**

*/
const errorHandler = err => {
if (err) {
console.error(err);
}
const errorHandler = (err) => {
if (err) {
console.error(err);
}
};

@@ -42,414 +46,504 @@

const TestStatus = Object.freeze({
PASSED: 'PASSED',
FAILED: 'FAILED',
SKIPPED: 'SKIPPED'
PASSED: 'PASSED',
FAILED: 'FAILED',
SKIPPED: 'SKIPPED',
INTERRUPTED: 'INTERRUPTED',
});
class Reporter {
constructor (emitter, options, collectionRunOptions, rpClient) {
const client = rpClient || RPClient;
this.client = new client(utils.getClientInitObject(options), utils.getAgentInfo());
this.launchObj = this.client.startLaunch(utils.getStartLaunchObj(options));
this.collectionMap = new Map();
this.suitesInfoStack = [];
this.decoder = new StringDecoder('utf8');
this.collectionRunOptions = collectionRunOptions;
this.options = options;
this.collectionPath = utils.getCollectionPath(this.collectionRunOptions.workingDir);
this.launchLogs = [];
this.suiteLogs = [];
this.testLogs = [];
constructor(emitter, options, collectionRunOptions, rpClient) {
const Client = rpClient || RPClient;
emitter.on('console', this.onConsole.bind(this));
emitter.on('start', this.onStart.bind(this));
emitter.on('beforeRequest', this.onBeforeRequest.bind(this));
emitter.on('beforeTest', this.onBeforeTest.bind(this));
emitter.on('item', this.finishTest.bind(this));
emitter.on('assertion', this.finishStep.bind(this));
emitter.on('test', this.finishAllSteps.bind(this));
emitter.on('request', this.onRequest.bind(this));
emitter.on('beforeDone', this.onBeforeDone.bind(this));
emitter.on('done', this.onDone.bind(this));
}
this.client = new Client(utils.getClientInitObject(options), utils.getAgentInfo());
this.launchObj = this.client.startLaunch(utils.getStartLaunchObj(options));
this.collectionMap = new Map();
this.suitesInfoStack = [];
this.decoder = new StringDecoder('utf8');
this.collectionRunOptions = collectionRunOptions;
this.options = options;
this.collectionPath = utils.getCollectionPath(this.collectionRunOptions.workingDir);
this.launchLogs = [];
this.suiteLogs = [];
this.testLogs = [];
onConsole (err, args) {
if (err) {
throw err;
}
emitter.on('console', this.onConsole.bind(this));
const type = args.messages && args.messages[0];
emitter.on('start', this.onStart.bind(this));
emitter.on('beforeRequest', this.onBeforeRequest.bind(this));
emitter.on('request', this.onRequest.bind(this));
emitter.on('beforeTest', this.onBeforeTest.bind(this));
emitter.on('test', this.finishAllSteps.bind(this));
emitter.on('item', this.finishTest.bind(this));
emitter.on('assertion', this.finishStep.bind(this));
emitter.on('beforeDone', this.onBeforeDone.bind(this));
emitter.on('done', this.onDone.bind(this));
}
switch (type) {
case 'launch':
if (this.launchLogs !== null) {
args.messages.slice(1)
.forEach(message => this.launchLogs.push({ level: args.level, message, time: this.getTime() }));
}
break;
case 'suite':
if (this.suiteLogs !== null) {
args.messages.slice(1)
.forEach(message => this.suiteLogs.push({ level: args.level, message, time: this.getTime() }));
}
break;
case 'test':
args.messages.slice(1)
.forEach(message => this.testLogs.push({ level: args.level, message, time: this.getTime() }));
break;
default:
break;
}
onConsole(err, args) {
if (err) {
throw err;
}
getCurrentSuiteTempId () {
const tempId = this.suitesInfoStack.length ?
this.suitesInfoStack[this.suitesInfoStack.length - 1].tempId : null;
const type = args.messages && args.messages[0];
return tempId;
switch (type) {
case 'launch':
if (this.launchLogs !== null) {
args.messages.slice(1).forEach((message) =>
this.launchLogs.push({
level: args.level,
message,
time: this.getTime(),
}),
);
}
break;
case 'suite':
if (this.suiteLogs !== null) {
args.messages.slice(1).forEach((message) =>
this.suiteLogs.push({
level: args.level,
message,
time: this.getTime(),
}),
);
}
break;
case 'test':
args.messages.slice(1).forEach((message) =>
this.testLogs.push({
level: args.level,
message,
time: this.getTime(),
}),
);
break;
default:
break;
}
}
getTestName (result) {
if (result.item.name === undefined) {
return null;
}
const iteration = this.collectionRunOptions.iterationCount === undefined ?
'' :
` #${result.cursor.iteration + 1}`;
getCurrentSuiteTempId() {
const tempId = this.suitesInfoStack.length
? this.suitesInfoStack[this.suitesInfoStack.length - 1].tempId
: null;
return `${result.item.name}${iteration}`;
return tempId;
}
getTestName(result) {
if (result.item.name === undefined) {
return null;
}
const iteration =
this.collectionRunOptions.iterationCount === undefined
? ''
: ` #${result.cursor.iteration + 1}`;
// Starts an item as suite
onStart (err, result) {
if (err) {
throw err;
}
return `${result.item.name}${iteration}`;
}
const name = this.collectionRunOptions.collection.name;
const description = this.collectionRunOptions.collection.description &&
this.collectionRunOptions.collection.description.content;
const codeRef = utils.getCodeRef(this.collectionPath, name);
startTestStep({ stepName, result, currentStepData, testObj }) {
const codeRefTitle = `${this.collectionRunOptions.collection.name}/${result.item.name}/${stepName}`;
const parameters = utils.getParameters(
this.collectionRunOptions.iterationData,
result.cursor.iteration,
);
const codeRef = utils.getCodeRef(this.collectionPath, codeRefTitle);
const suiteObj = this.client.startTestItem({
type: 'SUITE',
name,
description,
codeRef,
testCaseId: utils.getCollectionVariablesByKey('testCaseId', this.collectionRunOptions.collection.variables),
attributes: utils.getAttributes(this.collectionRunOptions.collection.variables)
}, this.launchObj.tempId);
const stepObj = this.client.startTestItem(
{
name: stepName,
type: 'STEP',
parameters,
codeRef,
...(currentStepData.testCaseId && { testCaseId: currentStepData.testCaseId }),
},
this.launchObj.tempId,
testObj.testId,
);
suiteObj.promise.catch(errorHandler);
stepObj.promise.catch(errorHandler);
this.suitesInfoStack.push({ tempId: suiteObj.tempId, ref: result.cursor.ref });
return stepObj;
}
// Starts an item as suite
onStart(err, result) {
if (err) {
throw err;
}
// Starts a request as test
onBeforeRequest (err, result) {
if (err) {
throw err;
}
const name = this.getTestName(result);
if (!name) {
return;
}
const parentId = this.getCurrentSuiteTempId();
const description = result.request.description && result.request.description.content;
const codeRefTitle = `${this.collectionRunOptions.collection.name}/${result.item.name}`;
const codeRef = utils.getCodeRef(this.collectionPath, codeRefTitle);
const parameters = utils.getParameters(this.collectionRunOptions.iterationData, result.cursor.iteration);
const { name } = this.collectionRunOptions.collection;
const description =
this.collectionRunOptions.collection.description &&
this.collectionRunOptions.collection.description.content;
const testObj = this.client.startTestItem({
name,
type: 'TEST',
description,
codeRef,
parameters,
testCaseId: utils.getCollectionVariablesByKey('testCaseId', this.collectionRunOptions.environment.values),
attributes: utils.getAttributes(this.collectionRunOptions.environment.values)
},
this.launchObj.tempId, parentId);
const codeRef = utils.getCodeRef(this.collectionPath, name);
testObj.promise.catch(errorHandler);
const suiteObj = this.client.startTestItem(
{
type: 'SUITE',
name,
description,
codeRef,
testCaseId: utils.getCollectionVariablesByKey(
'testCaseId',
this.collectionRunOptions.collection.variables,
),
attributes: utils.getAttributes(this.collectionRunOptions.collection.variables),
},
this.launchObj.tempId,
);
this.sendRequestLogs(testObj.tempId, result.request);
this.collectionMap.set(result.cursor.ref, {
testId: testObj.tempId,
requestId: result.cursor.httpRequestId || result.item.id,
steps: [],
status: utils.getCollectionVariablesByKey('status', this.collectionRunOptions.environment.values)
});
suiteObj.promise.catch(errorHandler);
this.testLogs &&
this.testLogs.forEach(log => this.logMessage(testObj.tempId, log.message, log.level, log.time));
this.testLogs = [];
this.suitesInfoStack.push({
tempId: suiteObj.tempId,
ref: result.cursor.ref,
});
}
this.launchLogs && this.launchLogs.forEach(log => this.sendLaunchLogMessage(log.message, log.level, log.time));
this.launchLogs = null;
// Starts a request as test
onBeforeRequest(err, result) {
if (err) {
throw err;
}
const name = this.getTestName(result);
this.suiteLogs && this.suiteLogs.forEach(log => this.logMessage(parentId, log.message, log.level, log.time));
this.suiteLogs = null;
if (!name) {
return;
}
// Starts test scripts as test steps
onBeforeTest (err, result) {
if (err) {
throw err;
}
const testObj = this.collectionMap.get(result.cursor.ref);
const parentId = this.getCurrentSuiteTempId();
const description = result.request.description && result.request.description.content;
const codeRefTitle = `${this.collectionRunOptions.collection.name}/${result.item.name}`;
const codeRef = utils.getCodeRef(this.collectionPath, codeRefTitle);
const parameters = utils.getParameters(
this.collectionRunOptions.iterationData,
result.cursor.iteration,
);
_.filter(result.events, 'script')
.flatMap(event => event.script.exec) // Extracts test script's strings
.flatMap(exec => {
const stepName = utils.getStepParameterByPatterns(exec, testPatterns)[0];
const testCaseId = utils.getStepParameterByPatterns(exec, pmVariablesTestCaseIdPatterns)[0];
const status = utils.getStepParameterByPatterns(exec, pmVariablesStatusPatterns)[0];
const testObj = this.client.startTestItem(
{
name,
type: 'TEST',
description,
codeRef,
parameters,
testCaseId: utils.getCollectionVariablesByKey(
'testCaseId',
this.collectionRunOptions.environment.values,
),
attributes: utils.getAttributes(this.collectionRunOptions.environment.values),
},
this.launchObj.tempId,
parentId,
);
return Object.assign({},
stepName ? { stepName } : {},
testCaseId ? { testCaseId } : {},
status ? { status } : {});
})
.groupBySpecificField('stepName', ['testCaseId', 'status'])
.forEach(stepInfoObj => {
// Starts a new step for every test in a test script
const stepName = stepInfoObj.stepName;
const codeRefTitle = `${this.collectionRunOptions.collection.name}/${result.item.name}/${stepName}`;
const parameters = utils.getParameters(this.collectionRunOptions.iterationData,
result.cursor.iteration);
const codeRef = utils.getCodeRef(this.collectionPath, codeRefTitle);
const stepObj = this.client.startTestItem(Object.assign({
name: stepName,
type: 'STEP',
parameters,
codeRef
}, stepInfoObj.testCaseId ? { testCaseId: stepInfoObj.testCaseId } : {}),
this.launchObj.tempId,
testObj.testId);
testObj.promise.catch(errorHandler);
stepObj.promise.catch(errorHandler);
this.sendRequestLogs(testObj.tempId, result.request);
this.collectionMap.set(result.cursor.ref, {
testId: testObj.tempId,
requestId: result.cursor.httpRequestId || result.item.id,
steps: [],
status: utils.getCollectionVariablesByKey(
'status',
this.collectionRunOptions.environment.values,
),
});
testObj.steps.push({
stepId: stepObj.tempId,
name: stepName,
status: stepInfoObj.status
});
});
this.testLogs &&
this.testLogs.forEach((log) =>
this.logMessage(testObj.tempId, log.message, log.level, log.time),
);
this.testLogs = [];
this.launchLogs &&
this.launchLogs.forEach((log) => this.sendLaunchLogMessage(log.message, log.level, log.time));
this.launchLogs = null;
this.suiteLogs &&
this.suiteLogs.forEach((log) => this.logMessage(parentId, log.message, log.level, log.time));
this.suiteLogs = null;
}
// Collect steps additional data (rp.status, rp.testCaseId)
onBeforeTest(err, result) {
if (err) {
throw err;
}
const testObj = this.collectionMap.get(result.cursor.ref);
finishStep (error, testAssertion) {
const testObj = this.collectionMap.get(testAssertion.cursor.ref);
if (!testObj) {
return;
}
const currentStepIndex = testObj.steps.findIndex(step => step.name === testAssertion.assertion);
const currentStep = testObj.steps[currentStepIndex];
testObj.steps.splice(currentStepIndex, 1);
_.filter(result.events, 'script')
.flatMap((event) => event.script.exec) // Extracts test script's strings
.flatMap((exec) => {
const stepName = utils.getStepParameterByPatterns(exec, testPatterns)[0];
const testCaseId = utils.getStepParameterByPatterns(exec, pmVariablesTestCaseIdPatterns)[0];
const status = utils.getStepParameterByPatterns(exec, pmVariablesStatusPatterns)[0];
if (!currentStep) {
return;
}
const actualError = error || testAssertion.error;
if (actualError) {
// Logs error message for the failed steps
this.logMessage(currentStep.stepId, actualError.message, 'ERROR');
}
return {
...(stepName && { stepName }),
...(testCaseId && { testCaseId }),
...(status && { status }),
};
})
.groupBySpecificField('stepName', ['testCaseId', 'status'])
.forEach((stepInfoObj) => {
testObj.steps.push(stepInfoObj);
});
const additionalData = {};
if (testAssertion.skipped) {
additionalData.status = TestStatus.SKIPPED;
if (this.options.skippedIssue === false) {
additionalData.issue = { issueType: 'NOT_ISSUE' };
}
}
testObj.steps.reverse();
}
this.client
.finishTestItem(currentStep.stepId, {
status: currentStep.status || (actualError ? TestStatus.FAILED : TestStatus.PASSED),
...additionalData
})
.promise.catch(errorHandler);
this.collectionMap.set(testAssertion.cursor.ref, testObj);
finishStep(error, testAssertion) {
const testObj = this.collectionMap.get(testAssertion.cursor.ref);
if (!testObj) {
return;
}
const currentStep = testObj.steps.pop();
finishAllSteps (err, testResult) {
if (err) {
throw err;
}
if (!currentStep) {
return;
}
const testObj = this.collectionMap.get(testResult.cursor.ref);
const testWithError = testResult.executions.find(item => item.error);
const stepName = testAssertion.assertion;
const stepObj = this.startTestStep({
stepName,
result: testAssertion,
currentStepData: currentStep,
testObj,
});
const actualError = error || testAssertion.error;
if (testWithError) {
// Fails all steps with the same error if there is an error in a test-script
this.failAllSteps(testObj, testWithError.error.message);
}
if (actualError) {
// Logs error message for the failed steps
this.logMessage(stepObj.tempId, actualError.message, 'ERROR');
}
onRequest (error, result) {
const testObj = this.collectionMap.get(result.cursor.ref);
const additionalData = {};
if (testObj) {
this.collectionMap.set(result.cursor.ref, { ...testObj, response: result && result.response, error });
}
if (testAssertion.skipped) {
additionalData.status = TestStatus.SKIPPED;
if (this.options.skippedIssue === false) {
additionalData.issue = { issueType: 'NOT_ISSUE' };
}
}
finishTest (err, result) {
if (err) {
throw err;
}
this.client
.finishTestItem(stepObj.tempId, {
status: currentStep.status || (actualError ? TestStatus.FAILED : TestStatus.PASSED),
...additionalData,
})
.promise.catch(errorHandler);
}
const testObj = this.collectionMap.get(result.cursor.ref);
if (!testObj) {
return;
}
const status = testObj.status;
finishAllSteps(err, testResult) {
if (err) {
throw err;
}
if (testObj.error) {
this.logMessage(testObj.testId, testObj.error.message, 'ERROR');
const testObj = this.collectionMap.get(testResult.cursor.ref);
const testWithError = testResult.executions.find((item) => {
return item.error;
});
this.client
.finishTestItem(testObj.testId, {
status: status || TestStatus.FAILED
})
.promise.catch(errorHandler);
// Need to start all remaining steps to send them to RP and finish them
// with the same error if there is an error in a test-script or Unknown error
testObj.steps.forEach((stepInfoObj, index, array) => {
const { stepName } = stepInfoObj;
const stepObj = this.startTestStep({
stepName,
result: testResult,
currentStepData: stepInfoObj,
testObj,
});
return;
}
Object.assign(array[index], { stepId: stepObj.tempId });
});
if (testObj.response) {
this.sendResponseLogs(testObj.testId, testObj.response);
}
// Fails all steps with the same error if there is an error in a test-script
this.interruptAllSteps(
testObj,
(testWithError && testWithError.error.message) || 'Unknown error occurred',
);
}
this.client
.finishTestItem(testObj.testId, {
status: status || TestStatus.PASSED
})
.promise.catch(errorHandler);
onRequest(error, result) {
const testObj = this.collectionMap.get(result.cursor.ref);
if (testObj) {
this.collectionMap.set(result.cursor.ref, {
...testObj,
response: result && result.response,
error,
});
}
}
// Finishes suite
onBeforeDone (err) {
if (err) {
throw err;
}
finishTest(err, result) {
if (err) {
throw err;
}
this.finishSuite();
this.suitesInfoStack.pop();
const testObj = this.collectionMap.get(result.cursor.ref);
if (!testObj) {
return;
}
const { status } = testObj;
// Finishes launch
onDone (err, result) {
if (err) {
throw err;
}
const status = this.collectionRunOptions.collection &&
utils.getCollectionVariablesByKey('launchStatus', this.collectionRunOptions.collection.variables);
if (testObj.error) {
this.logMessage(testObj.testId, testObj.error.message, 'ERROR');
this.client
.finishLaunch(this.launchObj.tempId, {
status: status || ((result.run.failures || []).length ? TestStatus.FAILED : TestStatus.PASSED)
})
.promise.catch(errorHandler);
this.client
.finishTestItem(testObj.testId, {
status: status || TestStatus.FAILED,
})
.promise.catch(errorHandler);
return;
}
// eslint-disable-next-line class-methods-use-this
getTime () {
return new Date().valueOf();
if (testObj.response) {
this.sendResponseLogs(testObj.testId, testObj.response);
}
/**
* Sends launch log message to RP using it's client.
*
* @param {string} message value.
* @param {string} [level="INFO"] Log level.
* @param {number} time when the log was started.
*/
sendLaunchLogMessage (message, level, time) {
this.logMessage(this.launchObj.tempId, message, level, time);
this.client
.finishTestItem(testObj.testId, {
status: status || TestStatus.PASSED,
})
.promise.catch(errorHandler);
}
// Finishes suite
onBeforeDone(err) {
if (err) {
throw err;
}
/**
* Sends log message to RP using it's client.
*
* @param {string} id RP's item id.
* @param {string} value Message value.
* @param {string} [level="INFO"] Log level.
* @param {number} time when the log was started.
*/
logMessage (id, value, level = 'INFO', time) {
this.client
.sendLog(id, {
level: level,
message: value,
time: time || this.getTime()
})
.promise.catch(errorHandler);
this.finishSuite();
this.suitesInfoStack.pop();
}
// Finishes launch
onDone(err, result) {
if (err) {
throw err;
}
const status =
this.collectionRunOptions.collection &&
utils.getCollectionVariablesByKey(
'launchStatus',
this.collectionRunOptions.collection.variables,
);
/**
* Sends request data logs for a specific request: URL, method, headers, body.
*
* @param {string} stepId Id of request's step.
* @param {Object} request Http request.
*/
sendRequestLogs (stepId, request) {
this.logMessage(stepId, `Request: URL: ${request.url.toString()}`);
this.logMessage(stepId, `Request: Method: ${request.method}`);
this.client
.finishLaunch(this.launchObj.tempId, {
status:
status || ((result.run.failures || []).length ? TestStatus.FAILED : TestStatus.PASSED),
})
.promise.catch(errorHandler);
}
const headers = request.headers.members.map(header => `${header.key}:${header.value}`);
// eslint-disable-next-line class-methods-use-this
getTime() {
return new Date().valueOf();
}
if (headers.length) {
this.logMessage(stepId, `Request: Headers: ${headers}`);
}
/**
* Sends launch log message to RP using it's client.
*
* @param {string} message value.
* @param {string} [level="INFO"] Log level.
* @param {number} time when the log was started.
*/
sendLaunchLogMessage(message, level, time) {
this.logMessage(this.launchObj.tempId, message, level, time);
}
if (request.body && request.body.toString()) {
this.logMessage(stepId, `Request: Body: ${request.body.toString()}`);
}
}
/**
* Sends log message to RP using it's client.
*
* @param {string} id RP's item id.
* @param {string} value Message value.
* @param {string} [level="INFO"] Log level.
* @param {number} time when the log was started.
*/
logMessage(id, value, level = 'INFO', time) {
this.client
.sendLog(id, {
level,
message: value,
time: time || this.getTime(),
})
.promise.catch(errorHandler);
}
/**
* Sends response data logs for a specific request: response code, status, headers, body.
*
* @param {string} stepId Id of request's step.
* @param {Object} response Http response.
*/
sendResponseLogs (stepId, response) {
const headers = response.headers.members.map(header => `${header.key}:${header.value}`);
/**
* Sends request data logs for a specific request: URL, method, headers, body.
*
* @param {string} stepId Id of request's step.
* @param {Object} request Http request.
*/
sendRequestLogs(stepId, request) {
this.logMessage(stepId, `Request: URL: ${request.url.toString()}`);
this.logMessage(stepId, `Request: Method: ${request.method}`);
this.logMessage(stepId, `Response: Code: ${response.code}`);
this.logMessage(stepId, `Response: Status: ${response.status}`);
this.logMessage(stepId, `Response: Headers: ${headers}`);
this.logMessage(stepId, `Response: Body: ${this.decoder.write(response.stream)}`);
const headers = request.headers.members.map((header) => `${header.key}:${header.value}`);
if (headers.length) {
this.logMessage(stepId, `Request: Headers: ${headers}`);
}
/**
* Fails all steps of the given test object with sending the same error message for each of them.
*
* @param {Object} testObj Test object with steps to fail.
* @param {string} message Error message to log.
*/
failAllSteps (testObj, message) {
_.forEach(testObj.steps, step => {
this.logMessage(step.stepId, message, 'ERROR');
this.client
.finishTestItem(step.stepId, {
status: TestStatus.FAILED
})
.promise.catch(errorHandler);
});
if (request.body && request.body.toString()) {
this.logMessage(stepId, `Request: Body: ${request.body.toString()}`);
}
}
finishSuite () {
const currentSuiteTempId = this.getCurrentSuiteTempId();
const status = this.collectionRunOptions.collection &&
utils.getCollectionVariablesByKey('status', this.collectionRunOptions.collection.variables);
/**
* Sends response data logs for a specific request: response code, status, headers, body.
*
* @param {string} stepId Id of request's step.
* @param {Object} response Http response.
*/
sendResponseLogs(stepId, response) {
const headers = response.headers.members.map((header) => `${header.key}:${header.value}`);
this.client
.finishTestItem(currentSuiteTempId, { status })
.promise.catch(errorHandler);
}
this.logMessage(stepId, `Response: Code: ${response.code}`);
this.logMessage(stepId, `Response: Status: ${response.status}`);
this.logMessage(stepId, `Response: Headers: ${headers}`);
this.logMessage(stepId, `Response: Body: ${this.decoder.write(response.stream)}`);
}
/**
* Fails all steps of the given test object with sending the same error message for each of them.
*
* @param {Object} testObj Test object with steps to fail.
* @param {string} message Error message to log.
*/
interruptAllSteps(testObj, message) {
_.forEach(testObj.steps, (step) => {
this.logMessage(step.stepId, message, 'ERROR');
this.client
.finishTestItem(step.stepId, {
status: TestStatus.INTERRUPTED,
})
.promise.catch(errorHandler);
});
}
finishSuite() {
const currentSuiteTempId = this.getCurrentSuiteTempId();
const status =
this.collectionRunOptions.collection &&
utils.getCollectionVariablesByKey('status', this.collectionRunOptions.collection.variables);
this.client.finishTestItem(currentSuiteTempId, { status }).promise.catch(errorHandler);
}
}
module.exports = Reporter;

@@ -17,7 +17,5 @@ /*

'use strict';
const _ = require('lodash');
const path = require('path');
const pjson = require('./../package.json');
const pjson = require('../package.json');

@@ -27,153 +25,158 @@ const PJSON_VERSION = pjson.version;

/**
* The default name of test launch. Agent will use this name if options.launch is not specified.
*
* @type {String}
*/
const DEFAULT_LAUNCH_NAME = 'Newman launch';
module.exports = {
/**
* Returns a match of specific string to a first given pattern. If there are no matches to given string -
* this function returns @type {null}.
* Also this function provides to specify an index of regexp group to extract it from matched string.
*
* @param {string} str String to check patterns.
* @param {RegExp[]} patterns An array of regexp patterns to verify given string.
* @param {Number} [index=0] An index of regexp group.
* @returns {string} Regexp matching.
*/
matchPattern (str, patterns, index = 0) {
if (!str) {
return null;
}
/**
* Returns a match of specific string to a first given pattern. If there are no matches to given string -
* this function returns @type {null}.
* Also this function provides to specify an index of regexp group to extract it from matched string.
*
* @param {string} str String to check patterns.
* @param {RegExp[]} patterns An array of regexp patterns to verify given string.
* @param {Number} [index=0] An index of regexp group.
* @returns {string} Regexp matching.
*/
matchPattern(str, patterns, index = 0) {
if (!str) {
return null;
}
if (!this.isArrayOfType(patterns, RegExp)) {
throw Error('Patterns array must contain only RegExp patterns');
}
if (!this.isArrayOfType(patterns, RegExp)) {
throw Error('Patterns array must contain only RegExp patterns');
}
const pattern = _.find(patterns, p => str.match(p));
const pattern = _.find(patterns, (p) => str.match(p));
return pattern ? str.match(pattern)[index] : null;
},
return pattern ? str.match(pattern)[index] : null;
},
/**
* Verifies whether the given array consists of elements only of specific type.
*
* @param {Array} array Array to check.
* @param {Function} type Constructor of specific type to verify.
* @returns {boolean} Is a given array consists of only of given types.
*/
isArrayOfType (array, type) {
return _.isArray(array) && array.every(x => x instanceof type);
},
/**
* Verifies whether the given array consists of elements only of specific type.
*
* @param {Array} array Array to check.
* @param {Function} type Constructor of specific type to verify.
* @returns {boolean} Is a given array consists of only of given types.
*/
isArrayOfType(array, type) {
return _.isArray(array) && array.every((x) => x instanceof type);
},
getStepParameterByPatterns (script, patterns) {
return script
.split(';')
.sliceOn(0, x => x.includes('//')) // Removes commented elements
.map(x => this.matchPattern(x, patterns, 1))
.filter(Boolean); // Removes empty step names
},
getStepParameterByPatterns(script, patterns) {
return script
.split(';')
.sliceOn(0, (x) => x.includes('//')) // Removes commented elements
.map((x) => this.matchPattern(x, patterns, 1))
.filter(Boolean); // Removes empty step names
},
getArrAttributesFromString (stringAttr) {
return stringAttr ? stringAttr.split(';').map(attribute => {
const attributeArr = attribute.split(':');
getArrAttributesFromString(stringAttr) {
return stringAttr
? stringAttr.split(';').map((attribute) => {
const attributeArr = attribute.split(':');
return {
key: attributeArr.length === 1 ? null : attributeArr[0],
value: attributeArr.length === 1 ? attributeArr[0] : attributeArr[1]
};
}) : [];
},
return {
key: attributeArr.length === 1 ? null : attributeArr[0],
value: attributeArr.length === 1 ? attributeArr[0] : attributeArr[1],
};
})
: [];
},
/**
* Extract all attributes from the given array and transform its
*
* @param {Object} variables Object that contains array of postman's variables.
* @returns {Array} Array of attributes.
*/
getAttributes (variables) {
const attributes = _.find(variables.members, {
key: 'rp.attributes'
});
/**
* Extract all attributes from the given array and transform its
*
* @param {Object} variables Object that contains array of postman's variables.
* @returns {Array} Array of attributes.
*/
getAttributes(variables) {
const attributes = _.find(variables.members, {
key: 'rp.attributes',
});
return attributes ? this.getArrAttributesFromString(attributes.value) : [];
},
return attributes ? this.getArrAttributesFromString(attributes.value) : [];
},
getCollectionVariablesByKey (key, variables) {
const result = _.find(variables.members, { key: `rp.${key}` });
getCollectionVariablesByKey(key, variables) {
const result = _.find(variables.members, { key: `rp.${key}` });
return result && result.value;
},
return result && result.value;
},
getClientInitObject (options = {}) {
return {
token: options.token || options.reportportalAgentJsPostmanToken,
endpoint: options.endpoint || options.reportportalAgentJsPostmanEndpoint,
launch: options.launch || options.reportportalAgentJsPostmanLaunch || DEFAULT_LAUNCH_NAME,
project: options.project || options.reportportalAgentJsPostmanProject,
rerun: options.rerun || options.reportportalAgentJsPostmanRerun,
rerunOf: options.rerunOf || options.reportportalAgentJsPostmanRerunOf,
description: options.description || options.reportportalAgentJsPostmanDescription,
attributes: options.attributes ||
this.getArrAttributesFromString(options.reportportalAgentJsPostmanAttributes),
debug: options.debug || options.reportportalAgentJsPostmanDebug,
mode: options.mode || options.reportportalAgentJsPostmanMode,
skippedIssue: options.skippedIssue || options.reportportalAgentJsPostmanSkippedIssue,
restClientConfig: options.restClientConfig
};
},
getClientInitObject(options = {}) {
let apiKey = options.apiKey || options.reportportalAgentJsPostmanApiKey;
getStartLaunchObj (options = {}) {
const systemAttr = {
key: 'agent',
value: `${PJSON_NAME}|${PJSON_VERSION}`,
system: true
};
const attributes = options.attributes ||
this.getArrAttributesFromString(options.reportportalAgentJsPostmanAttributes);
if (!apiKey) {
apiKey = options.token || options.reportportalAgentJsPostmanToken;
if (apiKey) {
console.warn('ReportPortal warning. Option "token" is deprecated. Use "apiKey" instead.');
}
}
return {
launch: options.launch || options.reportportalAgentJsPostmanLaunch || DEFAULT_LAUNCH_NAME,
description: options.description || options.reportportalAgentJsPostmanDescription,
attributes: attributes ? attributes.concat(systemAttr) : [systemAttr],
rerun: options.rerun || options.reportportalAgentJsPostmanRerun,
rerunOf: options.rerunOf || options.reportportalAgentJsPostmanRerunOf,
mode: options.mode || options.reportportalAgentJsPostmanMode
};
},
return {
apiKey,
endpoint: options.endpoint || options.reportportalAgentJsPostmanEndpoint,
launch: options.launch || options.reportportalAgentJsPostmanLaunch,
project: options.project || options.reportportalAgentJsPostmanProject,
rerun: options.rerun || options.reportportalAgentJsPostmanRerun,
rerunOf: options.rerunOf || options.reportportalAgentJsPostmanRerunOf,
description: options.description || options.reportportalAgentJsPostmanDescription,
attributes:
options.attributes ||
this.getArrAttributesFromString(options.reportportalAgentJsPostmanAttributes),
debug: options.debug || options.reportportalAgentJsPostmanDebug,
mode: options.mode || options.reportportalAgentJsPostmanMode,
skippedIssue: options.skippedIssue || options.reportportalAgentJsPostmanSkippedIssue,
restClientConfig: options.restClientConfig,
};
},
getCollectionPath (workingDir) {
const testFileDir = path
.parse(path.normalize(path.relative(process.cwd(), workingDir)))
.dir.replace(new RegExp('\\'.concat(path.sep), 'g'), '/');
const separator = testFileDir ? '/' : '';
const testFile = path.parse(workingDir);
getStartLaunchObj(options = {}) {
const systemAttr = {
key: 'agent',
value: `${PJSON_NAME}|${PJSON_VERSION}`,
system: true,
};
const attributes =
options.attributes ||
this.getArrAttributesFromString(options.reportportalAgentJsPostmanAttributes);
return `${testFileDir}${separator}${testFile.base}`;
},
return {
description: options.description || options.reportportalAgentJsPostmanDescription,
attributes: attributes ? attributes.concat(systemAttr) : [systemAttr],
rerun: options.rerun || options.reportportalAgentJsPostmanRerun,
rerunOf: options.rerunOf || options.reportportalAgentJsPostmanRerunOf,
mode: options.mode || options.reportportalAgentJsPostmanMode,
};
},
getCodeRef (collectionPath, title) {
return `${collectionPath}/${title}`;
},
getCollectionPath(workingDir) {
const testFileDir = path
.parse(path.normalize(path.relative(process.cwd(), workingDir)))
.dir.replace(new RegExp('\\'.concat(path.sep), 'g'), '/');
const separator = testFileDir ? '/' : '';
const testFile = path.parse(workingDir);
getAgentInfo () {
return {
version: PJSON_VERSION,
name: PJSON_NAME
};
},
return `${testFileDir}${separator}${testFile.base}`;
},
getParameters (data, index) {
if (!data) {
return undefined;
}
const parameters = data[index] || data[data.length - 1];
getCodeRef(collectionPath, title) {
return `${collectionPath}/${title}`;
},
return Object.entries(parameters).map(parameter => ({
key: parameter[0],
value: parameter[1]
}));
getAgentInfo() {
return {
version: PJSON_VERSION,
name: PJSON_NAME,
};
},
getParameters(data, index) {
if (!data) {
return undefined;
}
const parameters = data[index] || data[data.length - 1];
return Object.entries(parameters).map((parameter) => ({
key: parameter[0],
value: parameter[1],
}));
},
};

@@ -190,13 +193,14 @@

*/
// eslint-disable-next-line
Array.prototype.sliceOn = function (start, condition = _.identity) {
let lastIndex;
let lastIndex;
for (let index = start; index < this.length; index++) {
if (condition(this[index])) {
lastIndex = index;
break;
}
for (let index = start; index < this.length; index++) {
if (condition(this[index])) {
lastIndex = index;
break;
}
}
return this.slice(start, lastIndex);
return this.slice(start, lastIndex);
};

@@ -212,20 +216,22 @@

*/
// eslint-disable-next-line
Array.prototype.flatMap = function (iteratee = _.identity) {
return this.map(iteratee).reduce((acc, x) => acc.concat(x), []);
return this.map(iteratee).reduce((acc, x) => acc.concat(x), []);
};
// eslint-disable-next-line
Array.prototype.groupBySpecificField = function (specificField, additionalFields) {
return this.reduce((acc, current) => {
if (current && current[specificField]) {
return acc.concat([current]);
}
Array.prototype.groupBySpecificField = function (specificField, additionalFields) {
return this.reduce((acc, current) => {
if (current && current[specificField]) {
return acc.concat([current]);
additionalFields &&
additionalFields.forEach((additionalField) => {
if (acc.length && current && current[additionalField]) {
acc[acc.length - 1] = Object.assign(acc[acc.length - 1], current);
}
});
additionalFields && additionalFields.forEach(additionalField => {
if (acc.length && current && current[additionalField]) {
acc[acc.length - 1] = Object.assign(acc[acc.length - 1], current);
}
});
return acc;
}, []);
return acc;
}, []);
};
{
"name": "@reportportal/newman-reporter-agent-js-postman",
"version": "5.0.4",
"version": "5.0.5",
"description": "ReportPortal reporter for newman",

@@ -14,3 +14,3 @@ "main": "./lib/index.js",

"dependencies": {
"@reportportal/client-javascript": "^5.0.11",
"@reportportal/client-javascript": "^5.0.13",
"lodash": "^4.17.21",

@@ -26,3 +26,9 @@ "string_decoder": "^1.3.0"

"eslint-plugin-lodash": "^7.4.0",
"jest": "^27.5.1"
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^5.0.0",
"jest": "^27.5.1",
"prettier": "^3.0.2"
},

@@ -29,0 +35,0 @@ "directories": {

@@ -27,4 +27,4 @@ # @reportportal/agent-js-postman

--reporter-@reportportal/agent-js-postman-debug=true \
--reporter-@reportportal/agent-js-postman-endpoint=http://your-instance.com:8080/api/v1 \
--reporter-@reportportal/agent-js-postman-token=00000000-0000-0000-0000-000000000000 \
--reporter-@reportportal/agent-js-postman-endpoint=https://your-instance.com:8080/api/v1 \
--reporter-@reportportal/agent-js-postman-api-key=reportportalApiKey \
--reporter-@reportportal/agent-js-postman-launch=LAUNCH_NAME \

@@ -50,4 +50,4 @@ --reporter-@reportportal/agent-js-postman-project=PROJECT_NAME \

"@reportportal/agent-js-postman": {
endpoint: "http://your-instance.com:8080/api/v1",
token: "00000000-0000-0000-0000-000000000000",
apiKey: "reportportalApiKey",
endpoint: "https://your-instance.com:8080/api/v1",
launch: "LAUNCH_NAME",

@@ -66,3 +66,3 @@ project: "PROJECT_NAME",

mode: 'DEFAULT',
debug: true
debug: false
}

@@ -93,24 +93,28 @@ }

Both CLI and programmatic runs support following options:
The full list of available options presented below.
| Parameter | Description |
| --------- | ----------------------------------------------------------------------------------------------------------------- |
| token | User's Report Portal token from which you want to send requests. It can be found on the profile page of this user. |
| endpoint | URL of your server. For example 'https://server:8080/api/v1'. |
| launch | Name of launch at creation. |
| project | The name of the project in which the launches will be created. |
| description | Text description of launch. |
| attributes | Attributes of launch.<br/> Programmatically - [{ "key": "YourKey", "value": "YourValue" }] <br/> with CLI - "YourKey:YourValue;YourValueTwo" |
| rerun | Enable [rerun](https://github.com/reportportal/documentation/blob/master/src/md/src/DevGuides/rerun.md) |
| rerunOf | UUID of launch you want to rerun. If not specified, report portal will update the latest launch with the same name. |
| debug | Determines whether newman's run should be logged in details. |
| mode | Launch mode. Allowable values *DEFAULT* (by default) or *DEBUG*.
| restClientConfig | The object with `agent` property for configure [http(s)](https://nodejs.org/api/https.html#https_https_request_url_options_callback) client, may contain other client options eg. `timeout`. |
skippedIssue | *Default: true.* ReportPortal provides feature to mark skipped tests as not 'To Investigate' items on WS side.<br> Parameter could be equal boolean values:<br> *TRUE* - skipped tests considered as issues and will be marked as 'To Investigate' on Report Portal.<br> *FALSE* - skipped tests will not be marked as 'To Investigate' on application.
| Option | Necessity | Default | Description |
|------------------|------------|-----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| apiKey | Required | | User's reportportal token from which you want to send requests. It can be found on the profile page of this user. |
| endpoint | Required | | URL of your server. For example 'https://server:8080/api/v1'. |
| launch | Required | | Name of launch at creation. |
| project | Required | | The name of the project in which the launches will be created. |
| attributes | Optional | [] | Launch attributes. Programmatically - [{ "key": "YourKey", "value": "YourValue" }] <br/> with CLI - "YourKey:YourValue;YourValueTwo" |
| description | Optional | '' | Launch description. |
| rerun | Optional | false | Enable [rerun](https://github.com/reportportal/documentation/blob/master/src/md/src/DevGuides/rerun.md) |
| rerunOf | Optional | Not set | UUID of launch you want to rerun. If not specified, reportportal will update the latest launch with the same name |
| mode | Optional | 'DEFAULT' | Results will be submitted to Launches page <br/> *'DEBUG'* - Results will be submitted to Debug page. |
| skippedIssue | Optional | true | reportportal provides feature to mark skipped tests as not 'To Investigate'. <br/> Option could be equal boolean values: <br/> *true* - skipped tests considered as issues and will be marked as 'To Investigate' on reportportal. <br/> *false* - skipped tests will not be marked as 'To Investigate' on application. |
| debug | Optional | false | This flag allows seeing the logs of the client-javascript. Useful for debugging. |
| launchId | Optional | Not set | The _ID_ of an already existing launch. The launch must be in 'IN_PROGRESS' status while the tests are running. Please note that if this _ID_ is provided, the launch will not be finished at the end of the run and must be finished separately. |
| logLaunchLink | Optional | false | This flag allows print the URL of the Launch of the tests in console. |
| restClientConfig | Optional | Not set | The object with `agent` property for configure [http(s)](https://nodejs.org/api/https.html#https_https_request_url_options_callback) client, may contain other client options eg. [`timeout`](https://github.com/reportportal/client-javascript#timeout-30000ms-on-axios-requests). <br/> Visit [client-javascript](https://github.com/reportportal/client-javascript) for more details. |
| token | Deprecated | Not set | Use `apiKey` instead. |
### Report static attributes
* To report attributes for suite you should use collection variables.
VARIABLE | INITIAL VALUE | CURRENT VALUE
--------- | ----------- | -----------
rp.attributes | keySuiteOne:valueSuiteOne | keySuiteOne:valueSuiteOne
| VARIABLE | INITIAL VALUE | CURRENT VALUE |
|---------------|---------------------------|---------------------------|
| rp.attributes | keySuiteOne:valueSuiteOne | keySuiteOne:valueSuiteOne |

@@ -121,6 +125,6 @@ * To report attributes for tests inside of Pre-request Script you should use the next method

Parameter | Required | Description | Examples
--------- | ----------- | ----------- | -----------
namespace | true | "string" - namespace, must be equal to the *rp.attributes* | "rp.attributes"
attributes | true | "string" - contains set of pairs *key:value* | "keyOne:valueOne;valueTwo;keyThree:valueThree"
| Parameter | Required | Description | Examples |
|------------|----------|------------------------------------------------------------|------------------------------------------------|
| namespace | true | "string" - namespace, must be equal to the *rp.attributes* | "rp.attributes" |
| attributes | true | "string" - contains set of pairs *key:value* | "keyOne:valueOne;valueTwo;keyThree:valueThree" |

@@ -143,5 +147,5 @@ ```javascript

VARIABLE | INITIAL VALUE | CURRENT VALUE
--------- | ----------- | -----------
rp.launchStatus (for launch)<br/>rp.status (for suite) | your status | your status
| VARIABLE | INITIAL VALUE | CURRENT VALUE |
|--------------------------------------------------------|---------------|---------------|
| rp.launchStatus (for launch)<br/>rp.status (for suite) | your status | your status |

@@ -160,6 +164,6 @@ * To finish tests you should use environment variables inside of Pre-request Script

Parameter | Required | Description | Examples
--------- | ----------- | ----------- | -----------
namespace | true | "string" - namespace, must be equal to the *rp.status* | "rp.status"
status | true | "string" - status | "passed"
| Parameter | Required | Description | Examples |
|-----------|----------|--------------------------------------------------------|-------------|
| namespace | true | "string" - namespace, must be equal to the *rp.status* | "rp.status" |
| status | true | "string" - status | "passed" |

@@ -175,6 +179,6 @@ ### Logging

Parameter | Required | Description | Examples
--------- | ----------- | ----------- | -----------
namespace | true | "string" - namespace, must be equal to the *launch, suite or test* depends on where you want to report | "test"
message | true | "string" - message | "your message"
| Parameter | Required | Description | Examples |
|-----------|----------|--------------------------------------------------------------------------------------------------------|----------------|
| namespace | true | "string" - namespace, must be equal to the *launch, suite or test* depends on where you want to report | "test" |
| message | true | "string" - message | "your message" |

@@ -186,5 +190,5 @@ * Step doesn't support logs reporting

VARIABLE | INITIAL VALUE | CURRENT VALUE
--------- | ----------- | -----------
rp.testCaseId | yourSuiteTestCaseId | yourSuiteTestCaseId
| VARIABLE | INITIAL VALUE | CURRENT VALUE |
|---------------|---------------------|---------------------|
| rp.testCaseId | yourSuiteTestCaseId | yourSuiteTestCaseId |

@@ -203,6 +207,6 @@ * To report tests with test case id you should use environment variables inside of Pre-request Script

Parameter | Required | Description | Examples
--------- | ----------- | ----------- | -----------
namespace | true | "string" - namespace, must be equal to the *rp.testCaseId* | "rp.testCaseId"
testCaseId | true | "string" - test case id value | "yourTestCaseId"
| Parameter | Required | Description | Examples |
|------------|----------|------------------------------------------------------------|------------------|
| namespace | true | "string" - namespace, must be equal to the *rp.testCaseId* | "rp.testCaseId" |
| testCaseId | true | "string" - test case id value | "yourTestCaseId" |

@@ -209,0 +213,0 @@ # Copyright Notice

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc