Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@reportportal/agent-js-cypress

Package Overview
Dependencies
Maintainers
0
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@reportportal/agent-js-cypress - npm Package Compare versions

Comparing version 5.3.2 to 5.3.3

1

lib/constants.js

@@ -54,2 +54,3 @@ /*

INIT: 'rpInit',
FULL_CONFIG: 'rpFullConfig',
LOG: 'rpLog',

@@ -56,0 +57,0 @@ LAUNCH_LOG: 'rpLaunchLog',

9

lib/cypressReporter.js

@@ -38,4 +38,4 @@ /*

getLaunchStartObject,
getSuiteStartObject,
getSuiteEndObject,
getSuiteStartInfo,
getSuiteEndInfo,
getTestInfo,

@@ -67,2 +67,3 @@ getHookInfo,

const configListener = (cypressFullConfig) => {
this.worker.send({ event: reporterEvents.FULL_CONFIG, config: cypressFullConfig });
CypressReporter.cypressConfig = cypressFullConfig;

@@ -137,3 +138,3 @@ CypressReporter.calcTotalLaunches();

event: EVENT_SUITE_BEGIN,
suite: getSuiteStartObject(suite, this.runner.suite.file),
suite: getSuiteStartInfo(suite, this.runner.suite.file),
});

@@ -144,3 +145,3 @@ });

if (!suite.title) return;
this.worker.send({ event: EVENT_SUITE_END, suite: getSuiteEndObject(suite) });
this.worker.send({ event: EVENT_SUITE_END, suite: getSuiteEndInfo(suite) });
});

@@ -147,0 +148,0 @@

@@ -66,3 +66,3 @@ /*

const request = client.getMergeLaunchesRequest(launchIds);
request.description = config.reporterOptions.description;
request.description = config.description;
request.extendSuitesDescription = false;

@@ -69,0 +69,0 @@ const mergeURL = 'launch/merge';

/*
* Copyright 2020 EPAM Systems
* Copyright 2024 EPAM Systems
*

@@ -27,2 +27,5 @@ * Licensed under the Apache License, Version 2.0 (the "License");

getCodeRef,
getVideoFile,
getSuiteStartObject,
getSuiteEndObject,
} = require('./utils');

@@ -51,3 +54,5 @@

this.hooks = new Map();
this.config = config;
this.config = config.reporterOptions;
this.fullCypressConfig = config;
this.videoPromises = [];

@@ -66,2 +71,6 @@ this.currentTestFinishParams = getInitialTestFinishParams();

saveFullConfig(config) {
this.fullCypressConfig = config;
}
resetCurrentTestFinishParams() {

@@ -73,3 +82,3 @@ this.currentTestFinishParams = getInitialTestFinishParams();

const { tempId, promise } = this.client.startLaunch(launchObj);
const { launch, isLaunchMergeRequired } = this.config.reporterOptions;
const { launch, isLaunchMergeRequired } = this.config;
if (isLaunchMergeRequired) {

@@ -83,3 +92,3 @@ createMergeLaunchLockFile(launch, tempId);

runEnd() {
const basePromise = this.config.reporterOptions.launchId
const basePromise = this.config.launchId
? this.client.getPromiseFinishAllItems(this.tempLaunchId)

@@ -96,5 +105,5 @@ : this.client.finishLaunch(

const finishLaunchPromise = basePromise
const finishLaunchPromise = Promise.allSettled([basePromise, ...this.videoPromises])
.then(() => {
const { launch, isLaunchMergeRequired } = this.config.reporterOptions;
const { launch, isLaunchMergeRequired } = this.config;
if (isLaunchMergeRequired) {

@@ -105,3 +114,3 @@ deleteMergeLaunchLockFile(launch, this.tempLaunchId);

.then(() => {
const { parallel, autoMerge } = this.config.reporterOptions;
const { parallel, autoMerge } = this.config;
if (!(parallel && autoMerge)) {

@@ -118,28 +127,101 @@ return Promise.resolve();

const parentId = suite.parentId && this.testItemIds.get(suite.parentId);
const { tempId, promise } = this.client.startTestItem(suite, this.tempLaunchId, parentId);
const startSuiteObj = getSuiteStartObject(suite);
const { tempId, promise } = this.client.startTestItem(
startSuiteObj,
this.tempLaunchId,
parentId,
);
promiseErrorHandler(promise, 'Fail to start suite');
this.testItemIds.set(suite.id, tempId);
this.suitesStackTempInfo.push({ tempId, startTime: suite.startTime });
this.suitesStackTempInfo.push({
tempId,
startTime: suite.startTime,
title: suite.title || '',
id: suite.id,
testFileName: suite.testFileName,
});
}
suiteEnd(suite) {
const suiteId = this.testItemIds.get(suite.id);
const { uploadVideo = false } = this.config;
const { video: isVideoRecordingEnabled = false } = this.fullCypressConfig;
const isRootSuite =
this.suitesStackTempInfo.length && suite.id === this.suitesStackTempInfo[0].id;
const suiteFinishObj = this.prepareSuiteToFinish(suite);
if (isVideoRecordingEnabled && uploadVideo && isRootSuite) {
const suiteInfo = this.suitesStackTempInfo[0];
this.finishSuiteWithVideo(suiteInfo, suiteFinishObj);
} else {
const suiteTempId = this.testItemIds.get(suite.id);
this.finishSuite(suiteFinishObj, suiteTempId);
}
this.suitesStackTempInfo.pop();
}
prepareSuiteToFinish(suite) {
const suiteTestCaseId = this.suiteTestCaseIds.get(suite.title);
const suiteStatus = this.suiteStatuses.get(suite.title);
const finishTestItemPromise = this.client.finishTestItem(
suiteId,
Object.assign(
{
endTime: new Date().valueOf(),
},
suiteTestCaseId && { testCaseId: suiteTestCaseId },
suiteStatus && { status: suiteStatus },
),
).promise;
promiseErrorHandler(finishTestItemPromise, 'Fail to finish suite');
this.suitesStackTempInfo.pop();
let suiteFinishObj = getSuiteEndObject(suite);
suiteFinishObj = {
...suiteFinishObj,
status: suiteStatus || suite.status,
...(suiteTestCaseId && { testCaseId: suiteTestCaseId }),
};
suiteTestCaseId && this.suiteTestCaseIds.delete(suite.title);
suiteStatus && this.suiteStatuses.delete(suite.title);
return suiteFinishObj;
}
finishSuite(suiteFinishObj, suiteTempId) {
const finishTestItemPromise = this.client.finishTestItem(suiteTempId, suiteFinishObj).promise;
promiseErrorHandler(finishTestItemPromise, 'Fail to finish suite');
}
finishSuiteWithVideo(suiteInfo, suiteFinishObj) {
const uploadVideoOnPasses = this.config.uploadVideoOnPasses || false;
const suiteFailed = suiteFinishObj.status === testItemStatuses.FAILED;
// do not upload video if root suite passes and uploadVideoOnPasses is false
if ((!suiteFailed && !uploadVideoOnPasses) || !suiteInfo.testFileName) {
this.finishSuite(suiteFinishObj, suiteInfo.tempId);
} else {
const sendVideoPromise = this.sendVideo(suiteInfo).finally(() => {
this.finishSuite(suiteFinishObj, suiteInfo.tempId);
});
this.videoPromises.push(sendVideoPromise);
}
}
async sendVideo(suiteInfo) {
const { waitForVideoTimeout, waitForVideoInterval, videosFolder } = this.config;
const { testFileName, tempId, title } = suiteInfo;
const file = await getVideoFile(
testFileName,
videosFolder,
waitForVideoTimeout,
waitForVideoInterval,
);
if (!file) {
return null;
}
const sendVideoPromise = this.client.sendLog(
tempId,
{
message: `Video: '${title}' (${testFileName}.mp4)`,
level: logLevels.INFO,
time: new Date().valueOf(),
},
file,
).promise;
promiseErrorHandler(sendVideoPromise, 'Fail to save video');
return sendVideoPromise;
}
testStart(test) {

@@ -188,3 +270,3 @@ const parentId = this.testItemIds.get(test.parentId);

testId,
getTestEndObject(testInfo, this.config.reporterOptions.skippedIssue),
getTestEndObject(testInfo, this.config.skippedIssue),
).promise;

@@ -389,2 +471,6 @@ promiseErrorHandler(finishTestItemPromise, 'Fail to finish test');

this.suiteStatuses.set(suiteTitle, status);
const rootSuite = this.suitesStackTempInfo.length && this.suitesStackTempInfo[0];
if (rootSuite && status === testItemStatuses.FAILED) {
this.suitesStackTempInfo[0].status = status;
}
} else {

@@ -399,11 +485,15 @@ Object.assign(this.currentTestFinishParams, status && { status });

sendScreenshot(screenshotInfo, logMessage) {
async sendScreenshot(screenshotInfo, logMessage) {
const tempItemId = this.currentTestTempInfo && this.currentTestTempInfo.tempId;
const fileName = screenshotInfo.path;
if (!fileName || !tempItemId) return;
if (!fileName || !tempItemId) {
return;
}
const level = fileName && fileName.includes('(failed)') ? logLevels.ERROR : logLevels.INFO;
const file = getScreenshotAttachment(fileName);
if (!file) return;
const file = await getScreenshotAttachment(fileName);
if (!file) {
return;
}

@@ -410,0 +500,0 @@ const message = logMessage || `screenshot ${file.name}`;

/*
* Copyright 2022 EPAM Systems
* Copyright 2024 EPAM Systems
*

@@ -24,10 +24,15 @@ * Licensed under the Apache License, Version 2.0 (the "License");

const fsPromises = fs.promises;
const { FAILED, PASSED, SKIPPED } = testItemStatuses;
const base64Encode = (file) => {
const bitmap = fs.readFileSync(file);
const DEFAULT_WAIT_FOR_FILE_TIMEOUT = 10000;
const DEFAULT_WAIT_FOR_FILE_INTERVAL = 500;
const base64Encode = async (filePath) => {
const bitmap = await fsPromises.readFile(filePath);
return Buffer.from(bitmap).toString('base64');
};
const getScreenshotAttachment = (absolutePath) => {
const getScreenshotAttachment = async (absolutePath) => {
if (!absolutePath) return absolutePath;

@@ -38,6 +43,59 @@ const name = absolutePath.split(path.sep).pop();

type: 'image/png',
content: base64Encode(absolutePath),
content: await base64Encode(absolutePath),
};
};
const waitForFile = (
globFilePath,
timeout = DEFAULT_WAIT_FOR_FILE_TIMEOUT,
interval = DEFAULT_WAIT_FOR_FILE_INTERVAL,
) =>
new Promise((resolve, reject) => {
let totalTime = 0;
async function checkFileExistence() {
const files = await glob(globFilePath);
if (files.length) {
resolve(files[0]);
} else if (totalTime >= timeout) {
reject(new Error(`Timeout of ${timeout}ms reached, file ${globFilePath} not found.`));
} else {
totalTime += interval;
setTimeout(checkFileExistence, interval);
}
}
checkFileExistence().catch(reject);
});
const getVideoFile = async (
specFileName,
videosFolder = '**',
timeout = DEFAULT_WAIT_FOR_FILE_TIMEOUT,
interval = DEFAULT_WAIT_FOR_FILE_INTERVAL,
) => {
if (!specFileName) {
return null;
}
const fileName = specFileName.toLowerCase().endsWith('.mp4')
? specFileName
: `${specFileName}.mp4`;
const globFilePath = `**/${videosFolder}/${fileName}`;
let videoFilePath;
try {
videoFilePath = await waitForFile(globFilePath, timeout, interval);
} catch (e) {
console.warn(e.message);
return null;
}
return {
name: fileName,
type: 'video/mp4',
content: await base64Encode(videoFilePath),
};
};
const getCodeRef = (testItemPath, testFileName) =>

@@ -119,20 +177,39 @@ `${testFileName.replace(/\\/g, '/')}/${testItemPath.join('/')}`;

const getSuiteStartObject = (suite, testFileName) => ({
const getSuiteStartInfo = (suite, testFileName) => ({
id: suite.id,
type: entityType.SUITE,
name: suite.title.slice(0, 255).toString(),
title: suite.title,
startTime: new Date().valueOf(),
description: suite.description,
attributes: [],
codeRef: getCodeRef(suite.titlePath(), testFileName),
parentId: !suite.root ? suite.parent.id : undefined,
testFileName: testFileName.split(path.sep).pop(),
});
const getSuiteEndInfo = (suite) => {
let failed = false;
if (suite.tests != null) {
failed = suite.tests.some((test) => test.state === testItemStatuses.FAILED);
}
return {
id: suite.id,
status: failed ? testItemStatuses.FAILED : undefined,
title: suite.title,
endTime: new Date().valueOf(),
};
};
const getSuiteStartObject = (suite) => ({
type: entityType.SUITE,
name: suite.title.slice(0, 255).toString(),
startTime: suite.startTime,
description: suite.description,
codeRef: suite.codeRef,
attributes: [],
});
const getSuiteEndObject = (suite) => ({
id: suite.id,
title: suite.title,
endTime: new Date().valueOf(),
status: suite.status,
endTime: suite.endTime,
});
// TODO: update/split to not return the redundant and confusing data for items start
const getTestInfo = (test, testFileName, status, err) => ({

@@ -269,2 +346,4 @@ id: test.id,

getTestInfo,
getSuiteStartInfo,
getSuiteEndInfo,
getTestEndObject,

@@ -278,2 +357,3 @@ getHookInfo,

getSpecPattern,
getVideoFile,
};

@@ -41,2 +41,5 @@ /*

break;
case reporterEvents.FULL_CONFIG:
reporter.saveFullConfig(message.config);
break;
case EVENT_RUN_BEGIN:

@@ -43,0 +46,0 @@ reporter.runStart(message.launch);

{
"name": "@reportportal/agent-js-cypress",
"version": "5.3.2",
"version": "5.3.3",
"description": "This agent helps Cypress to communicate with Report Portal",

@@ -34,12 +34,12 @@ "main": "index.js",

"devDependencies": {
"@types/jest": "^29.5.3",
"cypress": "^13.12.0",
"eslint": "^8.45.0",
"@types/jest": "^29.5.12",
"cypress": "^13.13.0",
"eslint": "^8.57.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-cypress": "2.12.1",
"eslint-plugin-import": "^2.27.5",
"eslint-config-prettier": "^8.10.0",
"eslint-plugin-cypress": "2.15.2",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jest": "^23.20.0",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^29.6.1",
"jest": "^29.7.0",
"mock-fs": "^4.14.0",

@@ -46,0 +46,0 @@ "prettier": "^2.8.8"

@@ -137,3 +137,7 @@ # @reportportal/agent-js-cypress

| restClientConfig | Optional | Not set | `axios` like http client [config](https://github.com/axios/axios#request-config). May contain `agent` property for configure [http(s)](https://nodejs.org/api/https.html#https_https_request_url_options_callback) client, and other client options eg. `timeout`. For debugging and displaying logs you can set `debug: true`. |
| autoMerge | Optional | false | Enable automatic report test items of all runned spec into one launch. You should install plugin or setup additional settings in reporterOptions. See [Automatically merge launch](#automatically-merge-launches). |
| uploadVideo | Optional | false | Whether to upload the Cypress video. |
| uploadVideoOnPasses | Optional | false | Whether to upload the Cypress video for a non-failure specs. Works only if `uploadVideo` set to `true`. |
| waitForVideoTimeout | Optional | 10000 | Value in `ms`. Since Cypress video processing may take extra time after the spec is complete, there is a timeout to wait for the video file readiness. Works only if `uploadVideo` set to `true`. |
| waitForVideoInterval | Optional | 500 | Value in `ms`. Interval to check if the video file is ready. The interval is used until `waitForVideoTimeout` is reached. Works only if `uploadVideo` set to `true`. |
| autoMerge | Optional | false | Enable automatic report test items of all run spec into one launch. You should install plugin or setup additional settings in reporterOptions. See [Automatically merge launch](#automatically-merge-launches). |
| reportHooks | Optional | false | Determines report before and after hooks or not. |

@@ -156,3 +160,2 @@ | isLaunchMergeRequired | Optional | false | Allows to merge Cypress run's into one launch at the end of the run. Needs additional setup. See [Manual merge launches](#manual-merge-launches). |

};
```

@@ -159,0 +162,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc