@wdio/allure-reporter
Version:
A WebdriverIO reporter plugin to create Allure Test Reports
1,109 lines (1,096 loc) • 35.5 kB
JavaScript
// src/reporter.ts
import { stringify } from "csv-stringify/sync";
import { getBrowserName } from "@wdio/reporter";
import WDIOReporter from "@wdio/reporter";
import {
AllureRuntime,
AllureGroup as AllureGroup2,
AllureTest as AllureTest2,
Status as AllureStatus2,
Stage as Stage2,
LabelName as LabelName2,
LinkType,
ContentType,
AllureCommandStepExecutable as AllureCommandStepExecutable2,
ExecutableItemWrapper as ExecutableItemWrapper2,
AllureStep as AllureStep2,
Status as Status3
} from "allure-js-commons";
// src/common/api.ts
import { Status, AllureCommandStepExecutable } from "allure-js-commons";
// src/constants.ts
var events = {
addLabel: "allure:addLabel",
addLink: "allure:addLink",
addFeature: "allure:addFeature",
addStory: "allure:addStory",
addEpic: "allure:addEpic",
addSuite: "allure:addSuite",
addSubSuite: "allure:addSubSuite",
addParentSuite: "allure:addParentSuite",
addOwner: "allure:addOwner",
addSeverity: "allure:addSeverity",
addTag: "allure:addTag",
addIssue: "allure:addIssue",
addAllureId: "allure:addAllureId",
addTestId: "allure:addTestId",
addDescription: "allure:addDescription",
addAttachment: "allure:addAttachment",
startStep: "allure:startStep",
endStep: "allure:endStep",
addStep: "allure:addStep",
addArgument: "allure:addArgument",
addAllureStep: "allure:addAllureStep"
};
var eachHooks = ['"before each" hook', '"after each" hook'];
var allHooks = ['"before all" hook', '"after all" hook'];
var linkPlaceholder = "{}";
// src/common/api.ts
var tellReporter = (event, msg = {}) => {
process.emit(event, msg);
};
function addLabel(name, value) {
tellReporter(events.addLabel, { name, value });
}
function addLink(url, name, type) {
tellReporter(events.addLink, { url, name, type });
}
function addAllureId(id) {
tellReporter(events.addAllureId, { id });
}
function addFeature(featureName) {
tellReporter(events.addFeature, { featureName });
}
function addSeverity(severity) {
tellReporter(events.addSeverity, { severity });
}
function addIssue(issue) {
tellReporter(events.addIssue, { issue });
}
function addTestId(testId) {
tellReporter(events.addTestId, { testId });
}
function addStory(storyName) {
tellReporter(events.addStory, { storyName });
}
function addSuite(suiteName) {
tellReporter(events.addSuite, { suiteName });
}
function addParentSuite(suiteName) {
tellReporter(events.addParentSuite, { suiteName });
}
function addSubSuite(suiteName) {
tellReporter(events.addSubSuite, { suiteName });
}
function addEpic(epicName) {
tellReporter(events.addEpic, { epicName });
}
function addOwner(owner) {
tellReporter(events.addOwner, { owner });
}
function addTag(tag) {
tellReporter(events.addTag, { tag });
}
function addEnvironment(name, value) {
console.warn("\u26A0\uFE0F addEnvironment is deprecated and has no longer any functionality. Use reportedEnvironmentVars in wdio config instead. Read more in https://webdriver.io/docs/allure-reporter.");
}
function addDescription(description, descriptionType) {
tellReporter(events.addDescription, { description, descriptionType });
}
function addAttachment(name, content, type) {
if (!type) {
type = content instanceof Buffer ? "image/png" : typeof content === "string" ? "text/plain" : "application/json";
}
tellReporter(events.addAttachment, { name, content, type });
}
function startStep(title) {
tellReporter(events.startStep, title);
}
function endStep(status = Status.PASSED) {
if (!Object.values(Status).includes(status)) {
throw new Error(`Step status must be ${Object.values(Status).join(" or ")}. You tried to set "${status}"`);
}
tellReporter(events.endStep, status);
}
function addStep(title, {
content,
name = "attachment",
type = "text/plain"
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} = {}, status = Status.PASSED) {
if (!Object.values(Status).includes(status)) {
throw new Error(`Step status must be ${Object.values(Status).join(" or ")}. You tried to set "${status}"`);
}
const step2 = content ? { title, attachment: { content, name, type }, status } : { title, status };
tellReporter(events.addStep, { step: step2 });
}
function addArgument(name, value) {
tellReporter(events.addArgument, { name, value });
}
async function step(name, body) {
const runningStep = new AllureCommandStepExecutable(name);
await runningStep.run(body, async (message) => tellReporter(events.addAllureStep, message));
}
// src/state.ts
import { sep } from "node:path";
import { AllureGroup, AllureTest, AllureStep, ExecutableItemWrapper } from "allure-js-commons";
// src/utils.ts
import stripAnsi from "strip-ansi";
import { LabelName, md5, Stage, Status as Status2, Status as AllureStatus } from "allure-js-commons";
// src/compoundError.ts
function indentAll(lines) {
return lines.split("\n").map((x) => " " + x).join("\n");
}
var CompoundError = class extends Error {
innerErrors;
constructor(...innerErrors) {
const message = ["CompoundError: One or more errors occurred. ---\n"].concat(innerErrors.map(
(x) => x.message && x.stack?.includes(x.message) ? x.stack ? `${indentAll(x.stack)}
--- End of stack trace ---
` : "" : (x.message ? ` ${x.message}
--- End of error message ---
` : "") + (x.stack ? `${indentAll(x.stack)}
--- End of stack trace ---
` : "")
)).join("\n");
super(message);
this.innerErrors = innerErrors;
}
};
// src/utils.ts
var getTestStatus = (test, config) => {
if (config && config.framework === "jasmine") {
return AllureStatus.FAILED;
}
if (test.error) {
if (test.error.message) {
const message = test.error.message.trim().toLowerCase();
return message.startsWith("assertionerror") || message.includes("expect") ? AllureStatus.FAILED : AllureStatus.BROKEN;
}
if (test.error.stack) {
const stackTrace = test.error.stack.trim().toLowerCase();
return stackTrace.startsWith("assertionerror") || stackTrace.includes("expect") ? AllureStatus.FAILED : AllureStatus.BROKEN;
}
} else if (test.errors) {
return AllureStatus.FAILED;
}
return AllureStatus.BROKEN;
};
var isEmpty = (object) => !object || Object.keys(object).length === 0;
var isBeforeTypeHook = (title) => title.includes(allHooks[0]) || title.includes(eachHooks[0]);
var isEachTypeHooks = (title) => eachHooks.some((hook) => title.includes(hook));
var isAllTypeHooks = (title) => allHooks.some((hook) => title.includes(hook));
var getErrorFromFailedTest = (test) => {
if (test.errors && Array.isArray(test.errors) && test.errors.length) {
for (let i = 0; i < test.errors.length; i += 1) {
if (test.errors[i].message) {
test.errors[i].message = stripAnsi(test.errors[i].message);
}
if (test.errors[i].stack) {
test.errors[i].stack = stripAnsi(test.errors[i].stack);
}
}
return test.errors.length === 1 ? test.errors[0] : new CompoundError(...test.errors);
}
if (test.error) {
if (test.error.message) {
test.error.message = stripAnsi(test.error.message);
}
if (test.error.stack) {
test.error.stack = stripAnsi(test.error.stack);
}
}
return test.error;
};
var getHookStatus = (newHookStats, hookElement, hookRootStep) => {
hookElement.stage = hookRootStep.stage = Stage.FINISHED;
const formattedError = getErrorFromFailedTest(newHookStats);
hookElement.detailsMessage = hookRootStep.detailsMessage = formattedError?.message;
hookElement.detailsTrace = hookRootStep.detailsTrace = formattedError?.stack;
let finalStatus = Status2.PASSED;
const hookSteps = hookRootStep.wrappedItem.steps;
if (Array.isArray(hookSteps) && hookSteps.length) {
const statusPriority = {
[Status2.FAILED]: 0,
[Status2.BROKEN]: 1,
[Status2.SKIPPED]: 2,
[Status2.PASSED]: 3
};
let stepStatus = Status2.PASSED;
for (const step2 of hookSteps) {
if (step2.status && statusPriority[step2.status] < statusPriority[finalStatus]) {
stepStatus = step2.status;
}
}
finalStatus = stepStatus === Status2.FAILED ? Status2.BROKEN : stepStatus;
} else if (newHookStats.error || Array.isArray(newHookStats.errors) && newHookStats.errors.length) {
finalStatus = Status2.BROKEN;
}
hookElement.status = hookRootStep.status = finalStatus;
};
var cleanCucumberHooks = (hook) => {
const currentStep = hook.steps[hook.steps.length - 1];
if (currentStep && currentStep.steps.length === 0 && currentStep.attachments.length === 0 && hook.attachments.length === 0 && currentStep.status === Status2.PASSED) {
hook.steps.pop();
}
};
var getLinkByTemplate = (template, id) => {
if (typeof template !== "string") {
return id;
}
if (!template.includes(linkPlaceholder)) {
throw Error(
`The link template "${template}" must contain ${linkPlaceholder} substring.`
);
}
return template.replace(linkPlaceholder, id);
};
var findLast = (arr, predicate) => {
let result;
for (let i = arr.length - 1; i >= 0; i--) {
if (predicate(arr[i])) {
result = arr[i];
break;
}
}
return result;
};
var isScreenshotCommand = (command) => {
const isScrenshotEndpoint = /\/session\/[^/]*(\/element\/[^/]*)?\/screenshot/;
return (
// WebDriver protocol
command.endpoint && isScrenshotEndpoint.test(command.endpoint) || // DevTools protocol
command.command === "takeScreenshot"
);
};
var getSuiteLabels = ({ tags }) => {
if (!tags) {
return [];
}
return tags.reduce((acc, tag) => {
const label = tag.name.replace(/[@]/, "").split("=");
if (label.length === 2) {
return acc.concat({ name: label[0], value: label[1] });
}
return acc;
}, []);
};
var setAllureIds = (test, suite) => {
if (!test) {
return;
}
const params = test.wrappedItem.parameters.slice();
const paramsPart = params.sort((a, b) => a.name?.localeCompare(b.name)).map((it) => it.name + it.value).join("");
const hash = md5(`${suite?.name}${test.wrappedItem.name}${paramsPart}`);
test.historyId = hash;
if ("labels" in test.wrappedItem) {
if (test.wrappedItem.labels?.find((label) => label.name === LabelName.AS_ID)) {
return;
}
}
test.testCaseId = hash;
};
// src/state.ts
var AllureReporterState = class {
currentFile;
runningUnits = [];
stats = { test: 0, hooks: 0, suites: 0 };
get currentSuite() {
return findLast(this.runningUnits, (unit) => unit instanceof AllureGroup);
}
get currentTest() {
return findLast(this.runningUnits, (unit) => unit instanceof AllureTest);
}
get currentStep() {
return findLast(this.runningUnits, (unit) => unit instanceof AllureStep);
}
get currentHook() {
return findLast(this.runningUnits, (unit) => unit instanceof ExecutableItemWrapper);
}
get currentAllureStepableEntity() {
return findLast(this.runningUnits, (unit) => unit instanceof AllureTest || unit instanceof AllureStep || unit instanceof ExecutableItemWrapper);
}
get currentPackageLabel() {
if (!this.currentFile) {
return void 0;
}
return this.currentFile.replaceAll(sep, ".");
}
push(unit) {
if (unit instanceof AllureGroup) {
this.stats.suites++;
} else if (unit instanceof AllureTest) {
this.stats.test++;
} else {
this.stats.hooks++;
}
this.runningUnits.push(unit);
}
pop() {
return this.runningUnits.pop();
}
};
// src/types.ts
var TYPE = /* @__PURE__ */ ((TYPE2) => {
TYPE2["TEXT"] = "text";
TYPE2["HTML"] = "html";
TYPE2["MARKDOWN"] = "markdown";
return TYPE2;
})(TYPE || {});
// src/reporter.ts
var AllureReporter = class extends WDIOReporter {
_allure;
_capabilities;
_isMultiremote;
_config;
_options;
_consoleOutput;
_originalStdoutWrite;
_state;
_runningUnits = [];
constructor(options = {}) {
const { outputDir = "allure-results", ...rest } = options;
super({
...rest,
outputDir
});
this._consoleOutput = "";
this._originalStdoutWrite = process.stdout.write.bind(process.stdout);
this._allure = new AllureRuntime({
resultsDir: outputDir
});
this._state = new AllureReporterState();
this._capabilities = {};
this._options = options;
this.registerListeners();
const processObj = process;
if (options.addConsoleLogs) {
processObj.stdout.write = (chunk, encoding, callback) => {
if (typeof chunk === "string" && !chunk.includes("mwebdriver")) {
this._consoleOutput += chunk;
}
return this._originalStdoutWrite(chunk, encoding, callback);
};
}
const { reportedEnvironmentVars } = this._options;
if (reportedEnvironmentVars) {
this._allure.writeEnvironmentInfo(reportedEnvironmentVars);
}
}
attachLogs() {
if (!this._consoleOutput || !this._state.currentAllureStepableEntity) {
return;
}
const logsContent = `.........Console Logs.........
${this._consoleOutput}`;
const attachmentFilename = this._allure.writeAttachment(logsContent, ContentType.TEXT);
this._state.currentAllureStepableEntity.addAttachment(
"Console Logs",
{
contentType: ContentType.TEXT
},
attachmentFilename
);
}
attachFile(name, content, contentType) {
if (!this._state.currentAllureStepableEntity) {
throw new Error("There isn't any active test!");
}
const attachmentFilename = this._allure.writeAttachment(content, contentType);
this._state.currentAllureStepableEntity.addAttachment(
name,
{
contentType
},
attachmentFilename
);
}
attachJSON(name, value) {
let isJson = !!value && (typeof value === "object" || Array.isArray(value));
if (typeof value === "string" && (value.trim().startsWith("{") || value.trim().startsWith("["))) {
try {
value = JSON.parse(value);
isJson = !!value;
} catch {
isJson = false;
}
}
const content = isJson ? JSON.stringify(value, null, 2) : value;
this.attachFile(name, String(content), isJson ? ContentType.JSON : ContentType.TEXT);
}
attachScreenshot(name, content) {
this.attachFile(name, content, ContentType.PNG);
}
_startSuite(suiteTitle) {
const newSuite = this._state.currentSuite ? this._state.currentSuite.startGroup() : new AllureGroup2(this._allure);
newSuite.name = suiteTitle;
this._state.push(newSuite);
}
_endSuite() {
if (!this._state.currentSuite) {
throw new Error("There isn't any active suite!");
}
while (this._state.currentAllureStepableEntity) {
const currentElement = this._state.pop();
if (!(currentElement instanceof AllureGroup2)) {
const isAnyStepFailed = currentElement.wrappedItem.steps.some((step2) => step2.status === AllureStatus2.FAILED);
const isAnyStepBroken = currentElement.wrappedItem.steps.some((step2) => step2.status === AllureStatus2.BROKEN);
currentElement.stage = Stage2.FINISHED;
currentElement.status = isAnyStepFailed ? AllureStatus2.FAILED : isAnyStepBroken ? AllureStatus2.BROKEN : AllureStatus2.PASSED;
}
if (currentElement instanceof AllureTest2) {
setAllureIds(currentElement, this._state.currentSuite);
currentElement.endTest();
} else if (currentElement instanceof AllureStep2) {
currentElement.endStep();
}
}
const currentSuite = this._state.pop();
if (this._state.stats.hooks > 0 && this._state.stats.test === 0) {
const test = currentSuite.startTest(currentSuite.name);
test.status = Status3.BROKEN;
test.endTest();
}
currentSuite.endGroup();
}
_startTest(testTitle, cid) {
const newTest = this._state.currentSuite ? this._state.currentSuite.startTest() : new AllureTest2(this._allure);
newTest.name = testTitle;
this._state.push(newTest);
this.setTestParameters(cid);
}
_skipTest() {
if (!this._state.currentAllureStepableEntity) {
return;
}
const currentTest = this._state.pop();
currentTest.stage = Stage2.PENDING;
currentTest.status = AllureStatus2.SKIPPED;
if (currentTest instanceof AllureTest2) {
setAllureIds(currentTest, this._state.currentSuite);
currentTest.endTest();
} else {
currentTest.endStep();
}
}
_endTest(status, error, stage) {
if (!this._state.currentAllureStepableEntity) {
return;
}
const currentSpec = this._state.pop();
currentSpec.stage = stage ?? Stage2.FINISHED;
currentSpec.status = status;
if (error) {
currentSpec.detailsMessage = error.message;
currentSpec.detailsTrace = error.stack;
if (this._state.currentTest) {
this._state.currentTest.statusDetails = { message: error.message, trace: error.stack };
}
}
if (currentSpec instanceof AllureTest2) {
setAllureIds(currentSpec, this._state.currentSuite);
currentSpec.endTest();
} else if (currentSpec instanceof AllureStep2) {
currentSpec.endStep();
}
}
_startStep(testTitle) {
if (!this._state.currentAllureStepableEntity) {
throw new Error("There are no active steppable entities!");
}
const newStep = this._state.currentAllureStepableEntity.startStep(testTitle);
this._state.push(newStep);
}
setTestParameters(cid) {
if (!this._state.currentTest) {
return;
}
if (!this._isMultiremote) {
const caps = this._capabilities;
const { desired, device } = caps;
const deviceName = (desired || {}).deviceName || (desired || {})["appium:deviceName"] || caps.deviceName || caps["appium:deviceName"];
let targetName = device || getBrowserName(caps) || deviceName || cid;
if (desired && deviceName && desired["appium:platformVersion"]) {
targetName = `${device || deviceName} ${desired["appium:platformVersion"]}`;
}
const browserstackVersion = caps.os_version || caps.osVersion;
const version = browserstackVersion || caps.browserVersion || caps.version || caps["appium:platformVersion"] || "";
const paramName = deviceName || device ? "device" : "browser";
const paramValue = version ? `${targetName}-${version}` : targetName;
if (!paramValue) {
return;
}
this._state.currentTest.addParameter(paramName, paramValue);
} else {
this._state.currentTest.addParameter("isMultiremote", "true");
}
this._state.currentTest.addLabel(LabelName2.LANGUAGE, "javascript");
this._state.currentTest.addLabel(LabelName2.FRAMEWORK, "wdio");
if (this._state.currentPackageLabel) {
this._state.currentTest.addLabel(LabelName2.PACKAGE, this._state.currentPackageLabel);
}
if (cid) {
this._state.currentTest.addLabel(LabelName2.THREAD, cid);
}
if (!this._state.currentSuite) {
return;
}
const isFeaturePresent = this._state.currentTest.wrappedItem.labels.some((label) => label.name === LabelName2.FEATURE);
this._state.currentTest.addLabel(LabelName2.SUITE, this._state.currentSuite.name);
if (isFeaturePresent) {
return;
}
this._state.currentTest.addLabel(LabelName2.FEATURE, this._state.currentSuite.name);
}
registerListeners() {
process.on(events.addLink, this.addLink.bind(this));
process.on(events.addLabel, this.addLabel.bind(this));
process.on(events.addAllureId, this.addAllureId.bind(this));
process.on(events.addFeature, this.addFeature.bind(this));
process.on(events.addStory, this.addStory.bind(this));
process.on(events.addSeverity, this.addSeverity.bind(this));
process.on(events.addSuite, this.addSuite.bind(this));
process.on(events.addSubSuite, this.addSubSuite.bind(this));
process.on(events.addOwner, this.addOwner.bind(this));
process.on(events.addTag, this.addTag.bind(this));
process.on(events.addParentSuite, this.addParentSuite.bind(this));
process.on(events.addEpic, this.addEpic.bind(this));
process.on(events.addIssue, this.addIssue.bind(this));
process.on(events.addTestId, this.addTestId.bind(this));
process.on(events.addAttachment, this.addAttachment.bind(this));
process.on(events.addDescription, this.addDescription.bind(this));
process.on(events.startStep, this.startStep.bind(this));
process.on(events.endStep, this.endStep.bind(this));
process.on(events.addStep, this.addStep.bind(this));
process.on(events.addArgument, this.addArgument.bind(this));
process.on(events.addAllureStep, this.addAllureStep.bind(this));
}
onRunnerStart(runner) {
this._config = runner.config;
this._capabilities = runner.capabilities;
this._isMultiremote = runner.isMultiremote || false;
}
onSuiteStart(suite) {
const { useCucumberStepReporter } = this._options;
const isScenario = suite.type === "scenario";
const isFeature = suite.type === "feature";
this._state.currentFile = suite.file;
if (useCucumberStepReporter && isScenario) {
this._startTest(suite.title, suite.cid);
getSuiteLabels(suite).forEach((label) => {
switch (label.name) {
case "issue":
this.addIssue({ issue: label.value, linkName: label.value });
break;
case "testId":
this.addTestId({ testId: label.value, linkName: label.value });
break;
default:
this.addLabel(label);
}
});
if (suite.description) {
this.addDescription(suite);
}
return;
}
const prefix = this._state.currentSuite ? this._state.currentSuite.name + ": " : "";
const suiteTitle = isFeature ? suite.title : prefix + suite.title;
this._startSuite(suiteTitle);
}
onSuiteEnd(suite) {
const { useCucumberStepReporter } = this._options;
const isScenario = suite.type === "scenario";
this._state.currentFile = void 0;
if (useCucumberStepReporter && isScenario) {
suite.hooks = suite.hooks.map((hook) => {
hook.state = hook.state || AllureStatus2.PASSED;
return hook;
});
const suiteChildren = [...suite.tests, ...suite.hooks];
const isSkipped = suite.tests.every((item) => [AllureStatus2.SKIPPED].includes(item.state)) && suite.hooks.every((item) => [AllureStatus2.PASSED, AllureStatus2.SKIPPED].includes(item.state));
if (isSkipped) {
this._endTest(AllureStatus2.SKIPPED, void 0, Stage2.PENDING);
return;
}
const isFailed = suiteChildren.find((item) => item.state === AllureStatus2.FAILED);
if (isFailed) {
const testStatus = getTestStatus(isFailed);
const error = getErrorFromFailedTest(isFailed);
this._endTest(testStatus, error);
return;
}
const isPassed = suiteChildren.every((item) => item.state === AllureStatus2.PASSED);
const isPartiallySkipped = suiteChildren.every((item) => [AllureStatus2.PASSED, AllureStatus2.SKIPPED].includes(item.state));
if (isPassed || isPartiallySkipped) {
this._endTest(AllureStatus2.PASSED);
return;
}
return;
}
this._endSuite();
}
onTestStart(test) {
const { useCucumberStepReporter } = this._options;
this._consoleOutput = "";
if (useCucumberStepReporter) {
const testObj = test;
const argument = testObj?.argument;
const dataTable = argument?.rows?.map((a) => a?.cells);
this._startStep(test.title);
if (dataTable) {
this.attachFile("Data Table", stringify(dataTable), ContentType.CSV);
}
return;
}
this._startTest(test.title, test.cid);
}
onTestPass() {
this.attachLogs();
this._endTest(AllureStatus2.PASSED);
}
onTestRetry(test) {
this.attachLogs();
const status = getTestStatus(test, this._config);
this._endTest(status, getErrorFromFailedTest(test));
}
onTestFail(test) {
const { useCucumberStepReporter } = this._options;
if (useCucumberStepReporter) {
this.attachLogs();
const testStatus = getTestStatus(test, this._config);
this._endTest(testStatus, getErrorFromFailedTest(test));
return;
}
if (!this._state.currentAllureStepableEntity) {
this.onTestStart(test);
} else if (this._state.currentAllureStepableEntity instanceof AllureTest2) {
this._state.currentAllureStepableEntity.name = test.title;
}
this.attachLogs();
const status = getTestStatus(test, this._config);
this._endTest(status, getErrorFromFailedTest(test));
}
onTestSkip(test) {
const { useCucumberStepReporter } = this._options;
this.attachLogs();
if (!this._state.currentAllureStepableEntity || this._state.currentAllureStepableEntity.wrappedItem.name !== test.title) {
if (useCucumberStepReporter) {
this.onTestStart(test);
} else {
this._startTest(test.title, test.cid);
}
}
this._skipTest();
}
onBeforeCommand(beforeCommand) {
if (!this._state.currentAllureStepableEntity) {
return;
}
const { disableWebdriverStepsReporting } = this._options;
if (disableWebdriverStepsReporting || this._isMultiremote) {
return;
}
const { command, method = "", endpoint = "", body, params } = beforeCommand;
const stepName = command ? command : `${method} ${endpoint}`.trim() || "unknown command";
const payload = body || params;
this._startStep(stepName);
if (payload && (typeof payload === "object" || Array.isArray(payload)) && !isEmpty(payload)) {
this.attachJSON("Request", payload);
}
}
onAfterCommand(command) {
const { disableWebdriverStepsReporting, disableWebdriverScreenshotsReporting } = this._options;
const commandResult = command.result?.value || command.result?.error?.name || void 0;
if (!disableWebdriverScreenshotsReporting && isScreenshotCommand(command) && commandResult) {
this.attachScreenshot("Screenshot", Buffer.from(commandResult, "base64"));
}
if (disableWebdriverStepsReporting || this._isMultiremote || !this._state.currentStep) {
return;
}
if (commandResult) {
this.attachJSON("Response", commandResult);
}
this.endStep(AllureStatus2.PASSED);
}
onHookStart(hook) {
const { disableMochaHooks, useCucumberStepReporter } = this._options;
if (!hook.parent || !this._state.currentSuite || disableMochaHooks) {
return;
}
const isAllHook = isAllTypeHooks(hook.title);
const isEachHook = isEachTypeHooks(hook.title);
if (isAllHook || isEachHook) {
const hookExecutable = isBeforeTypeHook(hook.title) ? this._state.currentSuite.addBefore() : this._state.currentSuite.addAfter();
const hookStep = hookExecutable.startStep(hook.title);
this._state.push(hookExecutable);
this._state.push(hookStep);
} else if (!(isAllHook || isEachHook) && !useCucumberStepReporter) {
const customHookTest = this._state.currentSuite.startTest(
`hook:${hook.title}`
);
this._state.push(customHookTest);
} else if (useCucumberStepReporter) {
this.onTestStart(hook);
}
}
onHookEnd(hook) {
const { disableMochaHooks, useCucumberStepReporter } = this._options;
if (!hook.parent || !this._state.currentSuite) {
return;
}
const isAllHook = isAllTypeHooks(hook.title);
const isEachHook = isEachTypeHooks(hook.title);
if ((isAllHook || isEachHook) && !disableMochaHooks) {
const currentHookRootStep = this._state.pop();
const currentHookRoot = this._state.pop();
if (currentHookRootStep || currentHookRoot) {
if (currentHookRootStep instanceof AllureStep2 && currentHookRoot instanceof ExecutableItemWrapper2) {
getHookStatus(hook, currentHookRoot, currentHookRootStep);
currentHookRootStep.endStep();
if (isBeforeTypeHook(hook.title) && (hook.error || hook.errors?.length)) {
this._startTest(hook.currentTest || hook.title, hook.cid);
this._endTest(AllureStatus2.BROKEN, getErrorFromFailedTest(hook));
}
return;
}
if (currentHookRoot) {
this._state.push(currentHookRoot);
}
if (currentHookRootStep) {
this._state.push(currentHookRootStep);
}
}
}
if (disableMochaHooks && hook.error) {
if (useCucumberStepReporter) {
this.onTestStart(hook);
this.onTestFail(hook);
const currentItem = this._state.currentAllureStepableEntity?.wrappedItem;
if (currentItem) {
cleanCucumberHooks(currentItem);
}
return;
}
const hookExecutable = isBeforeTypeHook(hook.title) ? this._state.currentSuite.addBefore() : this._state.currentSuite.addAfter();
const hookStep = hookExecutable.startStep(hook.title);
this._state.stats.hooks++;
getHookStatus(hook, hookExecutable, hookStep);
hookStep.endStep();
return;
}
if (!(isAllHook || isEachHook) && !useCucumberStepReporter) {
const lastElement = this._state.pop();
if (lastElement) {
const isCustomHook = lastElement instanceof AllureTest2 && lastElement.wrappedItem.name?.startsWith("hook:");
this._state.push(lastElement);
if (isCustomHook) {
this._endTest(getTestStatus(hook), hook.error);
}
}
return;
}
if (useCucumberStepReporter && !disableMochaHooks) {
if (hook.error) {
this.onTestFail(hook);
} else {
this.onTestPass();
}
const currentItem = this._state.currentAllureStepableEntity?.wrappedItem;
if (currentItem) {
cleanCucumberHooks(currentItem);
}
return;
}
}
addLabel({
name,
value
}) {
if (!this._state.currentTest) {
return;
}
this._state.currentTest.addLabel(name, value);
}
addLink({
name,
url,
type
}) {
if (!this._state.currentTest) {
return;
}
this._state.currentTest.addLink(url, name, type);
}
addAllureId({
id
}) {
this.addLabel({
name: LabelName2.AS_ID,
value: id
});
}
addStory({
storyName
}) {
this.addLabel({
name: LabelName2.STORY,
value: storyName
});
}
addFeature({
featureName
}) {
this.addLabel({
name: LabelName2.FEATURE,
value: featureName
});
}
addSeverity({
severity
}) {
this.addLabel({
name: LabelName2.SEVERITY,
value: severity
});
}
addEpic({
epicName
}) {
this.addLabel({
name: LabelName2.EPIC,
value: epicName
});
}
addOwner({
owner
}) {
this.addLabel({
name: LabelName2.OWNER,
value: owner
});
}
addSuite({
suiteName
}) {
this.addLabel({
name: LabelName2.SUITE,
value: suiteName
});
}
addParentSuite({
suiteName
}) {
this.addLabel({
name: LabelName2.PARENT_SUITE,
value: suiteName
});
}
addSubSuite({
suiteName
}) {
this.addLabel({
name: LabelName2.SUB_SUITE,
value: suiteName
});
}
addTag({
tag
}) {
this.addLabel({
name: LabelName2.TAG,
value: tag
});
}
addTestId({
testId,
linkName
}) {
if (!this._options.tmsLinkTemplate) {
this.addLabel({
name: "tms",
value: testId
});
return;
}
const tmsLink = getLinkByTemplate(this._options.tmsLinkTemplate, testId);
this.addLink({
url: tmsLink,
name: linkName || "tms",
type: LinkType.TMS
});
}
addIssue({
issue,
linkName
}) {
if (!this._options.issueLinkTemplate) {
this.addLabel({
name: "issue",
value: issue
});
return;
}
const issueLink = getLinkByTemplate(this._options.issueLinkTemplate, issue);
this.addLink({
url: issueLink,
name: linkName,
type: LinkType.ISSUE
});
}
addDescription({
description,
descriptionType
}) {
if (!this._state.currentTest) {
return;
}
if (descriptionType === "html" /* HTML */) {
this._state.currentTest.descriptionHtml = description;
return;
}
this._state.currentTest.description = description;
}
addAttachment({
name,
content,
type = ContentType.TEXT
}) {
if (!this._state.currentAllureStepableEntity) {
return;
}
if (type === ContentType.JSON) {
this.attachJSON(name, content);
return;
}
this.attachFile(name, Buffer.from(content), type);
}
startStep(title) {
if (!this._state.currentAllureStepableEntity) {
return;
}
this._startStep(title);
}
endStep(status) {
if (!this._state.currentAllureStepableEntity) {
return;
}
this._endTest(status);
}
addStep({
step: step2
}) {
if (!this._state.currentAllureStepableEntity) {
return;
}
this._startStep(step2.title);
if (step2.attachment) {
this.attachFile(step2.attachment.name, step2.attachment.content, step2.attachment.type || ContentType.TEXT);
}
this._endTest(step2.status);
}
addArgument({
name,
value
}) {
if (!this._state.currentTest) {
return;
}
this._state.currentTest.addParameter(name, value);
}
addAllureStep(metadata) {
const { currentAllureStepableEntity: currentAllureSpec } = this._state;
if (!currentAllureSpec) {
throw new Error("Couldn't add step: no test case running!");
}
const {
attachments = [],
labels = [],
links = [],
parameter = [],
steps = [],
description,
descriptionHtml
} = metadata;
if (description) {
this.addDescription({
description,
descriptionType: "markdown" /* MARKDOWN */
});
}
if (descriptionHtml) {
this.addDescription({
description: descriptionHtml,
descriptionType: "html" /* HTML */
});
}
labels.forEach((label) => {
this.addLabel(label);
});
parameter.forEach((param) => {
this.addArgument(param);
});
links.forEach((link) => {
this.addLink(link);
});
attachments.forEach((attachment) => {
this.addAttachment(attachment);
});
steps.forEach((step2) => {
currentAllureSpec.addStep(AllureCommandStepExecutable2.toExecutableItem(this._allure, step2));
});
}
/**
* public API attached to the reporter
* deprecated approach and only here for backwards compatibility
*/
static addFeature = addFeature;
static addLink = addLink;
static addEpic = addEpic;
static addOwner = addOwner;
static addTag = addTag;
static addLabel = addLabel;
static addSeverity = addSeverity;
static addIssue = addIssue;
static addSuite = addSuite;
static addSubSuite = addSubSuite;
static addParentSuite = addParentSuite;
static addTestId = addTestId;
static addStory = addStory;
static addDescription = addDescription;
static addAttachment = addAttachment;
static startStep = startStep;
static endStep = endStep;
static addStep = addStep;
static addArgument = addArgument;
static addAllureId = addAllureId;
static step = step;
};
// src/index.ts
var index_default = AllureReporter;
export {
TYPE,
addAllureId,
addArgument,
addAttachment,
addDescription,
addEnvironment,
addEpic,
addFeature,
addIssue,
addLabel,
addLink,
addOwner,
addParentSuite,
addSeverity,
addStep,
addStory,
addSubSuite,
addSuite,
addTag,
addTestId,
index_default as default,
endStep,
startStep,
step
};