wdio-reportportal-reporter
Advanced tools
Comparing version 0.0.13 to 0.0.14
@@ -1,11 +0,50 @@ | ||
'use strict'; | ||
/* eslint-disable object-curly-newline */ | ||
const testItemStatuses = { PASSED: 'passed', FAILED: 'failed', SKIPPED: 'skipped' }; | ||
const logLevels = { | ||
ERROR: 'error', TRACE: 'trace', DEBUG: 'debug', INFO: 'info', WARN: 'warn' | ||
}; | ||
const events = { RP_LOG: 'rp:log', RP_FILE: 'rp:file', RP_FAILED_LOG: 'rp:failedLog', RP_FAILED_FILE: 'rp:failedFile' }; | ||
const entityType = { SUITE: 'SUITE', TEST: 'STEP' }; | ||
module.exports = { testItemStatuses, logLevels, events, entityType }; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var EVENTS; | ||
(function (EVENTS) { | ||
EVENTS["RP_LOG"] = "rp:log"; | ||
EVENTS["RP_FILE"] = "rp:file"; | ||
EVENTS["RP_TEST_LOG"] = "rp:failedLog"; | ||
EVENTS["RP_TEST_FILE"] = "rp:failedFile"; | ||
})(EVENTS = exports.EVENTS || (exports.EVENTS = {})); | ||
var STATUS; | ||
(function (STATUS) { | ||
STATUS["PASSED"] = "PASSED"; | ||
STATUS["FAILED"] = "FAILED"; | ||
STATUS["STOPPED"] = "STOPPED"; | ||
STATUS["SKIPPED"] = "SKIPPED"; | ||
STATUS["RESETED"] = "RESETED"; | ||
STATUS["CANCELLED"] = "CANCELLED"; | ||
})(STATUS = exports.STATUS || (exports.STATUS = {})); | ||
var LEVEL; | ||
(function (LEVEL) { | ||
LEVEL["ERROR"] = "ERROR"; | ||
LEVEL["TRACE"] = "TRACE"; | ||
LEVEL["DEBUG"] = "DEBUG"; | ||
LEVEL["INFO"] = "INFO"; | ||
LEVEL["WARN"] = "WARN"; | ||
LEVEL["EMPTY"] = ""; | ||
})(LEVEL = exports.LEVEL || (exports.LEVEL = {})); | ||
var TYPE; | ||
(function (TYPE) { | ||
TYPE["SUITE"] = "SUITE"; | ||
TYPE["STORY"] = "STORY"; | ||
TYPE["TEST"] = "TEST"; | ||
TYPE["SCENARIO"] = "SCENARIO"; | ||
TYPE["STEP"] = "STEP"; | ||
TYPE["BEFORE_CLASS"] = "BEFORE_CLASS"; | ||
TYPE["BEFORE_GROUPS"] = "BEFORE_GROUPS"; | ||
TYPE["BEFORE_METHOD"] = "BEFORE_METHOD"; | ||
TYPE["BEFORE_SUITE"] = "BEFORE_SUITE"; | ||
TYPE["BEFORE_TEST"] = "BEFORE_TEST"; | ||
TYPE["AFTER_CLASS"] = "AFTER_CLASS"; | ||
TYPE["AFTER_GROUPS"] = "AFTER_GROUPS"; | ||
TYPE["AFTER_METHOD"] = "AFTER_METHOD"; | ||
TYPE["AFTER_SUITE"] = "AFTER_SUITE"; | ||
TYPE["AFTER_TEST"] = "AFTER_TEST"; | ||
})(TYPE = exports.TYPE || (exports.TYPE = {})); | ||
var MODE; | ||
(function (MODE) { | ||
MODE["DEFAULT"] = "DEFAULT"; | ||
MODE["DEBUG"] = "DEBUG"; | ||
})(MODE = exports.MODE || (exports.MODE = {})); |
@@ -1,353 +0,316 @@ | ||
'use strict'; | ||
var _promise = require('babel-runtime/core-js/promise'); | ||
var _promise2 = _interopRequireDefault(_promise); | ||
var _stringify = require('babel-runtime/core-js/json/stringify'); | ||
var _stringify2 = _interopRequireDefault(_stringify); | ||
var _assign = require('babel-runtime/core-js/object/assign'); | ||
var _assign2 = _interopRequireDefault(_assign); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
/* eslint-disable object-curly-newline */ | ||
const { EventEmitter } = require('events'); | ||
const ReportPortalClient = require('reportportal-client'); | ||
const { testItemStatuses, events, entityType } = require('./constants'); | ||
const { promiseErrorHandler, Logger, isEmpty, limit, sendToReporter } = require('./utils'); | ||
const { PASSED, FAILED, SKIPPED } = testItemStatuses; | ||
class ReportPortalReporter extends EventEmitter { | ||
constructor(baseReporter, config, options = {}) { | ||
super(); | ||
this.parents = {}; | ||
this.logger = new Logger(options.debug); | ||
this.testStartRequestsPromises = {}; | ||
this.lastFailedTestRequestPromises = {}; | ||
this.config = config; | ||
this.options = (0, _assign2.default)({ | ||
enableSeleniumCommandReporting: false, | ||
seleniumCommandsLogLevel: 'debug', | ||
enableScreenshotsReporting: false, | ||
screenshotsLogLevel: 'info', | ||
enableRetriesWorkaround: false, | ||
debug: false | ||
}, options); | ||
this.client = new ReportPortalClient(options.rpConfig); | ||
const { tempId, promise } = this.client.startLaunch({ mode: options.rpConfig.mode || 'DEFAULT' }); | ||
promiseErrorHandler(promise); | ||
this.tempLaunchId = tempId; | ||
// Test framework events | ||
this.on('suite:start', this.suiteStart.bind(this)); | ||
this.on('suite:end', this.suiteEnd.bind(this)); | ||
this.on('test:start', this.testStart.bind(this)); | ||
this.on('test:pass', this.testPass.bind(this)); | ||
this.on('test:fail', this.testFail.bind(this)); | ||
this.on('test:pending', this.testPending.bind(this)); | ||
this.on('start', this.start.bind(this)); | ||
this.on('runner:command', this.runnerCommand.bind(this)); | ||
this.on('runner:result', this.runnerResult.bind(this)); | ||
// Rp events | ||
this.on(events.RP_LOG, this.sendLog.bind(this)); | ||
this.on(events.RP_FILE, this.sendFile.bind(this)); | ||
this.on(events.RP_FAILED_LOG, this.sendLogToLastFailedItem.bind(this)); | ||
this.on(events.RP_FAILED_FILE, this.sendFileToLastFailedItem.bind(this)); | ||
const { epilogue } = baseReporter; | ||
this.on('end', async () => { | ||
const { promise: finishLaunchPromise } = this.client.finishLaunch(this.tempLaunchId, {}); | ||
promiseErrorHandler(finishLaunchPromise); | ||
await finishLaunchPromise; | ||
epilogue.call(baseReporter); | ||
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
} | ||
getParent(cid) { | ||
const parents = this.getParentIds(cid); | ||
if (!parents.length) { | ||
return null; | ||
}; | ||
const events_1 = require("events"); | ||
const ReportPortalClient = require("reportportal-client"); | ||
const constants_1 = require("./constants"); | ||
const ReporterOptions_1 = require("./ReporterOptions"); | ||
const utils_1 = require("./utils"); | ||
class ReportPortalReporter extends events_1.EventEmitter { | ||
constructor(baseReporter, config, options) { | ||
super(); | ||
this.parents = {}; | ||
this.startedTests = {}; | ||
this.baseReporter = baseReporter; | ||
this.logger = new utils_1.Logger(options.debug); | ||
this.config = config; | ||
this.options = Object.assign(new ReporterOptions_1.default(), options); | ||
// Test framework events | ||
this.on("suite:start", this.suiteStart.bind(this)); | ||
this.on("suite:end", this.suiteEnd.bind(this)); | ||
this.on("test:start", this.testStart.bind(this)); | ||
this.on("test:pass", this.testPass.bind(this)); | ||
this.on("test:fail", this.testFail.bind(this)); | ||
this.on("test:pending", this.testPending.bind(this)); | ||
this.on("start", this.start.bind(this)); | ||
this.on("end", this.end.bind(this)); | ||
this.on("runner:command", this.runnerCommand.bind(this)); | ||
this.on("runner:result", this.runnerResult.bind(this)); | ||
this.on("runner:end", this.runnerEnd.bind(this)); | ||
// Rp events | ||
this.on(constants_1.EVENTS.RP_LOG, this.sendLog.bind(this)); | ||
this.on(constants_1.EVENTS.RP_FILE, this.sendFile.bind(this)); | ||
this.on(constants_1.EVENTS.RP_TEST_LOG, this.sendLogToTest.bind(this)); | ||
this.on(constants_1.EVENTS.RP_TEST_FILE, this.sendFileToTest.bind(this)); | ||
} | ||
return parents[parents.length - 1]; | ||
} | ||
addParent(cid, parent) { | ||
const parents = this.getParentIds(cid); | ||
parents.push(parent); | ||
} | ||
clearParent(cid) { | ||
const parents = this.getParentIds(cid); | ||
parents.pop(); | ||
} | ||
suiteStart(suite) { | ||
const suiteStartObj = { type: entityType.SUITE, name: suite.title }; | ||
if (suite.tags && suite.tags.length > 0) { | ||
// check is it at least cucumber v1 | ||
if (suite.tags[0].name) { | ||
suiteStartObj.tags = suite.tags.map(tag => tag.name); | ||
} else { | ||
suiteStartObj.tags = suite.tags; | ||
} | ||
static sendLog(level, message) { | ||
utils_1.sendToReporter(constants_1.EVENTS.RP_LOG, { level, message }); | ||
} | ||
if (suite.description) { | ||
suiteStartObj.description = suite.description; | ||
static sendFile(level, name, content, type = "image/png") { | ||
utils_1.sendToReporter(constants_1.EVENTS.RP_FILE, { level, name, content, type }); | ||
} | ||
const parent = this.getParent(suite.cid) || {}; | ||
const { tempId, promise } = this.client.startTestItem(suiteStartObj, this.tempLaunchId, parent.id); | ||
promiseErrorHandler(promise); | ||
this.addParent(suite.cid, { type: entityType.SUITE, id: tempId, promise }); | ||
} | ||
suiteEnd(suite) { | ||
const parent = this.getParent(suite.cid); | ||
const { promise } = this.client.finishTestItem(parent.id, {}); | ||
promiseErrorHandler(promise); | ||
this.clearParent(suite.cid); | ||
} | ||
testStart(test) { | ||
if (!test.title) { | ||
return; | ||
static sendLogToTest(test, level, message) { | ||
utils_1.sendToReporter(constants_1.EVENTS.RP_TEST_LOG, { test, level, message }); | ||
} | ||
const parent = this.getParent(test.cid); | ||
if (parent.type === entityType.TEST && this.options.enableRetriesWorkaround) { | ||
return; | ||
static sendFileToTest(test, level, name, content, type = "image/png") { | ||
utils_1.sendToReporter(constants_1.EVENTS.RP_TEST_FILE, { test, level, name, content, type }); | ||
} | ||
const testStartObj = { type: entityType.TEST, name: test.title }; | ||
const browser = test.runner[test.cid].browserName; | ||
if (browser) { | ||
const param = { key: 'browser', value: browser }; | ||
testStartObj.parameters = [param]; | ||
getParent(cid) { | ||
const parents = this.getParentIds(cid); | ||
if (!parents.length) { | ||
return null; | ||
} | ||
return parents[parents.length - 1]; | ||
} | ||
const { tempId, promise } = this.client.startTestItem(testStartObj, this.tempLaunchId, parent.id); | ||
promiseErrorHandler(promise); | ||
this.testStartRequestsPromises[test.cid] = promise; | ||
this.addParent(test.cid, { type: entityType.TEST, id: tempId, promise }); | ||
} | ||
testPass(test) { | ||
this.testFinished(test, PASSED); | ||
} | ||
testFail(test) { | ||
this.testFinished(test, FAILED); | ||
} | ||
testPending(test) { | ||
const parent = this.getParent(test.cid); | ||
if (parent && parent.type === entityType.SUITE) { | ||
this.testStart(test); | ||
addParent(cid, parent) { | ||
const parents = this.getParentIds(cid); | ||
parents.push(parent); | ||
} | ||
this.testFinished(test, SKIPPED, { issue_type: 'NOT_ISSUE' }); | ||
} | ||
testFinished(test, status, issue) { | ||
const parent = this.getParent(test.cid); | ||
if (parent && parent.type !== entityType.TEST) { | ||
return; | ||
clearParent(cid) { | ||
const parents = this.getParentIds(cid); | ||
parents.pop(); | ||
} | ||
const finishTestObj = { status, issue }; | ||
if (status === FAILED) { | ||
const level = 'ERROR'; | ||
let message = `Message: ${test.err.message}\n`; | ||
message += `Stacktrace: ${test.err.stack}\n`; | ||
finishTestObj.description = `${test.file}\n\`\`\`error\n${message}\n\`\`\``; | ||
this.client.sendLog(parent.id, { | ||
message, | ||
level | ||
}); | ||
suiteStart(suite) { | ||
const suiteStartObj = new SuiteStartObj(suite.title); | ||
if (suite.tags && suite.tags.length > 0) { | ||
// check is it at least cucumber v1 | ||
if (suite.tags[0].name) { | ||
suiteStartObj.tags = suite.tags.map((tag) => tag.name); | ||
} | ||
else { | ||
suiteStartObj.tags = suite.tags; | ||
} | ||
} | ||
if (suite.description) { | ||
suiteStartObj.description = suite.description; | ||
} | ||
const parent = this.getParent(suite.cid) || {}; | ||
const { tempId, promise } = this.client.startTestItem(suiteStartObj, this.tempLaunchId, parent.id); | ||
utils_1.promiseErrorHandler(promise); | ||
this.addParent(suite.cid, { type: constants_1.TYPE.SUITE, id: tempId, promise }); | ||
if (!this.startedTests[suite.cid]) { | ||
this.startedTests[suite.cid] = []; | ||
} | ||
} | ||
const { promise } = this.client.finishTestItem(parent.id, finishTestObj); | ||
promiseErrorHandler(promise); | ||
if (status === FAILED) { | ||
this.lastFailedTestRequestPromises[test.cid] = this.testStartRequestsPromises[test.cid]; | ||
suiteEnd(suite) { | ||
const parent = this.getParent(suite.cid); | ||
const { promise } = this.client.finishTestItem(parent.id, {}); | ||
utils_1.promiseErrorHandler(promise); | ||
this.clearParent(suite.cid); | ||
} | ||
this.clearParent(test.cid); | ||
delete this.testStartRequestsPromises[test.cid]; | ||
} | ||
runnerCommand(command) { | ||
if (!this.options.enableSeleniumCommandReporting || this.isMultiremote) { | ||
return; | ||
testStart(test) { | ||
if (!test.title) { | ||
return; | ||
} | ||
const parent = this.getParent(test.cid); | ||
if (parent.type === constants_1.TYPE.STEP && this.options.enableRetriesWorkaround) { | ||
return; | ||
} | ||
const testStartObj = new TestStartObj(test.title); | ||
const browser = test.runner[test.cid].browserName; | ||
if (browser) { | ||
const param = { key: "browser", value: browser }; | ||
testStartObj.parameters = [param]; | ||
} | ||
if (this.options.parseTagsFromTestTitle) { | ||
const tags = utils_1.parseTags(test.title); | ||
if (tags.length > 0) { | ||
testStartObj.tags = tags; | ||
} | ||
} | ||
const { tempId, promise } = this.client.startTestItem(testStartObj, this.tempLaunchId, parent.id); | ||
utils_1.promiseErrorHandler(promise); | ||
this.addParent(test.cid, { type: constants_1.TYPE.STEP, id: tempId, promise }); | ||
this.startedTests[test.cid].push({ test, promise }); | ||
return promise; | ||
} | ||
const parent = this.getParent(command.cid); | ||
if (!parent) { | ||
return; | ||
testPass(test) { | ||
this.testFinished(test, constants_1.STATUS.PASSED); | ||
} | ||
const method = `${command.method} ${command.uri.path}`; | ||
if (!isEmpty(command.data)) { | ||
const data = (0, _stringify2.default)(limit(command.data)); | ||
this.sendLog({ cid: command.cid, level: this.options.seleniumCommandsLogLevel, message: `${method}\n${data}` }); | ||
} else { | ||
this.sendLog({ cid: command.cid, level: this.options.seleniumCommandsLogLevel, message: `${method}` }); | ||
testFail(test) { | ||
this.testFinished(test, constants_1.STATUS.FAILED); | ||
} | ||
} | ||
start(event) { | ||
this.isMultiremote = event.isMultiremote; | ||
} | ||
runnerResult(command) { | ||
if (this.isMultiremote) { | ||
return; | ||
testPending(test) { | ||
const parent = this.getParent(test.cid); | ||
if (parent && parent.type === constants_1.TYPE.SUITE) { | ||
this.testStart(test); | ||
} | ||
this.testFinished(test, constants_1.STATUS.SKIPPED, new Issue("NOT_ISSUE")); | ||
} | ||
const parent = this.getParent(command.cid); | ||
if (!parent) { | ||
return; | ||
testFinished(test, status, issue) { | ||
const parent = this.getParent(test.cid); | ||
if (parent && parent.type !== constants_1.TYPE.STEP) { | ||
return; | ||
} | ||
const finishTestObj = new TestEndObj(status, issue); | ||
if (status === constants_1.STATUS.FAILED) { | ||
let message = `Message: ${test.err.message}\n`; | ||
message += `Stacktrace: ${test.err.stack}\n`; | ||
finishTestObj.description = `${test.file}\n\`\`\`error\n${message}\n\`\`\``; | ||
this.client.sendLog(parent.id, { | ||
level: constants_1.LEVEL.ERROR, | ||
message, | ||
}); | ||
} | ||
const { promise } = this.client.finishTestItem(parent.id, finishTestObj); | ||
utils_1.promiseErrorHandler(promise); | ||
this.clearParent(test.cid); | ||
} | ||
const isScreenshot = command.requestOptions.uri.path.match(/\/session\/[^/]*\/screenshot/) && command.body.value; | ||
if (isScreenshot) { | ||
if (this.options.enableScreenshotsReporting) { | ||
const obj = { | ||
cid: command.cid, | ||
level: this.options.screenshotsLogLevel, | ||
name: 'screenshot.png', | ||
content: command.body.value | ||
}; | ||
this.sendFile(obj); | ||
} | ||
runnerCommand(command) { | ||
if (!this.options.enableSeleniumCommandReporting || this.isMultiremote) { | ||
return; | ||
} | ||
const parent = this.getParent(command.cid); | ||
if (!parent) { | ||
return; | ||
} | ||
const method = `${command.method} ${command.uri.path}`; | ||
if (!utils_1.isEmpty(command.data)) { | ||
const data = JSON.stringify(utils_1.limit(command.data)); | ||
this.sendLog({ cid: command.cid, level: this.options.seleniumCommandsLogLevel, message: `${method}\n${data}` }); | ||
} | ||
else { | ||
this.sendLog({ cid: command.cid, level: this.options.seleniumCommandsLogLevel, message: `${method}` }); | ||
} | ||
} | ||
if (this.options.enableSeleniumCommandReporting) { | ||
if (command.body && !isEmpty(command.body.value)) { | ||
const method = `${command.requestOptions.uri.path}`; | ||
// eslint-disable-next-line no-param-reassign | ||
delete command.body.sessionId; | ||
const data = (0, _stringify2.default)(limit(command.body)); | ||
this.sendLog({ cid: command.cid, level: this.options.seleniumCommandsLogLevel, message: `${method}\n${data}` }); | ||
} | ||
start(event, client) { | ||
this.isMultiremote = event.isMultiremote; | ||
this.client = client || new ReportPortalClient(this.options.rpConfig); | ||
const { tempId, promise } = this.client.startLaunch({ mode: this.options.rpConfig.mode }); | ||
utils_1.promiseErrorHandler(promise); | ||
this.tempLaunchId = tempId; | ||
} | ||
} | ||
async sendLogToLastFailedItem({ cid, level, message }) { | ||
if (!(await this.waitForFailedTest(cid, 2000, 10))) { | ||
this.logger.warn('Attempt to send file to failed item fails. There is no failed test yet.'); | ||
return; | ||
end() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { promise: finishLaunchPromise } = this.client.finishLaunch(this.tempLaunchId, {}); | ||
utils_1.promiseErrorHandler(finishLaunchPromise); | ||
yield finishLaunchPromise; | ||
this.baseReporter.epilogue.call(this.baseReporter); | ||
}); | ||
} | ||
const rs = await this.lastFailedTestRequestPromises[cid]; | ||
const saveLogRQ = { | ||
item_id: rs.id, | ||
level, | ||
message, | ||
time: this.client.helpers.now() | ||
}; | ||
const url = [this.client.baseURL, 'log'].join('/'); | ||
const promise = this.client.helpers.getServerResult(url, saveLogRQ, { headers: this.client.headers }, 'POST'); | ||
promiseErrorHandler(promise); | ||
} | ||
// eslint-disable-next-line object-curly-newline | ||
async sendFileToLastFailedItem({ cid, level, name, content, type = 'image/png' }) { | ||
if (!(await this.waitForFailedTest(cid, 2000, 10))) { | ||
this.logger.warn('Attempt to send log to failed item fails. There is no failed test yet.'); | ||
return; | ||
runnerResult(command) { | ||
if (this.isMultiremote) { | ||
return; | ||
} | ||
const parent = this.getParent(command.cid); | ||
if (!parent) { | ||
return; | ||
} | ||
const isScreenshot = command.requestOptions.uri.path.match(/\/session\/[^/]*\/screenshot/) && command.body.value; | ||
if (isScreenshot) { | ||
if (this.options.enableScreenshotsReporting) { | ||
const obj = { | ||
cid: command.cid, | ||
content: command.body.value, | ||
level: this.options.screenshotsLogLevel, | ||
name: "screenshot.png", | ||
}; | ||
this.sendFile(obj); | ||
} | ||
} | ||
if (this.options.enableSeleniumCommandReporting) { | ||
if (command.body && !utils_1.isEmpty(command.body.value)) { | ||
const method = `${command.requestOptions.uri.path}`; | ||
delete command.body.sessionId; | ||
const data = JSON.stringify(utils_1.limit(command.body)); | ||
this.sendLog({ cid: command.cid, level: this.options.seleniumCommandsLogLevel, message: `${method}\n${data}` }); | ||
} | ||
} | ||
} | ||
const rs = await this.lastFailedTestRequestPromises[cid]; | ||
const saveLogRQ = { | ||
item_id: rs.id, | ||
level, | ||
message: '', | ||
time: this.client.helpers.now() | ||
}; | ||
const promise = this.client.getRequestLogWithFile(saveLogRQ, { name, content, type }); | ||
promiseErrorHandler(promise); | ||
} | ||
sendLog({ cid, level, message }) { | ||
const parent = this.getParent(cid); | ||
if (!parent) { | ||
return; | ||
runnerEnd(runner) { | ||
delete this.startedTests[runner.cid]; | ||
} | ||
const { promise } = this.client.sendLog(parent.id, { | ||
message: String(message), | ||
level | ||
}); | ||
promiseErrorHandler(promise); | ||
} | ||
// eslint-disable-next-line object-curly-newline | ||
sendFile({ cid, level, name, content, type = 'image/png' }) { | ||
const parent = this.getParent(cid); | ||
if (!parent) { | ||
return; | ||
sendLogToTest({ cid, test, level, message }) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const failedTest = this.startedTests[cid].find(({ test: startedTest }) => { | ||
return startedTest.title === test.title; | ||
}); | ||
if (!failedTest) { | ||
this.logger.warn(`Can not send log to test ${test.title}`); | ||
return; | ||
} | ||
const rs = yield failedTest.promise; | ||
const saveLogRQ = { | ||
item_id: rs.id, | ||
level, | ||
message, | ||
time: this.client.helpers.now(), | ||
}; | ||
const url = [this.client.baseURL, "log"].join("/"); | ||
const promise = this.client.helpers.getServerResult(url, saveLogRQ, { headers: this.client.headers }, "POST"); | ||
utils_1.promiseErrorHandler(promise); | ||
}); | ||
} | ||
const { promise } = this.client.sendLog(parent.id, { level }, { name, content, type }); | ||
promiseErrorHandler(promise); | ||
} | ||
getParentIds(cid) { | ||
if (this.parents[cid]) { | ||
return this.parents[cid]; | ||
sendFileToTest({ cid, test, level, name, content, type = "image/png" }) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const failedTest = this.startedTests[cid].find(({ test: startedTest }) => { | ||
return startedTest.title === test.title; | ||
}); | ||
if (!failedTest) { | ||
this.logger.warn(`Can not send file to test ${test.title}`); | ||
return; | ||
} | ||
const rs = yield failedTest.promise; | ||
const saveLogRQ = { | ||
item_id: rs.id, | ||
level, | ||
message: "", | ||
time: this.client.helpers.now(), | ||
}; | ||
const promise = this.client.getRequestLogWithFile(saveLogRQ, { name, content, type }); | ||
utils_1.promiseErrorHandler(promise); | ||
}); | ||
} | ||
this.parents[cid] = []; | ||
return this.parents[cid]; | ||
} | ||
async waitForFailedTest(cid, time, count = 10) { | ||
const interval = time / count; | ||
while (count > 0) { | ||
if (this.lastFailedTestRequestPromises[cid]) { | ||
return true; | ||
} | ||
// eslint-disable-next-line no-await-in-loop | ||
await new _promise2.default(resolve => setTimeout(resolve, interval)); | ||
// eslint-disable-next-line no-param-reassign | ||
count -= 1; | ||
sendLog({ cid, level, message }) { | ||
const parent = this.getParent(cid); | ||
if (!parent) { | ||
this.logger.warn(`Can not send log to test. There is no running tests`); | ||
return; | ||
} | ||
const { promise } = this.client.sendLog(parent.id, { | ||
level, | ||
message: String(message), | ||
}); | ||
utils_1.promiseErrorHandler(promise); | ||
} | ||
return false; | ||
} | ||
static sendLog(level, message) { | ||
sendToReporter(events.RP_LOG, { level, message }); | ||
} | ||
static sendFile(level, name, content, type = 'image/png') { | ||
// eslint-disable-next-line object-curly-newline | ||
sendToReporter(events.RP_FILE, { level, name, content, type }); | ||
} | ||
static sendLogToLastFailedTest(level, message) { | ||
sendToReporter(events.RP_FAILED_LOG, { level, message }); | ||
} | ||
static sendFileToLastFailedTest(level, name, content, type = 'image/png') { | ||
// eslint-disable-next-line object-curly-newline | ||
sendToReporter(events.RP_FAILED_FILE, { level, name, content, type }); | ||
} | ||
sendFile({ cid, level, name, content, type = "image/png" }) { | ||
const parent = this.getParent(cid); | ||
if (!parent) { | ||
this.logger.warn(`Can not send file to test. There is no running tests`); | ||
return; | ||
} | ||
const { promise } = this.client.sendLog(parent.id, { level }, { name, content, type }); | ||
utils_1.promiseErrorHandler(promise); | ||
} | ||
getParentIds(cid) { | ||
if (this.parents[cid]) { | ||
return this.parents[cid]; | ||
} | ||
this.parents[cid] = []; | ||
return this.parents[cid]; | ||
} | ||
} | ||
ReportPortalReporter.reporterName = 'reportportal'; | ||
module.exports = ReportPortalReporter; | ||
ReportPortalReporter.reporterName = "reportportal"; | ||
class SuiteStartObj { | ||
constructor(name) { | ||
this.name = ""; | ||
this.type = constants_1.TYPE.SUITE; | ||
this.name = name; | ||
} | ||
} | ||
class TestStartObj { | ||
constructor(name) { | ||
this.name = ""; | ||
this.type = constants_1.TYPE.STEP; | ||
this.name = name; | ||
} | ||
} | ||
class TestEndObj { | ||
constructor(status, issue = new Issue("NOT_ISSUE")) { | ||
this.status = status; | ||
this.issue = issue; | ||
} | ||
} | ||
class Issue { | ||
// tslint:disable-next-line | ||
constructor(issue_type) { | ||
this.issue_type = issue_type; | ||
} | ||
} | ||
module.exports = ReportPortalReporter; |
@@ -1,20 +0,4 @@ | ||
'use strict'; | ||
var _assign = require('babel-runtime/core-js/object/assign'); | ||
var _assign2 = _interopRequireDefault(_assign); | ||
var _stringify = require('babel-runtime/core-js/json/stringify'); | ||
var _stringify2 = _interopRequireDefault(_stringify); | ||
var _keys = require('babel-runtime/core-js/object/keys'); | ||
var _keys2 = _interopRequireDefault(_keys); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
/* eslint-disable no-console,no-param-reassign,class-methods-use-this */ | ||
const stringify = require('json-stringify-safe'); | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const stringify = require("json-stringify-safe"); | ||
const OBJLENGTH = 10; | ||
@@ -25,46 +9,44 @@ const ARRLENGTH = 10; | ||
const notBase64 = /[^A-Z0-9+/=]/i; | ||
const TAGS_PATTERN = /\B@[a-z0-9_-]+/gi; | ||
class Logger { | ||
constructor(debug = false) { | ||
this.debug = debug; | ||
} | ||
info(msg) { | ||
console.log(msg); | ||
} | ||
error(msg) { | ||
console.error(msg); | ||
} | ||
warn(msg) { | ||
if (this.debug) { | ||
console.warn(msg); | ||
constructor(debug = false) { | ||
this.debug = false; | ||
this.debug = debug; | ||
} | ||
} | ||
info(msg) { | ||
// tslint:disable-next-line | ||
console.log(msg); | ||
} | ||
error(msg) { | ||
// tslint:disable-next-line | ||
console.error(msg); | ||
} | ||
warn(msg) { | ||
if (this.debug) { | ||
// tslint:disable-next-line | ||
console.warn(msg); | ||
} | ||
} | ||
} | ||
exports.Logger = Logger; | ||
const logger = new Logger(); | ||
const promiseErrorHandler = promise => { | ||
promise.catch(err => { | ||
logger.error(err); | ||
}); | ||
exports.promiseErrorHandler = (promise) => { | ||
promise.catch((err) => { | ||
logger.error(err); | ||
}); | ||
}; | ||
const isEmpty = object => !object || (0, _keys2.default)(object).length === 0; | ||
const isBase64 = str => { | ||
if (typeof str !== 'string') { | ||
return false; | ||
} | ||
const len = str.length; | ||
if (!len || len % 4 !== 0 || notBase64.test(str)) { | ||
return false; | ||
} | ||
const firstPaddingChar = str.indexOf('='); | ||
return firstPaddingChar === -1 || firstPaddingChar === len - 1 || firstPaddingChar === len - 2 && str[len - 1] === '='; | ||
exports.isEmpty = (object) => !object || Object.keys(object).length === 0; | ||
const isBase64 = (str) => { | ||
if (typeof str !== "string") { | ||
return false; | ||
} | ||
const len = str.length; | ||
if (!len || len % 4 !== 0 || notBase64.test(str)) { | ||
return false; | ||
} | ||
const firstPaddingChar = str.indexOf("="); | ||
return firstPaddingChar === -1 || | ||
firstPaddingChar === len - 1 || | ||
(firstPaddingChar === len - 2 && str[len - 1] === "="); | ||
}; | ||
/** | ||
@@ -75,57 +57,50 @@ * Limit the length of an arbitrary variable of any type, suitable for being logged or displayed | ||
*/ | ||
const limit = val => { | ||
if (!val) return val; | ||
// Ensure we're working with a copy | ||
let value = JSON.parse(stringify(val)); | ||
switch (Object.prototype.toString.call(value)) { | ||
case '[object String]': | ||
if (value.length > 100 && isBase64(value)) { | ||
return `[base64] ${value.length} bytes`; | ||
} | ||
if (value.length > STRINGLIMIT) { | ||
return `${value.substr(0, STRINGTRUNCATE)} ... (${value.length - STRINGTRUNCATE} more bytes)`; | ||
} | ||
return value; | ||
case '[object Array]': | ||
{ | ||
const { length } = value; | ||
if (length > ARRLENGTH) { | ||
value = value.slice(0, ARRLENGTH); | ||
value.push(`(${length - ARRLENGTH} more items)`); | ||
exports.limit = (val) => { | ||
if (!val) { | ||
return val; | ||
} | ||
// Ensure we're working with a copy | ||
let value = JSON.parse(stringify(val)); | ||
switch (Object.prototype.toString.call(value)) { | ||
case "[object String]": | ||
if (value.length > 100 && isBase64(value)) { | ||
return `[base64] ${value.length} bytes`; | ||
} | ||
if (value.length > STRINGLIMIT) { | ||
return `${value.substr(0, STRINGTRUNCATE)} ... (${value.length - STRINGTRUNCATE} more bytes)`; | ||
} | ||
return value; | ||
case "[object Array]": { | ||
const { length } = value; | ||
if (length > ARRLENGTH) { | ||
value = value.slice(0, ARRLENGTH); | ||
value.push(`(${length - ARRLENGTH} more items)`); | ||
} | ||
return value.map(exports.limit); | ||
} | ||
return value.map(limit); | ||
} | ||
case '[object Object]': | ||
{ | ||
const keys = (0, _keys2.default)(value); | ||
const removed = []; | ||
for (let i = 0, l = keys.length; i < l; i += 1) { | ||
if (i < OBJLENGTH) { | ||
value[keys[i]] = limit(value[keys[i]]); | ||
} else { | ||
delete value[keys[i]]; | ||
removed.push(keys[i]); | ||
} | ||
case "[object Object]": { | ||
const keys = Object.keys(value); | ||
const removed = []; | ||
for (let i = 0, l = keys.length; i < l; i += 1) { | ||
if (i < OBJLENGTH) { | ||
value[keys[i]] = exports.limit(value[keys[i]]); | ||
} | ||
else { | ||
delete value[keys[i]]; | ||
removed.push(keys[i]); | ||
} | ||
} | ||
if (removed.length) { | ||
value._ = `${keys.length - OBJLENGTH} more keys: ${JSON.stringify(removed)}`; | ||
} | ||
return value; | ||
} | ||
if (removed.length) { | ||
value._ = `${keys.length - OBJLENGTH} more keys: ${(0, _stringify2.default)(removed)}`; | ||
default: { | ||
return value; | ||
} | ||
return value; | ||
} | ||
default: | ||
{ | ||
return value; | ||
} | ||
} | ||
} | ||
}; | ||
const sendToReporter = (event, msg = {}) => { | ||
process.send((0, _assign2.default)({ event }, msg)); | ||
exports.parseTags = (text) => text.match(TAGS_PATTERN) || []; | ||
exports.sendToReporter = (event, msg = {}) => { | ||
process.send(Object.assign({ event }, msg)); | ||
}; | ||
module.exports = { | ||
promiseErrorHandler, Logger, isEmpty, limit, sendToReporter | ||
}; |
134
package.json
{ | ||
"name": "wdio-reportportal-reporter", | ||
"version": "0.0.13", | ||
"description": "A WebdriverIO plugin. Report results to Report Portal.", | ||
"main": "build/reporter.js", | ||
"scripts": { | ||
"build": "run-s clean compile", | ||
"clean": "rimraf ./build ./coverage", | ||
"compile": "babel lib/ -d build/", | ||
"eslint": "eslint ./lib", | ||
"test": "run-s eslint test:unit", | ||
"test:unit": "mocha" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/borisosipov/wdio-reportportal-reporter.git" | ||
}, | ||
"directories": { | ||
"lib": "./lib" | ||
}, | ||
"keywords": [ | ||
"reporter", | ||
"webdriverio", | ||
"wdio", | ||
"wdio-plugin", | ||
"wdio-reporter", | ||
"reportportal" | ||
"name": "wdio-reportportal-reporter", | ||
"version": "0.0.14", | ||
"description": "A WebdriverIO plugin. Report results to Report Portal.", | ||
"main": "build/reporter.js", | ||
"scripts": { | ||
"build": "run-s clean compile", | ||
"clean": "rimraf ./build ./coverage", | ||
"compile": "node ./node_modules/typescript/lib/tsc.js", | ||
"lint": "tslint -c tslint.json 'lib/**/*.{ts,tsx}'", | ||
"test": "run-s lint test:unit", | ||
"test:integration": "mocha", | ||
"test:unit": "jest" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/borisosipov/wdio-reportportal-reporter.git" | ||
}, | ||
"directories": { | ||
"lib": "./lib" | ||
}, | ||
"keywords": [ | ||
"reporter", | ||
"webdriverio", | ||
"wdio", | ||
"wdio-plugin", | ||
"wdio-reporter", | ||
"reportportal" | ||
], | ||
"author": "Boris Osipov <osipov.boris@gmail.com>", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/borisosipov/wdio-reportportal-reporter/issues" | ||
}, | ||
"homepage": "https://github.com/borisosipov/wdio-reportportal-reporter#readme", | ||
"dependencies": { | ||
"json-stringify-safe": "~5.0.1", | ||
"reportportal-client": "https://github.com/reportportal/client-javascript.git#b09e49b" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^23.3.3", | ||
"jest": "^23.6.0", | ||
"ts-jest": "^23.10.4", | ||
"@types/chai": "4.1.6", | ||
"@types/cucumber": "^4.0.4", | ||
"@types/mocha": "5.2.5", | ||
"@types/webdriverio": "^4.10.4", | ||
"chai": "^4.1.2", | ||
"mocha": "^5.2.0", | ||
"npm-run-all": "~4.1.0", | ||
"rimraf": "^2.6.2", | ||
"wdio-cucumber-framework": "^2.2.7", | ||
"wdio-mocha-framework": "^0.6.3", | ||
"webdriverio": "^4.12.0", | ||
"ts-node": "7.0.1", | ||
"tslint": "^5.11.0", | ||
"typescript": "3.1.3" | ||
}, | ||
"contributors": [ | ||
"Boris Osipov <osipov.boris@gmail.com>" | ||
], | ||
"jest": { | ||
"moduleFileExtensions": [ | ||
"ts", | ||
"tsx", | ||
"js", | ||
"jsx" | ||
], | ||
"author": "Boris Osipov <osipov.boris@gmail.com>", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/borisosipov/wdio-reportportal-reporter/issues" | ||
"transform": { | ||
"\\.(ts|tsx)$": "ts-jest" | ||
}, | ||
"homepage": "https://github.com/borisosipov/wdio-reportportal-reporter#readme", | ||
"dependencies": { | ||
"babel-runtime": "^6.26.0", | ||
"json-stringify-safe": "~5.0.1", | ||
"reportportal-client": "https://github.com/reportportal/client-javascript.git#b09e49b" | ||
}, | ||
"devDependencies": { | ||
"babel-cli": "^6.26.0", | ||
"babel-eslint": "^8.2.2", | ||
"babel-plugin-add-module-exports": "~0.2.1", | ||
"babel-plugin-transform-function-bind": "^6.22.0", | ||
"babel-plugin-transform-object-rest-spread": "^6.26.0", | ||
"babel-plugin-transform-runtime": "~6.23.0", | ||
"babel-preset-env": "^1.6.1", | ||
"babel-register": "^6.26.0", | ||
"chai": "^4.1.2", | ||
"eslint": "^4.19.0", | ||
"eslint-config-airbnb-base": "^12.1.0", | ||
"eslint-plugin-import": "^2.9.0", | ||
"eslint-plugin-mocha": "^5.0.0", | ||
"eslint-plugin-node": "^5.2.1", | ||
"mocha": "^5.2.0", | ||
"node-static": "^0.7.10", | ||
"npm-run-all": "~4.1.0", | ||
"rimraf": "^2.6.2", | ||
"server-destroy": "^1.0.1", | ||
"wdio-cucumber-framework": "^2.2.7", | ||
"wdio-mocha-framework": "^0.6.3", | ||
"wdio-phantomjs-service": "^0.2.2", | ||
"webdriverio": "^4.12.0" | ||
}, | ||
"contributors": [ | ||
"Boris Osipov <osipov.boris@gmail.com>" | ||
] | ||
"testRegex": "/__tests__/.*\\.spec.(ts)$" | ||
} | ||
} |
WDIO Report Portal Reporter | ||
==================== | ||
[![Greenkeeper badge](https://badges.greenkeeper.io/BorisOsipov/wdio-reportportal-reporter.svg)](https://greenkeeper.io/) | ||
[![Build Status](https://travis-ci.org/BorisOsipov/wdio-reportportal-reporter.svg?branch=master)](https://travis-ci.org/BorisOsipov/wdio-reportportal-reporter) | ||
> A WebdriverIO reporter plugin to report results to Report Portal(http://reportportal.io/). | ||
@@ -12,3 +15,3 @@ | ||
"devDependencies": { | ||
"wdio-reportportal-reporter": "~0.0.8" | ||
"wdio-reportportal-reporter": "~0.0.13" | ||
} | ||
@@ -25,5 +28,7 @@ } | ||
```js | ||
const reportportal = require('wdio-reportportal-reporter'); | ||
exports.config = { | ||
// ... | ||
reporters: ['reportportal'], | ||
reporters: [reportportal], | ||
reporterOptions: { | ||
@@ -36,3 +41,4 @@ reportportal: { | ||
project: 'project_name', | ||
mode: 'DEFAULT' | ||
mode: 'DEFAULT', | ||
debug: false | ||
}, | ||
@@ -44,2 +50,4 @@ enableSeleniumCommandReporting: false, | ||
enableRetriesWorkaround: false, | ||
parseTagsFromTestTitle: false, | ||
debug: false | ||
} | ||
@@ -58,22 +66,24 @@ }, | ||
### Methods description | ||
* `sendLog(level, message) ` – send log to current suite\test item. | ||
* `level` (*String*) - log level. Values ['trace', 'debug', 'info', 'warn', 'error']. | ||
* `reporter.sendLog(level, message) ` – send log to current suite\test item. | ||
* `level` (*string*) - log level. Values ['trace', 'debug', 'info', 'warn', 'error']. | ||
* `message` (*String*)– log message content. | ||
* `sendFile(level, name, content, [type])` – send file to current suite\test item. | ||
* `level` (*String*) - log level. Values ['trace', 'debug', 'info', 'warn', 'error']. | ||
* `name` (*String*)– file name. | ||
* `reporter.sendFile(level, name, content, [type])` – send file to current suite\test item. | ||
* `level` (*string*) - log level. Values ['trace', 'debug', 'info', 'warn', 'error']. | ||
* `name` (*string*)– file name. | ||
* `content` (*String*) – attachment content | ||
* `type` (*String*, optional) – attachment MIME-type, `image/png` by default | ||
* `sendLogToLastFailedTest(level, message)` - send log to last failed test item. | ||
* `level` (*String*) - log level. Values ['trace', 'debug', 'info', 'warn', 'error']. | ||
* `reporter.sendLogToTest(test, level, message)` - send log to specific test. | ||
* `test` (*object*) - test object from `afterTest\afterStep` wdio hook | ||
* `level` (*string*) - log level. Values ['trace', 'debug', 'info', 'warn', 'error']. | ||
* `message` (*String*)– log message content. | ||
* `sendFileToLastFailedTest(level, name, content, [type])` – send file to last failed test item. | ||
* `level` (*String*) - log level. Values ['trace', 'debug', 'info', 'warn', 'error']. | ||
* `name` (*String*)– file name. | ||
* `reporter.sendFileToTest(test, level, name, content, [type])` – send file to to specific test. | ||
* `test` (*object*) - test object from `afterTest\afterStep` wdio hook | ||
* `level` (*string*) - log level. Values ['trace', 'debug', 'info', 'warn', 'error']. | ||
* `name` (*string*)– file name. | ||
* `content` (*String*) – attachment content | ||
* `type` (*String*, optional) – attachment MIME-type, `image/png` by default | ||
* `type` (*string*, optional) – attachment MIME-type, `image/png` by default | ||
Pay attention: `sendLog`\\`sendFile` sends log to **current test item**. It means if you send log without active test(e.g from hooks or on suite level) you will not be able to access them in Report Portal UI. | ||
Pay attention: `sendLog`\\`sendFile` sends log to **current running test item**. It means if you send log without active test(e.g from hooks or on suite level) it will not be reported Report Portal UI. | ||
Methods `sendLogToLastFailedTest`\\`sendFileToLastFailedTest` are useful when you need to send screenshots or logs to the failed test item from wdio afterTest hook. | ||
Methods `sendLogToTest`\\`sendFileToTest` are useful when you need to send screenshots or logs to the failed test item from wdio afterTest hook. | ||
@@ -89,3 +99,3 @@ Mocha example: | ||
const screenshot = await browser.saveScreenshot(); | ||
reporter.sendFileToLastFailedTest('error', 'failed.png', screenshot); | ||
reporter.sendFileToTest(test, 'error', 'failed.png', screenshot); | ||
} | ||
@@ -92,0 +102,0 @@ }, |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
57429
2
17
34
1338
103
2
- Removedbabel-runtime@^6.26.0
- Removedbabel-runtime@6.26.0(transitive)
- Removedcore-js@2.6.12(transitive)
- Removedregenerator-runtime@0.11.1(transitive)