@nightwatch/browserstack
Advanced tools
Comparing version 3.2.2 to 3.2.3
@@ -98,2 +98,5 @@ const LocalTunnel = require('../src/local-tunnel'); | ||
worker.process.on('message', async (data) => { | ||
if (data.POST_SESSION_EVENT) { | ||
helper.storeSessionsData(data); | ||
} | ||
if (data.eventType === EVENTS.LOG_INIT) { | ||
@@ -156,3 +159,3 @@ const testCaseStartedId = data.loggingData.message.replace('TEST-OBSERVABILITY-PID-TESTCASE-MAPPING-', '').slice(1, -1); | ||
eventBroadcaster.on('TestStepStarted', (args) => { | ||
eventBroadcaster.on('TestStepStarted', async (args) => { | ||
if (!helper.isTestObservabilitySession()) { | ||
@@ -168,5 +171,6 @@ return; | ||
const testStepId = reportData.testStepStarted[args.envelope.testCaseStartedId].testStepId; | ||
await testObservability.sendHook(args, 'HookRunStarted', testSteps, testStepId, _tests[testCaseId]); | ||
const pickleStepId = testSteps.find((testStep) => testStep.id === testStepId).pickleStepId; | ||
if (pickleStepId && _tests['testStepId'] !== testStepId) { | ||
_tests['testStepId'] = testStepId; | ||
if (pickleStepId && _tests[testCaseId]?.['testStepId'] !== testStepId) { | ||
_tests[testCaseId]['testStepId'] = testStepId; | ||
const pickleStepData = pickleData.steps.find((pickle) => pickle.id === pickleStepId); | ||
@@ -196,2 +200,3 @@ const testMetaData = _tests[testCaseId] || {steps: []}; | ||
const reportData = args.report; | ||
helper.storeSessionsData(args); | ||
const testCaseId = _testCasesData[args.envelope.testCaseStartedId].testCaseId; | ||
@@ -203,2 +208,3 @@ const testStepFinished = reportData.testStepFinished[args.envelope.testCaseStartedId]; | ||
const testStepId = reportData.testStepFinished[args.envelope.testCaseStartedId].testStepId; | ||
await testObservability.sendHook(args, 'HookRunFinished', testSteps, testStepId, _tests[testCaseId]); | ||
const pickleStepId = testSteps.find((testStep) => testStep.id === testStepId).pickleStepId; | ||
@@ -212,3 +218,3 @@ let failure; | ||
if (pickleStepId && _tests['testStepId']) { | ||
if (pickleStepId && _tests[testCaseId]['testStepId']) { | ||
const pickleStepData = pickleData.steps.find((pickle) => pickle.id === pickleStepId); | ||
@@ -238,3 +244,3 @@ const testMetaData = _tests[testCaseId] || {steps: []}; | ||
_tests[testCaseId] = testMetaData; | ||
delete _tests['testStepId']; | ||
delete _tests[testCaseId]['testStepId']; | ||
if (testStepFinished.httpOutput && testStepFinished.httpOutput.length > 0) { | ||
@@ -241,0 +247,0 @@ for (const [index, output] of testStepFinished.httpOutput.entries()) { |
{ | ||
"name": "@nightwatch/browserstack", | ||
"version": "3.2.2", | ||
"version": "3.2.3", | ||
"description": "Nightwatch plugin for integration with browserstack.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -11,2 +11,3 @@ const os = require('os'); | ||
const {API_URL} = require('./utils/constants'); | ||
const hooksMap = {}; | ||
@@ -418,5 +419,5 @@ class TestObservability { | ||
if (eventType === 'TestRunFinished') { | ||
const currentSessionCapabilities = reportData.session[args.envelope.testCaseStartedId]; | ||
if (currentSessionCapabilities.error) { | ||
throw new Error(`Error in driver capabilities: ${JSON.stringify(currentSessionCapabilities.error)}`); | ||
let currentSessionCapabilities = reportData.session[args.envelope.testCaseStartedId]; | ||
if (currentSessionCapabilities === undefined || currentSessionCapabilities.error) { | ||
currentSessionCapabilities = helper.generateCapabilityDetails(args); | ||
} | ||
@@ -474,2 +475,10 @@ | ||
if (eventType === 'TestRunFinished') { | ||
const hooksList = this.getHooksListForTest(args); | ||
if (hooksList && hooksList.length > 0) { | ||
testData.hooks = hooksList; | ||
this.updateTestStatus(args, testData); | ||
} | ||
} | ||
const uploadData = { | ||
@@ -483,2 +492,138 @@ event_type: eventType, | ||
updateTestStatus(args, testData) { | ||
const testCaseStartedId = args.envelope.testCaseStartedId; | ||
const hookList = hooksMap[testCaseStartedId]; | ||
if (hookList instanceof Array) { | ||
for (const hook of hookList) { | ||
if (hook.result === 'failed') { | ||
testData.result = hook.result; | ||
testData.failure = hook.failure_data; | ||
testData.failure_reason = (hook.failure_data instanceof Array) ? hook.failure_data[0]?.backtrace.join('\n') : ''; | ||
testData.failure_type = hook.failure_type; | ||
return testData; | ||
} | ||
} | ||
}; | ||
} | ||
getHooksListForTest(args) { | ||
const testCaseStartedId = args.envelope.testCaseStartedId; | ||
if (hooksMap[testCaseStartedId]) { | ||
return hooksMap[testCaseStartedId].map(hookDetail => hookDetail.uuid); | ||
} | ||
return []; | ||
} | ||
getHookRunEventData(args, eventType, hookData, testMetaData, hookType) { | ||
if (eventType === 'HookRunFinished') { | ||
const finishedAt = new Date().toISOString(); | ||
const testCaseStartedId = args.envelope.testCaseStartedId; | ||
const hookList = hooksMap[testCaseStartedId]; | ||
if (!hookList) { | ||
return; | ||
} | ||
const hookEventData = hookList.find(hook => hook.uuid === hookData.id); | ||
if (!hookEventData) { | ||
return; | ||
} | ||
const result = this.getHookResult(args); | ||
hookEventData.result = result.status; | ||
hookEventData.finished_at = finishedAt; | ||
hookEventData.failure_type = result.failureType; | ||
hookEventData.failure_data = [{backtrace: result.failureData}]; | ||
return hookEventData; | ||
} | ||
const hookDetails = args.report.hooks.find(hookDetail => hookDetail.id === hookData.hookId); | ||
const relativeFilePath = hookDetails?.sourceReference?.uri; | ||
if (!relativeFilePath) { | ||
return; | ||
} else if (relativeFilePath.includes('setup_cucumber_runner')) { | ||
return; | ||
} | ||
const startedAt = new Date().toISOString(); | ||
const result = 'pending'; | ||
const hookTagsList = hookDetails.tagExpression ? hookDetails.tagExpression.split(' ').filter(val => val.includes('@')) : null; | ||
const hookEventData = { | ||
uuid: hookData.id, | ||
type: 'hook', | ||
hook_type: hookType, | ||
name: hookDetails?.name || '', | ||
body: { | ||
lang: 'NodeJs', | ||
code: null | ||
}, | ||
tags: hookTagsList, | ||
scope: testMetaData?.feature?.name, | ||
scopes: [testMetaData?.feature?.name || ''], | ||
file_name: relativeFilePath, | ||
location: relativeFilePath, | ||
vc_filepath: (this._gitMetadata && this._gitMetadata.root) ? path.relative(this._gitMetadata.root, relativeFilePath) : null, | ||
result: result.status, | ||
started_at: startedAt, | ||
framework: 'nightwatch' | ||
}; | ||
return hookEventData; | ||
} | ||
async sendHook(args, eventType, testSteps, testStepId, testMetaData) { | ||
const hookData = testSteps.find((testStep) => testStep.id === testStepId); | ||
if (!hookData.hookId) { | ||
return; | ||
} | ||
const testCaseStartedId = args.envelope.testCaseStartedId; | ||
const hookType = this.getCucumberHookType(testSteps, hookData); | ||
const hookRunEvent = this.getHookRunEventData(args, eventType, hookData, testMetaData, hookType); | ||
if (!hookRunEvent) { | ||
return; | ||
} | ||
if (eventType === 'HookRunStarted') { | ||
if (hooksMap[testCaseStartedId]) { | ||
hooksMap[testCaseStartedId].push(hookRunEvent); | ||
} else { | ||
hooksMap[testCaseStartedId] = [hookRunEvent]; | ||
} | ||
} | ||
const hookEventUploadData = { | ||
event_type: eventType, | ||
hook_run: hookRunEvent | ||
}; | ||
await helper.uploadEventData(hookEventUploadData); | ||
} | ||
getHookResult(args) { | ||
const testCaseStartedId = args.envelope.testCaseStartedId; | ||
const hookResult = args.report.testStepFinished[testCaseStartedId].testStepResult; | ||
let failure; | ||
let failureType; | ||
if (hookResult?.status.toString().toLowerCase() === 'failed') { | ||
failure = (hookResult?.exception === undefined) ? hookResult?.message : hookResult?.exception?.message; | ||
failureType = (hookResult?.exception === undefined) ? 'UnhandledError' : hookResult?.message.match(/Assert/) ? 'AssertionError' : 'UnhandledError'; | ||
} | ||
return { | ||
status: hookResult.status.toLowerCase(), | ||
failureType: failureType || null, | ||
failureData: (!failure) ? null : [failure] | ||
}; | ||
} | ||
// BEFORE_ALL and AFTER_ALL are not implemented for TO | ||
getCucumberHookType(testSteps, hookData) { | ||
let isStep = false; | ||
for (const step of testSteps) { | ||
if (step.pickleStepId) { | ||
isStep = true; | ||
} | ||
if (hookData.id === step.id) { | ||
return (isStep) ? 'AFTER_EACH' : 'BEFORE_EACH'; | ||
} | ||
} | ||
} | ||
async appendTestItemLog (log, testUuid) { | ||
@@ -485,0 +630,0 @@ try { |
@@ -16,2 +16,3 @@ const os = require('os'); | ||
const BSTestOpsPatcher = new LogPatcher({}); | ||
const sessions = {}; | ||
@@ -698,1 +699,57 @@ console = {}; | ||
}; | ||
exports.generateCapabilityDetails = (args) => { | ||
if (!this.isUndefined(browser)) { | ||
return { | ||
host: browser.options.webdriver.host, | ||
port: browser.options.webdriver.port, | ||
capabilities: browser.capabilities, | ||
sessionId: browser.sessionId, | ||
testCaseStartedId: args.envelope.testCaseStartedId | ||
}; | ||
} | ||
if (sessions[args.envelope.testCaseStartedId]) { | ||
return sessions[args.envelope.testCaseStartedId]; | ||
} | ||
}; | ||
exports.storeSessionsData = (data) => { | ||
if (data.POST_SESSION_EVENT) { | ||
const sessionDetails = JSON.parse(data.POST_SESSION_EVENT); | ||
if (!sessionDetails.session) { | ||
return; | ||
} | ||
if (!Object.keys(sessions).includes(sessionDetails.session.testCaseStartedId)) { | ||
sessions[sessionDetails.session.testCaseStartedId] = sessionDetails.session; | ||
} | ||
} else { | ||
if (!data.report.session) { | ||
return; | ||
} | ||
Object.keys(data.report.session).forEach(key => { | ||
if (!Object.keys(sessions).includes(key)) { | ||
sessions[key] = data.report.session[key]; | ||
} | ||
}); | ||
} | ||
}; | ||
exports.deepClone = (obj) => { | ||
if (obj === null || typeof obj !== 'object') { | ||
return obj; | ||
} | ||
if (Array.isArray(obj)) { | ||
return obj.map(exports.deepClone); | ||
} | ||
const cloned = {}; | ||
for (const key in obj) { | ||
if (Object.prototype.hasOwnProperty.call(obj, key)) { | ||
cloned[key] = exports.deepClone(obj[key]); | ||
} | ||
} | ||
return cloned; | ||
}; |
102594
2531