UNPKG

@ericmconnelly/wdio-slack-reporter

Version:

Reporter from WebdriverIO using Web API to send results to Slack.

903 lines (902 loc) 38.3 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 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) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const web_api_1 = require("@slack/web-api"); const webhook_1 = require("@slack/webhook"); const logger_1 = __importDefault(require("@wdio/logger")); const reporter_1 = __importDefault(require("@wdio/reporter")); const util_1 = __importDefault(require("util")); const constants_js_1 = require("./constants.js"); const log = (0, logger_1.default)('@moroo/wdio-slack-reporter'); class SlackReporter extends reporter_1.default { constructor(options) { var _a, _b, _c, _d, _e, _f, _g; super(Object.assign({ stdout: true }, options)); this._slackRequestQueue = []; this._pendingSlackRequestCount = 0; this._stateCounts = { passed: 0, failed: 0, skipped: 0, }; this._isCucumberFramework = false; this._notifyTestStartMessage = true; this._notifyFailedCase = true; this._uploadScreenshotOfFailedCase = true; this._notifyTestFinishMessage = true; this._notifyDetailResultThread = true; this._filterForDetailResults = [ 'passed', 'failed', 'pending', 'skipped', ]; this._isSynchronizing = false; this._hasRunnerEnd = false; this._lastScreenshotBuffer = undefined; this._suiteUids = new Set(); this._orderedSuites = []; this._cucumberOrderedTests = []; this._indents = 0; this._suiteIndents = {}; if (!options.slackOptions) { log.error(constants_js_1.ERROR_MESSAGES.UNDEFINED_SLACK_OPTION); log.debug(options.slackOptions); throw new Error(constants_js_1.ERROR_MESSAGES.UNDEFINED_SLACK_OPTION); } if (options.slackOptions.type === 'web-api') { this._client = new web_api_1.WebClient(options.slackOptions.slackBotToken); log.info('Created Slack Web API Client Instance.'); log.debug('Slack Web API Client', { token: options.slackOptions.slackBotToken, channel: options.slackOptions.channel, }); this._channel = options.slackOptions.channel; if (options.slackOptions.notifyDetailResultThread !== undefined) { if (options.notifyTestFinishMessage === false) { log.warn('Notify is not possible. because the notifyResultMessage option is off.'); } this._notifyDetailResultThread = options.slackOptions.notifyDetailResultThread; } if (options.slackOptions.filterForDetailResults !== undefined) { if (options.slackOptions.notifyDetailResultThread === false) { log.warn('Detail result filters does not work. because the notifyDetailResultThread option is off.'); } if (options.slackOptions.filterForDetailResults.length === 0) { log.info('If there are no filters (array is empty), all filters are applied.'); } else { this._filterForDetailResults = [ ...options.slackOptions.filterForDetailResults, ]; } } if (options.slackOptions.uploadScreenshotOfFailedCase !== undefined) { this._uploadScreenshotOfFailedCase = options.slackOptions.uploadScreenshotOfFailedCase; } if (options.slackOptions.uploadScreenshotOfFailedCase !== undefined) { this._uploadScreenshotOfFailedCase = options.slackOptions.uploadScreenshotOfFailedCase; } if (options.slackOptions.createScreenshotPayload) { this.createScreenshotPayload = options.slackOptions.createScreenshotPayload.bind(this); log.info('The [createScreenshotPayload] function has been overridden.'); log.debug('RESULT', this.createScreenshotPayload.toString()); } if (options.slackOptions.createResultDetailPayload) { this.createResultDetailPayload = options.slackOptions.createResultDetailPayload.bind(this); log.info('The [createResultDetailPayload] function has been overridden.'); log.debug('RESULT', this.createResultDetailPayload.toString()); } } else { this._webhook = new webhook_1.IncomingWebhook(options.slackOptions.webhook, { username: options.slackOptions.slackName || constants_js_1.SLACK_NAME, icon_url: options.slackOptions.slackIconUrl || constants_js_1.SLACK_ICON_URL, }); log.info('Created Slack Webhook Instance.'); log.debug('IncomingWebhook', { webhook: options.slackOptions.webhook, username: options.slackOptions.slackName || constants_js_1.SLACK_NAME, icon_url: options.slackOptions.slackIconUrl || constants_js_1.SLACK_ICON_URL, }); } this._symbols = { passed: ((_a = options.emojiSymbols) === null || _a === void 0 ? void 0 : _a.passed) || constants_js_1.EMOJI_SYMBOLS.PASSED, skipped: ((_b = options.emojiSymbols) === null || _b === void 0 ? void 0 : _b.skipped) || constants_js_1.EMOJI_SYMBOLS.SKIPPED, failed: ((_c = options.emojiSymbols) === null || _c === void 0 ? void 0 : _c.failed) || constants_js_1.EMOJI_SYMBOLS.FAILED, pending: ((_d = options.emojiSymbols) === null || _d === void 0 ? void 0 : _d.pending) || constants_js_1.EMOJI_SYMBOLS.PENDING, start: ((_e = options.emojiSymbols) === null || _e === void 0 ? void 0 : _e.start) || constants_js_1.EMOJI_SYMBOLS.ROKET, finished: ((_f = options.emojiSymbols) === null || _f === void 0 ? void 0 : _f.finished) || constants_js_1.EMOJI_SYMBOLS.CHECKERED_FLAG, watch: ((_g = options.emojiSymbols) === null || _g === void 0 ? void 0 : _g.watch) || constants_js_1.EMOJI_SYMBOLS.STOPWATCH, }; this._title = options.title; if (options.resultsUrl !== undefined) { SlackReporter.setResultsUrl(options.resultsUrl); } if (options.notifyTestStartMessage !== undefined) { this._notifyTestStartMessage = options.notifyTestStartMessage; } if (options.notifyFailedCase !== undefined) { this._notifyFailedCase = options.notifyFailedCase; } if (options.notifyTestFinishMessage !== undefined) { this._notifyTestFinishMessage = options.notifyTestFinishMessage; } this._interval = global.setInterval(this.sync.bind(this), 100); if (options.createStartPayload) { this.createStartPayload = options.createStartPayload.bind(this); log.info('The [createStartPayload] function has been overridden.'); log.debug('RESULT', this.createStartPayload.toString()); } if (options.createFailedTestPayload) { this.createFailedTestPayload = options.createFailedTestPayload.bind(this); log.info('The [createFailedTestPayload] function has been overridden.'); log.debug('RESULT', this.createFailedTestPayload.toString()); } if (options.createResultPayload) { this.createResultPayload = options.createResultPayload.bind(this); log.info('The [createResultPayload] function has been overridden.'); log.debug('RESULT', this.createResultPayload.toString()); } process.on(constants_js_1.EVENTS.POST_MESSAGE, this.postMessage.bind(this)); process.on(constants_js_1.EVENTS.UPLOAD, this.upload.bind(this)); process.on(constants_js_1.EVENTS.SEND, this.send.bind(this)); process.on(constants_js_1.EVENTS.SCREENSHOT, this.uploadFailedTestScreenshot.bind(this)); } static getResultsUrl() { return SlackReporter.resultsUrl; } static setResultsUrl(url) { SlackReporter.resultsUrl = url; } /** * Upload failed test scrteenshot * @param {WebdriverIO.Browser} browser Parameters used by WebdriverIO.Browser * @param {{page: Page, options: ScreenshotOptions}} puppeteer Parameters used by Puppeteer * @return {Promise<Buffer>} */ static uploadFailedTestScreenshot(data) { let buffer; if (typeof data === 'string') { buffer = Buffer.from(data, 'base64'); } else { buffer = data; } process.emit(constants_js_1.EVENTS.SCREENSHOT, buffer); } /** * Post message from Slack web-api * @param {ChatPostMessageArguments} payload Parameters used by Slack web-api * @return {Promise<WebAPICallResult>} */ static postMessage(payload) { return new Promise((resolve, reject) => { process.emit(constants_js_1.EVENTS.POST_MESSAGE, payload); process.once(constants_js_1.EVENTS.RESULT, ({ result, error }) => { if (result) { resolve(result); } reject(error); }); }); } /** * Upload from Slack web-api * @param {FilesUploadArguments} payload Parameters used by Slack web-api * @return {WebAPICallResult} */ static upload(payload) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { process.emit(constants_js_1.EVENTS.UPLOAD, payload); process.once(constants_js_1.EVENTS.RESULT, ({ result, error }) => { if (result) { resolve(result); } reject(error); }); }); }); } /** * Send from Slack webhook * @param {IncomingWebhookSendArguments} payload Parameters used by Slack webhook * @return {IncomingWebhookResult} */ static send(payload) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { process.emit(constants_js_1.EVENTS.SEND, payload); process.once(constants_js_1.EVENTS.RESULT, ({ result, error }) => { if (result) { resolve(result); } reject(error); }); }); }); } uploadFailedTestScreenshot(buffer) { if (this._client) { if (this._notifyFailedCase && this._uploadScreenshotOfFailedCase) { this._lastScreenshotBuffer = buffer; return; } else { log.warn(constants_js_1.ERROR_MESSAGES.DISABLED_OPTIONS); } } else { log.warn(constants_js_1.ERROR_MESSAGES.NOT_USING_WEB_API); } // return new Promise((resolve, reject) => { // const interval = setInterval(() => { // if (this._lastScreenshotBuffer === undefined) { // clearInterval(interval); // if (this._client && this._notifyFailedCase) { // this._lastScreenshotBuffer = buffer; // } else { // log.warn( // ERROR_MESSAGES.NOT_USING_WEB_API_OR_DISABLED_NOTIFY_FAILED_CASE // ); // } // resolve(); // } // }, 100); // }); } postMessage(payload) { return __awaiter(this, void 0, void 0, function* () { if (this._client) { try { log.debug('COMMAND', `postMessage(${payload})`); this._pendingSlackRequestCount++; const result = yield this._client.chat.postMessage(payload); log.debug('RESULT', util_1.default.inspect(result)); process.emit(constants_js_1.EVENTS.RESULT, { result, error: undefined }); return result; } catch (error) { log.error(error); process.emit(constants_js_1.EVENTS.RESULT, { result: undefined, error }); throw error; } finally { this._pendingSlackRequestCount--; } } log.error(constants_js_1.ERROR_MESSAGES.NOT_USING_WEB_API); throw new Error(constants_js_1.ERROR_MESSAGES.NOT_USING_WEB_API); }); } upload(payload) { return __awaiter(this, void 0, void 0, function* () { if (this._client) { try { log.debug('COMMAND', `upload(${payload})`); this._pendingSlackRequestCount++; const result = yield this._client.files.upload(payload); log.debug('RESULT', util_1.default.inspect(result)); process.emit(constants_js_1.EVENTS.RESULT, { result, error: undefined }); return result; } catch (error) { log.error(error); process.emit(constants_js_1.EVENTS.RESULT, { result: undefined, error }); throw error; } finally { this._pendingSlackRequestCount--; } } log.error(constants_js_1.ERROR_MESSAGES.NOT_USING_WEB_API); throw new Error(constants_js_1.ERROR_MESSAGES.NOT_USING_WEB_API); }); } send(payload) { return __awaiter(this, void 0, void 0, function* () { if (this._webhook) { try { log.debug('COMMAND', `send(${payload})`); this._pendingSlackRequestCount++; const result = yield this._webhook.send(payload); log.debug('RESULT', util_1.default.inspect(result)); process.emit(constants_js_1.EVENTS.RESULT, { result, error: undefined }); return result; } catch (error) { log.error(error); process.emit(constants_js_1.EVENTS.RESULT, { result: undefined, error }); throw error; } finally { this._pendingSlackRequestCount--; } } log.error(constants_js_1.ERROR_MESSAGES.NOT_USING_WEBHOOK); throw new Error(constants_js_1.ERROR_MESSAGES.NOT_USING_WEBHOOK); }); } get isSynchronised() { return (this._pendingSlackRequestCount === 0 && this._isSynchronizing === false); } sync() { return __awaiter(this, void 0, void 0, function* () { if (this._hasRunnerEnd && this._slackRequestQueue.length === 0 && this._pendingSlackRequestCount === 0) { clearInterval(this._interval); } if (this._isSynchronizing || this._slackRequestQueue.length === 0 || this._pendingSlackRequestCount > 0) { return; } try { this._isSynchronizing = true; log.info('Start Synchronising...'); yield this.next(); } catch (error) { log.error(error); throw error; } finally { this._isSynchronizing = false; log.info('End Synchronising!!!'); } }); } next() { var _a, _b; return __awaiter(this, void 0, void 0, function* () { const request = this._slackRequestQueue.shift(); let result; log.info('POST', `Slack Request ${request === null || request === void 0 ? void 0 : request.type}`); log.debug('DATA', util_1.default.inspect(request === null || request === void 0 ? void 0 : request.payload)); if (request) { try { this._pendingSlackRequestCount++; switch (request.type) { case constants_js_1.SLACK_REQUEST_TYPE.WEB_API_POST_MESSAGE: { if (this._client) { result = yield this._client.chat.postMessage(Object.assign(Object.assign({}, request.payload), { thread_ts: request.isDetailResult ? (_a = this._lastSlackWebAPICallResult) === null || _a === void 0 ? void 0 : _a.ts : undefined })); this._lastSlackWebAPICallResult = result; log.debug('RESULT', util_1.default.inspect(result)); } break; } case constants_js_1.SLACK_REQUEST_TYPE.WEB_API_UPLOAD: { if (this._client) { result = yield this._client.files.upload(Object.assign(Object.assign({}, request.payload), { thread_ts: (_b = this._lastSlackWebAPICallResult) === null || _b === void 0 ? void 0 : _b.ts })); log.debug('RESULT', util_1.default.inspect(result)); } break; } case constants_js_1.SLACK_REQUEST_TYPE.WEBHOOK_SEND: { if (this._webhook) { result = yield this._webhook.send(request.payload); log.debug('RESULT', util_1.default.inspect(result)); } break; } } } catch (error) { log.error(error); } finally { this._pendingSlackRequestCount--; } if (this._slackRequestQueue.length > 0) { yield this.next(); } } }); } convertErrorStack(stack) { return stack.replace( // eslint-disable-next-line no-control-regex /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, ''); } getEnviromentCombo(capability, isMultiremote = false) { let output = ''; const capabilities = capability .alwaysMatch || capability; const drivers = []; if (isMultiremote) { output += '*MultiRemote*: \n'; Object.keys(capabilities).forEach((key) => { drivers.push({ driverName: key, capability: capabilities[key], }); }); } else { drivers.push({ capability: capabilities, }); } drivers.forEach(({ driverName, capability }, index, array) => { const isLastIndex = array.length - 1 === index; let env = ''; const caps = capability .alwaysMatch || capability; const device = caps.deviceName; const browser = caps.browserName || caps.browser; const version = caps.browserVersion || caps.version || // eslint-disable-next-line @typescript-eslint/no-explicit-any caps.platformVersion || caps.browser_version; const platform = caps.platformName || caps.platform || (caps.os ? caps.os + (caps.os_version ? ` ${caps.os_version}` : '') : '(unknown)'); if (device) { const program = // eslint-disable-next-line @typescript-eslint/no-explicit-any (caps.app || '').replace('sauce-storage:', '') || caps.browserName; const executing = program ? `executing ${program}` : ''; env = `${device} on ${platform} ${version} ${executing}`.trim(); } else { env = browser + (version ? ` (v${version})` : '') + ` on ${platform}`; } output += isMultiremote ? `- *${driverName}*: ` : '*Driver*: '; output += env; output += isLastIndex ? '' : '\n'; }); return output; } /** * Indent a suite based on where how it's nested * @param {String} uid Unique suite key * @return {String} Spaces for indentation */ indent(uid) { const indents = this._suiteIndents[uid]; return indents === 0 ? '' : Array(indents).join(constants_js_1.DEFAULT_INDENT); } /** * Indent a suite based on where how it's nested * @param {StateCount} stateCounts Stat count * @return {String} String to the stat count to be displayed in Slack */ getCounts(stateCounts) { return `*${this._symbols.passed} Passed: ${stateCounts.passed} | ${this._symbols.failed} Failed: ${stateCounts.failed} | ${this._symbols.skipped} Skipped: ${stateCounts.skipped}*`; } createStartPayload(runnerStats) { const text = `${this._title ? '*Title*: `' + this._title + '`\n' : ''}${this.getEnviromentCombo(runnerStats.capabilities, runnerStats.isMultiremote)}`; const payload = { channel: this._channel, text: `${this._symbols.start} Start testing${this._title ? 'for ' + this._title : ''}`, blocks: [ { type: 'header', text: { type: 'plain_text', text: `${this._symbols.start} Start testing`, emoji: true, }, }, ], attachments: [ { color: constants_js_1.DEFAULT_COLOR, text, ts: Date.now().toString(), }, ], }; return payload; } createFailedTestPayload(hookAndTest) { var _a; const stack = ((_a = hookAndTest.error) === null || _a === void 0 ? void 0 : _a.stack) ? '```' + this.convertErrorStack(hookAndTest.error.stack) + '```' : ''; const payload = { channel: this._channel, text: `${this._symbols.failed} Test failure`, blocks: [ { type: 'header', text: { type: 'plain_text', text: `${this._symbols.failed} Test failure`, emoji: true, }, }, ], attachments: [ { color: constants_js_1.FAILED_COLOR, title: `${this._currentSuite ? this._currentSuite.title : hookAndTest.parent}`, text: `* » ${hookAndTest.title}*\n${stack}`, }, ], }; return payload; } createScreenshotPayload(testStats, screenshotBuffer) { const payload = { channels: this._channel, initial_comment: `Screenshot for Fail to ${testStats.title}`, filename: `${testStats.uid}.png`, filetype: 'png', file: screenshotBuffer, }; return payload; } createResultPayload(runnerStats, stateCounts) { const resltsUrl = SlackReporter.getResultsUrl(); const counts = this.getCounts(stateCounts); const payload = { channel: this._channel, text: `${this._symbols.finished} End of test${this._title ? ' - ' + this._title : ''}\n${counts}`, blocks: [ { type: 'header', text: { type: 'plain_text', text: `${this._symbols.finished} End of test - ${this._symbols.watch} ${runnerStats.duration / 1000}s`, emoji: true, }, }, ], attachments: [ { color: constants_js_1.FINISHED_COLOR, text: `${this._title ? `*Title*: \`${this._title}\`\n` : ''}${resltsUrl ? `*Results*: <${resltsUrl}>\n` : ''}${counts}`, ts: Date.now().toString(), }, ], }; return payload; } createResultDetailPayload(runnerStats, stateCounts) { const counts = this.getCounts(stateCounts); const payload = { channel: this._channel, text: `${this._title ? this._title + '\n' : ''}${counts}`, blocks: [ { type: 'header', text: { type: 'plain_text', text: 'Result Details', emoji: true, }, }, ...this.getResultDetailPayloads(), { type: 'section', text: { type: 'mrkdwn', text: `${counts}\n${this._symbols.watch} ${runnerStats.duration / 1000}s`, }, }, { type: 'context', elements: [ { type: 'mrkdwn', text: `*Filter*: ${this._filterForDetailResults .map((filter) => '`' + filter + '`') .join(', ')}`, }, ], }, ], }; return payload; } getResultDetailPayloads() { const output = []; let suites = this._isCucumberFramework ? this.getOrderedCucumberTests() : this.getOrderedSuites(); const blocks = []; // Filter Detailed suites by state (Cucumber only) if (this._isCucumberFramework && this._notifyDetailResultThread) { suites = suites.filter(({ state }) => this._filterForDetailResults.includes(state)); } for (const suite of suites) { // Don't do anything if a suite has no tests or sub suites if (suite.tests.length === 0 && suite.suites.length === 0 && suite.hooks.length === 0) { continue; } let eventsToReport = this.getEventsToReport(suite); // Filter Detailed tests results by state (if needed) if (this._isCucumberFramework === false && this._notifyDetailResultThread) { eventsToReport = eventsToReport.filter(({ state }) => this._filterForDetailResults.includes(state)); } if (eventsToReport.length === 0) { continue; } // Get the indent/starting point for this suite const suiteIndent = this.indent(suite.uid); // Display the title of the suite if (suite.type) { output.push(`*${suiteIndent}${suite.title}*`); } // display suite description (Cucumber only) if (suite.description) { output.push(...suite.description .trim() .split('\n') .map((l) => `${suiteIndent}${l.trim()}`)); } for (const test of eventsToReport) { const testTitle = test.title; const testState = test.state; const testIndent = `${constants_js_1.DEFAULT_INDENT}${suiteIndent}`; // Output for a single test output.push(`*${testIndent}${testState ? `${this._symbols[testState]} ` : ''}${testTitle}*`); } // Put a line break after each suite (only if tests exist in that suite) if (eventsToReport.length) { const block = { type: 'section', text: { type: 'mrkdwn', text: output.join('\n'), }, }; output.length = 0; blocks.push(block); } } if (blocks.length === 0) { const block = { type: 'section', text: { type: 'mrkdwn', text: '*`No filter Results.`*', }, }; blocks.push(block); } return blocks; } getOrderedSuites() { if (this._orderedSuites.length) { return this._orderedSuites; } this._orderedSuites = []; for (const uid of this._suiteUids) { for (const [suiteUid, suite] of Object.entries(this.suites)) { if (suiteUid !== uid) { continue; } this._orderedSuites.push(suite); } } return this._orderedSuites; } getOrderedCucumberTests() { if (this._cucumberOrderedTests.length) { return this._cucumberOrderedTests; } this._cucumberOrderedTests = []; for (const uid of this._suiteUids) { for (const [suiteUid, suite] of Object.entries(this.suites)) { if (suiteUid !== uid) { continue; } if (suite.type === 'scenario') { let testState = 'skipped'; if (suite.tests.some((test) => test.state === 'passed')) { testState = 'passed'; } else if (suite.tests.some((test) => test.state === 'failed')) { testState = 'failed'; } this._cucumberOrderedTests.push(Object.assign(suite, { state: testState })); } } } return this._cucumberOrderedTests; } getCucumberTestsCounts() { const suitesData = this.getOrderedCucumberTests(); const suiteStats = { passed: suitesData.filter(({ state }) => state === 'passed').length, failed: suitesData.filter(({ state }) => state === 'failed').length, skipped: suitesData.filter(({ state }) => state === 'skipped').length, }; return suiteStats; } /** * returns everything worth reporting from a suite * @param {Object} suite test suite containing tests and hooks * @return {Object[]} list of events to report */ getEventsToReport(suite) { return [ /** * report all tests and only hooks that failed */ ...suite.hooksAndTests.filter((item) => { return item.type === 'test' || Boolean(item.error); }), ]; } onRunnerStart(runnerStats) { log.info('INFO', `Test Framework: ${runnerStats.config.framework}`); if (runnerStats.config.framework === 'cucumber') { this._isCucumberFramework = true; } if (this._notifyTestStartMessage) { try { if (this._client) { log.info('INFO', `ON RUNNER START: POST MESSAGE`); this._slackRequestQueue.push({ type: constants_js_1.SLACK_REQUEST_TYPE.WEB_API_POST_MESSAGE, payload: this.createStartPayload(runnerStats), }); } else if (this._webhook) { log.info('INFO', `ON RUNNER START: SEND`); this._slackRequestQueue.push({ type: constants_js_1.SLACK_REQUEST_TYPE.WEBHOOK_SEND, payload: this.createStartPayload(runnerStats), }); } } catch (error) { log.error(error); throw error; } } } // onBeforeCommand(commandArgs: BeforeCommandArgs): void {} // onAfterCommand(commandArgs: AfterCommandArgs): void {} onSuiteStart(suiteStats) { this._currentSuite = suiteStats; this._suiteUids.add(suiteStats.uid); if (this._isCucumberFramework) { if (suiteStats.type === 'feature') { this._indents = 0; this._suiteIndents[suiteStats.uid] = this._indents; } } else { this._suiteIndents[suiteStats.uid] = ++this._indents; } } // onHookStart(hookStat: HookStats): void {} onHookEnd(hookStats) { if (hookStats.error) { this._stateCounts.failed++; if (this._notifyFailedCase) { if (this._client) { this._slackRequestQueue.push({ type: constants_js_1.SLACK_REQUEST_TYPE.WEB_API_POST_MESSAGE, payload: this.createFailedTestPayload(hookStats), }); } else { this._slackRequestQueue.push({ type: constants_js_1.SLACK_REQUEST_TYPE.WEBHOOK_SEND, payload: this.createFailedTestPayload(hookStats), }); } } } } // onTestStart(testStats: TestStats): void {} onTestPass(testStats) { this._stateCounts.passed++; } onTestFail(testStats) { this._stateCounts.failed++; if (this._notifyFailedCase) { if (this._client) { this._slackRequestQueue.push({ type: constants_js_1.SLACK_REQUEST_TYPE.WEB_API_POST_MESSAGE, payload: this.createFailedTestPayload(testStats), }); if (this._uploadScreenshotOfFailedCase && this._lastScreenshotBuffer) { log.error('UID', testStats.uid); this._slackRequestQueue.push({ type: constants_js_1.SLACK_REQUEST_TYPE.WEB_API_UPLOAD, payload: this.createScreenshotPayload(testStats, this._lastScreenshotBuffer), }); this._lastScreenshotBuffer = undefined; } } else { this._slackRequestQueue.push({ type: constants_js_1.SLACK_REQUEST_TYPE.WEBHOOK_SEND, payload: this.createFailedTestPayload(testStats), }); } } } // onTestRetry(testStats: TestStats): void {} onTestSkip(testStats) { this._stateCounts.skipped++; } // onTestEnd(testStats: TestStats): void {} onSuiteEnd(suiteStats) { this._indents--; } onRunnerEnd(runnerStats) { if (this._notifyTestFinishMessage) { const stateCount = this._isCucumberFramework ? this.getCucumberTestsCounts() : this._stateCounts; try { if (this._client) { this._slackRequestQueue.push({ type: constants_js_1.SLACK_REQUEST_TYPE.WEB_API_POST_MESSAGE, payload: this.createResultPayload(runnerStats, stateCount), }); if (this._notifyDetailResultThread) { this._slackRequestQueue.push({ type: constants_js_1.SLACK_REQUEST_TYPE.WEB_API_POST_MESSAGE, payload: this.createResultDetailPayload(runnerStats, stateCount), isDetailResult: true, }); } } else { this._slackRequestQueue.push({ type: constants_js_1.SLACK_REQUEST_TYPE.WEBHOOK_SEND, payload: this.createResultPayload(runnerStats, stateCount), }); } } catch (error) { log.error(error); throw error; } } this._hasRunnerEnd = true; } } exports.default = SlackReporter; __exportStar(require("./types.js"), exports);