UNPKG

@wdio/allure-reporter

Version:
1,109 lines (1,096 loc) 35.5 kB
// 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 };