UNPKG

playwright-bdd

Version:
171 lines 7.38 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /** * Cucumber html reporter. * Based on: https://github.com/cucumber/cucumber-js/blob/main/src/formatter/html_formatter.ts * See: https://github.com/cucumber/html-formatter * See: https://github.com/cucumber/react-components */ const node_fs_1 = __importDefault(require("node:fs")); const promises_1 = require("node:stream/promises"); const node_stream_1 = require("node:stream"); const html_formatter_1 = require("@cucumber/html-formatter"); const node_path_1 = __importDefault(require("node:path")); const base_1 = __importDefault(require("../base")); const helpers_1 = require("../attachments/helpers"); const skip_1 = require("../attachments/skip"); const external_1 = require("../attachments/external"); const traceViewer_1 = require("./traceViewer"); const utils_1 = require("../../../utils"); const envelopesTransformer_1 = require("./envelopesTransformer"); // Directory for attahcments, relative to reportDir. // We store attachments in subdirectory to not accidentally // bloat the working dir and make it easier to find report html file. // 'data' name is also used in Playwright HTML reporter. const ATTACHMENTS_DIR = 'data'; class HtmlReporter extends base_1.default { constructor(internalOptions, userOptions = {}) { super(internalOptions); this.userOptions = userOptions; this.attachmentsDir = ''; this.attachmentsBaseURL = ''; this.hasTraces = false; this.receivedTestRunFinished = false; this.setOutputStream(this.userOptions.outputFile); if (this.userOptions.externalAttachments) { this.setupAttachmentsDir(); this.setupAttachmentsBaseURL(); } this.htmlStream = new html_formatter_1.CucumberHtmlStream(); this.transformStream = this.createTransformStream(); this.htmlStream.pipe(this.transformStream).pipe(this.outputStream); } async init() { const envelopesTransformer = new envelopesTransformer_1.EnvelopesTransformer(this.messagesBuilder); this.messagesBuilder.getMessages().forEach((origEnvelope) => { // filter out retries, except the last one const envelope = envelopesTransformer.transformEnvelope(origEnvelope); if (!envelope) return; if (envelope.testRunFinished) this.receivedTestRunFinished = true; if ((0, helpers_1.isAttachmentEnvelope)(envelope)) { this.handleAttachment(envelope); } else { this.writeEnvelope(envelope); } }); } async finished() { this.htmlStream.end(); await (0, promises_1.finished)(this.htmlStream); await (0, promises_1.finished)(this.transformStream); if (this.hasTraces) await (0, traceViewer_1.copyTraceViewer)(this.outputDir); await super.finished(); } handleAttachment(envelope) { if ((0, skip_1.shouldSkipAttachment)(envelope, this.userOptions.skipAttachments)) return; // For now don't externalize text attachments, b/c they are not visible in the report. // In the future maybe handle separately 'text/x.cucumber.log+plain', 'text/uri-list'. // See: https://github.com/cucumber/cucumber-js/issues/2430 // See: https://github.com/cucumber/react-components/blob/main/src/components/gherkin/attachment/Attachment.tsx#L32 const isExternalAttachment = this.userOptions.externalAttachments && !(0, external_1.isTextAttachment)(envelope.attachment); const newAttachment = isExternalAttachment ? (0, external_1.toExternalAttachment)(envelope.attachment, this.attachmentsDir, this.attachmentsBaseURL) : (0, external_1.toEmbeddedAttachment)(envelope.attachment); if (isExternalAttachment) this.handleTraceAttachment(newAttachment); this.writeEnvelope({ ...envelope, attachment: newAttachment, }); } writeEnvelope(envelope) { this.htmlStream.write(envelope); } /** * If there is trace attachment, copy trace-viewer to the report * and create additional attachment with trace view link. * - implementation in PW: https://github.com/microsoft/playwright/blob/release-1.50/packages/playwright/src/reporters/html.ts#L434 * - attachmentsBaseURL should start with http(s) to be able to show traces. */ handleTraceAttachment(attachment) { if ((0, traceViewer_1.isTraceAttachment)(attachment)) { this.hasTraces = true; const { testCaseStartedId, testStepId } = attachment; const href = (0, traceViewer_1.generateTraceUrl)(attachment); const newEnvelope = (0, traceViewer_1.createViewTraceLinkAttachment)(testCaseStartedId, testStepId, href); this.writeEnvelope(newEnvelope); } } setupAttachmentsDir() { (0, utils_1.throwIf)(!this.outputDir, 'Unable to externalize attachments when reporter is not writing to a file'); this.attachmentsDir = node_path_1.default.join(this.outputDir, ATTACHMENTS_DIR); if (node_fs_1.default.existsSync(this.attachmentsDir)) node_fs_1.default.rmSync(this.attachmentsDir, { recursive: true }); node_fs_1.default.mkdirSync(this.attachmentsDir, { recursive: true }); } setupAttachmentsBaseURL() { this.attachmentsBaseURL = removeTrailingSlash( // don't prepend '/' to ATTACHMENTS_DIR // to make it work when reporter is opened from file:// protocol. this.userOptions.attachmentsBaseURL || ATTACHMENTS_DIR); } /** * Special transform stream to inject custom script into the HTML. */ createTransformStream() { return new node_stream_1.Transform({ transform: (chunk, _encoding, callback) => { const newChunk = this.receivedTestRunFinished ? this.injectCustomAssets(chunk) : chunk; callback(null, newChunk); }, }); } injectCustomAssets(chunk) { const chunkStr = chunk.toString(); if (chunkStr.includes('</body>')) { const customAssets = [ cssHideLogForCustomHtml, // prettier-ignore traceViewer_1.assetsViewTraceLinks, ].join('\n'); return chunkStr.replace('</body>', `${customAssets}</body>`); } else { return chunk; } } } exports.default = HtmlReporter; function removeTrailingSlash(url) { return url.replace(/\/+$/, ''); } /** * Custom css to adjust log entries for showing custom HTML: * - hide LOG label (it's a ::before pseudo-element) * - hide copy button * - adjust padding */ const cssHideLogForCustomHtml = ` <style> div:has(> pre > span > [data-custom-html])::before { display: none !important; } div:has(> pre > span > [data-custom-html]) > button { display: none !important; } div:has(> pre > span > [data-custom-html]) { padding-left: 0 !important; } div:has(> pre > span > [data-custom-html]) > pre { padding: .666em .75em !important; } </style> `; //# sourceMappingURL=index.js.map