@ericmconnelly/wdio-slack-reporter
Version:
Reporter from WebdriverIO using Web API to send results to Slack.
903 lines (902 loc) • 38.3 kB
JavaScript
"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);