@chtsinc/ch-playwright-report
Version:
Custom Playwright Reporter that logs test and execution results to MongoDB
252 lines • 12 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const ch_logger_1 = require("@chtsinc/ch-logger");
const ch_javascript_sdk_1 = require("@chtsinc/ch-javascript-sdk");
const execution_context_loader_1 = require("./reporter-setup/execution-context-loader");
const service_config_loader_1 = require("./reporter-setup/service-config-loader");
const test_report_util_1 = require("./utils/test-report-util");
const execution_report_util_1 = require("./utils/execution-report-util");
const session_report_util_1 = require("./utils/session-report-util");
const test_status_summary_util_1 = require("./utils/test-status-summary-util");
const video_upload_util_1 = require("./utils/video-upload-util");
const validation_util_1 = require("./utils/validation-util");
const email_util_1 = require("./utils/email-util");
const report_upload_util_1 = require("./utils/report-upload-util");
class CHPlaywrightReporter {
constructor() {
this.logger = (0, ch_logger_1.getLogger)();
this.isInitSuccess = false;
this.executionReport = null;
this.testStatusSummary = null;
this.videosCollection = [];
}
async onBegin(_config, suite) {
//initializing reporter
await this.initializeReport();
if (!this.isInitSuccess) {
return;
}
try {
//setting browser name
this.setBrowserNameForReport(_config, suite);
//creating execution report
this.executionReport = execution_report_util_1.ExecutionReportUtil.createExecutionReport(this.executionContext);
this.executionReport.expectedTestCounts = suite.allTests().length;
//exporting execution report
await this.exportService.exportExecutionReport(this.executionReport);
this.testStatusSummary = new test_status_summary_util_1.TestStatusSummaryUtil();
this.logger.info(`CHPlaywrightReporter started for executionId=${this.executionReport.executionId} with totalTests=${this.executionReport.expectedTestCounts} and start time = ${this.executionReport.executionStartTime}`);
}
catch (error) {
this.isInitSuccess = false;
this.logger.error("CHPlaywrightReporter: Error during onBegin", error);
}
}
async onTestBegin(_test, _result) { }
async onTestEnd(test, result) {
if (!this.isInitSuccess) {
return;
}
//creating test report
let testReport = test_report_util_1.TestReportUtil.createTestReport(this.executionContext);
try {
//processing test report
testReport = test_report_util_1.TestReportUtil.populateTestReport(test, result, testReport);
//exporting test report
await this.exportService.exportTestReport(testReport);
this.logger.info(`CHPlaywrightReporter – Test completed | test=${test.title} | status=${result.status} | duration=${result.duration}ms`);
this.testStatusSummary?.addResult(result);
}
catch (error) {
this.logger.error("CHPlaywrightReporter: Error uploading test report", error);
}
try {
this.collectVideoPath(test, result, testReport.sessionId);
}
catch (error) {
this.logger.error("CHPlaywrightReporter: Error collecting test videos", error);
}
}
async onStepBegin(_test, _result, _step) { }
async onStepEnd(_test, _result, _step) { }
async onEnd(result) {
if (!this.isInitSuccess) {
return;
}
try {
this.executionReport = validation_util_1.ValidationUtil.assertNotNull(this.executionReport, "ExecutionReport");
//processing execution report
this.executionReport = execution_report_util_1.ExecutionReportUtil.finalizeExecutionReport(this.executionReport);
//exporting execution report
await this.exportService.exportExecutionReport(this.executionReport);
this.logger.info(`CHPlaywrightReporter completed for executionId=${this.executionReport.executionId} - duration=${result.duration}ms`);
}
catch (error) {
this.logger.error("CHPlaywrightReporter: Error uploading execution report", error);
}
//uploading and exporting test videos to session reports
try {
const isVideosUploaded = await this.processVideoCollection();
if (isVideosUploaded) {
this.logger.info(`CHPlaywrightReporter - Completed video upload`);
}
else {
this.logger.info(`CHPlaywrightReporter - No videos to upload`);
}
}
catch (error) {
this.logger.error("CHPlaywrightReporter: Error uploading videos", error);
}
//uploading report
let reportUrl = null;
if (this.servicesConfig?.isReportUploadEnabled == true) {
try {
reportUrl = await report_upload_util_1.ReportUploadUtil.uploadReportFile(this.servicesConfig, this.testStatusSummary, this.executionReport);
if (!reportUrl) {
this.logger.info(`CHPlaywrightReporter: Report URL is null`);
}
else {
this.logger.info(`CHPlaywrightReporter - Completed Report upload`);
}
}
catch (error) {
this.logger.error("CHPlaywrightReporter: Error uploading report", error);
}
}
else {
this.logger.debug(`CHPlaywrightReporter: Report upload is not enabled`);
}
//sending test summary email
const files = "";
if (this.servicesConfig?.isEmailEnabled == true) {
try {
await email_util_1.EmailUtil.sendEmail(this.servicesConfig, this.testStatusSummary, this.executionReport, reportUrl, files);
this.logger.info(`CHPlaywrightReporter - Test summary email sent`);
}
catch (error) {
this.logger.error("CHPlaywrightReporter: Error sending email", error);
}
}
else {
this.logger.debug(`CHPlaywrightReporter: Email Service is not enabled`);
}
try {
this.exportService.stopService();
}
catch (error) {
this.logger.error("CHPlaywrightReporter: Error in shutting down services", error);
}
}
collectVideoPath(test, result, id) {
if (this.servicesConfig?.isVideoUploadEnabled == true) {
try {
const videoPath = this.getVideoPath(result);
this.videosCollection.push({
videoPath: videoPath,
sessionId: id,
});
}
catch (error) {
this.logger.debug(`CHPlaywrightReporter: No video found for test: ${test.title} - ${error}`);
}
}
else {
this.logger.debug(`CHPlaywrightReporter: Video upload is not enabled for ${test.title}`);
}
}
async processVideoCollection() {
if (this.videosCollection.length == 0) {
this.logger.info(`CHPlaywrightReporter: Videos collection empty`);
return false;
}
//processing videos from collection, uploading
for (const { videoPath, sessionId } of this.videosCollection) {
let sessionReport = session_report_util_1.SessionReportUtil.createSessionReport(this.executionContext, sessionId);
let videoUrl = null;
videoUrl = await video_upload_util_1.VideoUploadUtil.uploadVideoFile(videoPath, this.servicesConfig, sessionReport);
if (!videoUrl) {
this.logger.error(`CHPlaywrightReporter:Video upload failed (session=${sessionReport.sessionInfo.sessionId}, exec=${sessionReport.executionId}) for file: ${videoPath}`);
continue;
}
//processing session report
sessionReport = session_report_util_1.SessionReportUtil.populateSessionReport(videoUrl, sessionReport);
try {
//exporting session report
await this.exportService.exportSessionReport(sessionReport);
}
catch (error) {
this.logger.error(`CHPlaywrightReporter: Failed to export session report for video: ${videoUrl}`, error);
}
}
return true;
}
getVideoPath(result) {
if (!result.attachments) {
throw new Error("No attachments found in the test result.");
}
const videoAttachments = result.attachments
.filter((att) => att.name === "video" &&
typeof att.path === "string" &&
fs_1.default.existsSync(att.path))
.map((att) => ({
path: att.path,
size: fs_1.default.statSync(att.path).size,
}));
if (videoAttachments.length === 0) {
throw new Error("No valid video attachment found or video file does not exist.");
}
const largestVideo = videoAttachments.reduce((max, current) => current.size > max.size ? current : max);
return largestVideo.path;
}
async initializeReport() {
this.logger.info(`CHPlaywrightReporter: Initializing Reporter`);
try {
this.executionContext = validation_util_1.ValidationUtil.assertNotNull((0, execution_context_loader_1.loadExecutionContext)(), "ExecutionContext");
this.servicesConfig = validation_util_1.ValidationUtil.assertNotNull((0, service_config_loader_1.loadServiceConfig)(), "ServicesContext");
const serviceConfigPath = path_1.default.resolve(process.cwd(), "ch-services.json");
this.exportService = validation_util_1.ValidationUtil.assertNotNull(new ch_javascript_sdk_1.ExportService(serviceConfigPath), "ExportService");
await this.exportService.startService();
this.isInitSuccess = true;
}
catch (error) {
this.logger.error("CHPlaywrightReporter: Error initializing reporter", error);
}
}
getBrowserNameByProjectConfig(config, suite) {
const runningProjectName = suite.suites.length > 0 ? suite.suites[0]?.title : "";
const matchedProject = config.projects.find((project) => project.name === runningProjectName);
const playwrightBrowser = matchedProject?.use?.browserName ||
matchedProject?.use?.defaultBrowserType ||
"chromium";
switch (playwrightBrowser.toLowerCase()) {
case "chromium":
return "Chrome";
case "webkit":
return "Safari";
case "firefox":
return "Firefox";
default:
return "Chrome";
}
}
setBrowserNameForReport(config, suite) {
const playwrightBrowserName = this.getBrowserNameByProjectConfig(config, suite);
const formFactor = this.executionContext.formFactor?.toLowerCase();
const isMobileOrTablet = formFactor === "mobile" || formFactor === "tablet";
const executionContextBrowser = this.executionContext.browserName;
const isBrowserNameMissing = !executionContextBrowser || executionContextBrowser.trim() === "";
if (isBrowserNameMissing) {
this.executionContext.browserName = playwrightBrowserName;
}
if (isMobileOrTablet && playwrightBrowserName.toLowerCase() === "safari") {
this.executionContext.browserName = playwrightBrowserName;
}
}
}
exports.default = CHPlaywrightReporter;
//# sourceMappingURL=ch-playwright-reporter.js.map