New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

cypress-aiotests-reporter

Package Overview
Dependencies
Maintainers
0
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cypress-aiotests-reporter - npm Package Compare versions

Comparing version 1.4.2 to 1.5.0

.github/workflows/integration.yml

10

cypress.config-hosted.js

@@ -14,3 +14,3 @@ const { defineConfig } = require("cypress");

"hosted" : {
"jiraUrl": "https://jira8.aioreports.com",
"jiraUrl": "https://jira.aiojiraapps.com",
"jiraPAT": "",

@@ -26,3 +26,3 @@ "jiraUsername": "",

"folder": ["Cloud","Smoke Test Nightly"],
"tasks": ["NVTES-1"]
"tasks": ["NVTES-1"],
},

@@ -32,5 +32,9 @@ "addNewRun": false,

"createNewRunForRetries": false,
"addTestBodyToComments": true
"addTestBodyToComments": true,
"parallelBuild":{
"masterBuild": true,
"waitForSeconds": 10
}
}
}
});

@@ -20,6 +20,6 @@ const { defineConfig } = require("cypress");

"createNewCycle": false,
"cycleName": "Cypress nightly runs ",
"cycleName": "Cypress nightly runs 4",
"cycleKey": "NVTES-CY-65",
"folder": ["Cloud","Smoke Test Nightly"],
"tasks": ["NVTES-1"]
"tasks": ["NVTES-1"],
},

@@ -30,5 +30,9 @@ "addNewRun": false,

"addTestBodyToComments": true,
"debugMode": true
"debugMode": true,
"parallelBuild":{
"masterBuild": true,
"waitForSeconds": 10
}
}
}
});
{
"name": "cypress-aiotests-reporter",
"version": "1.4.2",
"version": "1.5.0",
"description": "Plugin to report cypress results to AIO Tests Jira",

@@ -5,0 +5,0 @@ "main": "src/index.js",

@@ -108,8 +108,46 @@ [![CI](https://github.com/aiotests/cypress-aiotests-reporter/actions/workflows/main.yml/badge.svg)](https://github.com/aiotests/cypress-aiotests-reporter/actions/workflows/main.yml)

"cycleDetails": {
"createNewCycle": true,
"createNewCycle": true, //possible values "true","false","CREATE_IF_ABSENT", true, false
"cycleName": "Cypress first run from plugin",
"cycleKey": "NVTES-CY-2",
"folder": ["Cloud","Smoke Test Nightly"],
"tasks": ["SCRUM-1","SCRUM-2]
"tasks": ["SCRUM-1","SCRUM-2],
"customFields": [
{
"name": "Reviewed? [Boolean CF]",
"value": "Yes",
},
{
"name": "Set (Single Select CF)",
"value": {"value":"P1"}
},
{
"name": "Teams (Multi Select CF)",
"value": [{"value":"TeamAlpha"},{"value":"Zeta"}]
},
{
"name": "NumberCF", "value": 0
},
{
"name": "TextValue CF", "value": "This can be a long note",
},
{
"name": "Reviewed Date", "value": "2024-08-29T04:38:36.437Z",
},
{
"name": "SME [User CF]", "value": "<accountid of user>"
}
],
},
"runDetails": {
"customFieldsToUpdate": [
{
"operationType": "ADD_TO_EXISTING",
"name": "StepOwner",
"value": [{"value": "Val2"},{"value": "Val1"}]
},
{
"name": "Env", "value": {"value":"UAT"}
}
]
},
"addNewRun": true,

@@ -119,3 +157,7 @@ "addAttachmentToFailedCases": true,

"addTestBodyToComments": true,
"debugMode": false
"debugMode": false,
"parallelBuild":{ //optional
"masterBuild": true,
"waitForSeconds": 10 //defaults to 2 seconds
}
}

@@ -149,8 +191,46 @@ }

"cycleDetails": {
"createNewCycle": true,
"createNewCycle": true, //possible values "true","false","CREATE_IF_ABSENT", true, false
"cycleName": "Cypress Nightly Run ",
"cycleKey": "SERV-CY-2",
"folder": ["Server","Smoke Test Nightly"],
"tasks": ["SERV-1","SERV-2]
"tasks": ["SERV-1","SERV-2],
"customFields": [
{
"name": "Reviewed? [Boolean CF]",
"value": "Yes",
},
{
"name": "Set (Single Select CF)",
"value": {"value":"P1"}
},
{
"name": "Teams (Multi Select CF)",
"value": [{"value":"TeamAlpha"},{"value":"Zeta"}]
},
{
"name": "NumberCF", "value": 0
},
{
"name": "TextValue CF", "value": "This can be a long note",
},
{
"name": "Reviewed Date", "value": "2024-08-29T04:38:36.437Z",
},
{
"name": "SME [User CF]", "value": "<accountid of user>"
}
],
},
"runDetails": {
"customFieldsToUpdate": [
{
"operationType": "ADD_TO_EXISTING",
"name": "StepOwner",
"value": [{"value": "Val2"},{"value": "Val1"}]
},
{
"name": "Env", "value": {"value":"UAT"}
}
]
},
"addNewRun": true,

@@ -160,3 +240,7 @@ "addAttachmentToFailedCases": false,

"addTestBodyToComments": true,
"debugMode": false
"debugMode": false,
"parallelBuild":{ //optional
"masterBuild": true,
"waitForSeconds": 10 //defaults to 2 seconds
}
}

@@ -170,18 +254,38 @@ }

| Value | Description |
|-----------------------------|------------------------------------------------------------------------------------------------------|
| enableReporting | Set to true to make the current run update results to AIO Tests. Default false. |
| jiraProjectId | Jira Project key to update results to |
| cycleDetails.createNewCycle | Set to true to create a new cycle for run being reported |
| cycleDetails.cycleName | Works if createNewCycle is true, sets the cycle name of cycle getting created |
| cycleDetails.cycleKey | AIO Tests cycle key that should be updated. Used if createNewCycle is false |
| cycleDetails.folder | Folder hierarchy, where first item in array is parent folder and so on eg.["Parent","Child"] |
| cycleDetails.tasks | List of Jira Issue Keys to attach as Tasks to created cycle, impacts only when creating new cycle |
| addNewRun | Create a new run or update an existing run in the cycle |
| addAttachmentToFailedCases | Set to true to attach screenshots, if available, for failed cases |
| createNewRunForRetries | Set to true if each retry should create a new run |
| addTestBodyToComments | Set to true test script body should be added as a comment in a failed case. Doesn't work above v12.x |
| debugMode | Default false. Set to true to increase verbosity of logs while debugging an issue |
| Value | Description |
|------------------------------------|----------------------------------------------------------------------------------------------------------|
| enableReporting | Set to true to make the current run update results to AIO Tests. Default false. |
| jiraProjectId | Jira Project key to update results to |
| cycleDetails.createNewCycle | Options: [true, false, "CREATE_IF_ABSENT"]. Set to true to create a new cycle for run being reported. |
| cycleDetails.cycleName | Works if createNewCycle is true, sets the cycle name of cycle getting created |
| cycleDetails.cycleKey | AIO Tests cycle key that should be updated. Used if createNewCycle is false |
| cycleDetails.folder | Folder hierarchy, where first item in array is parent folder and so on eg.["Parent","Child"] |
| cycleDetails.tasks | List of Jira Issue Keys to attach as Tasks to created cycle, impacts only when creating new cycle |
| cycleDetails.customFields | List of custom fields that need to be set while creating cycle. Options shown in example. |
| addNewRun | Create a new run or update an existing run in the cycle |
| addAttachmentToFailedCases | Set to true to attach screenshots, if available, for failed cases |
| createNewRunForRetries | Set to true if each retry should create a new run |
| addTestBodyToComments | Set to true test script body should be added as a comment in a failed case. **Doesn't work above v12.x** |
| runDetails.customFieldsToUpdate | List of run level custom fields. Options in example above. |
| customFieldsToUpdate.operationType | Options: ADD_TO_EXISTING, REPLACE_EXISTING, DELETE_EXISTING |
| debugMode | Default false. Set to true to increase verbosity of logs while debugging an issue |
| parallelBuild.masterBuild | Optional. Default true. See below for details on parallelBuild |
| parallelBuild.waitForSeconds | Optional. Default 2 seconds. See below for details on parallelBuild |
#### Create New Cycle options
- createNewCycle = true or "true", uses the **cycleName** and cycleDetails value to generate new cycle
- createNewCycle = false or "false", uses the **cycleKey** value to find an existing cycle and updates the cycle. If cycle is not found, an error is thrown
- createNewCycle = "CREATE_IF_ABSENT" uses the **cycleName** to search for an existing cycle with an exact match. If cycle is found, then the cycle is updated.
If it is not found, then a new cycle is created using **cycleName** and **cycleDetails**
#### Parallel builds
If multiple builds are being triggered in parallel, the parallelBuild setting can be used to specify the masterBuild.
One of the parallel builds can be configured to set **masterBuild as true**. This build should have createNewCycle either set as true or CREATE_IF_ABSENT.
The other builds running in parallel can have masterBuild set to false, which would imply, they would wait for the masterBuild to run the cycle creation code, waiting for
**waitForSeconds** (defaults to 2 seconds), before trying to find the cycle.
If multiple builds are not being run in parallel, the parallelBuild value can be ignored.
# Logging

@@ -188,0 +292,0 @@

@@ -7,4 +7,7 @@ const axios = require('axios');

const rateLimitWaitTime = 60*1000;
const CREATE_IF_ABSENT = "CREATE_IF_ABSENT";
const createNewCycleOptions = [true, false, "true", "false", CREATE_IF_ABSENT];
let aioAPIClient = null;
let debugMode = false;
let allCaseKeys = [];
function sleep(ms) {

@@ -62,2 +65,51 @@ return new Promise(resolve => setTimeout(resolve, ms));

let isAttachmentAPIAvailable = null;
function getCustomFieldValueToUpdate(customFieldsToUpdate) {
let cfUpdates = [];
if(customFieldsToUpdate) {
customFieldsToUpdate.forEach(cf => {
let data = {"customValue":{"name":cf.name, "value": cf.value}};
if(cf.operationType) {
data["customFieldUpdateOperationType"] = cf.operationType;
}
cfUpdates.push(data);
})
}
return cfUpdates;
}
const updateRunFields = async function (aioConfig){
if(allCaseKeys.length === 0){
aioLogger.debug("No cases to update for bulk update of run custom fields.")
return Promise.resolve();
}
const cfUpdates = getCustomFieldValueToUpdate(aioConfig.runDetails.customFieldsToUpdate);
if(!cfUpdates.length) {
aioLogger.debug("No custom fields data found.")
return Promise.resolve();
}
let data = {
"testRunSearchRequest": {
"key": {
"comparisonType": "IN",
"list": allCaseKeys
}},
"testRunBulkUpdateRequest": {"customFieldValueToUpdate" : cfUpdates}
}
aioLogger.debug("Posting run fields to " + `/project/${aioConfig.jiraProjectId}/testcycle/${aioConfig.cycleDetails.cycleKeyToReportTo}/bulk/testrun`)
return await aioAPIClient
.put(`/project/${aioConfig.jiraProjectId}/testcycle/${aioConfig.cycleDetails.cycleKeyToReportTo}/bulk/testrun`, data)
.then(function (response) {
aioLogger.debug(`Successfully updated run fields.`);
})
.catch(async err => {
debugLogError(err)
if(err.response) {
aioLogger.error("Error reporting in updating run fields. " + "Status Code - " + err.response.status + " - " + err.response.data);
} else {
aioLogger.error("Error in updating run fields : " + err.code);
}
})
}
const reportSpecResults = function(config, results) {

@@ -75,2 +127,3 @@ if(!aioAPIClient) {

let caseKeys = [...testData.keys()];
allCaseKeys.push(...caseKeys);
let passedCaseKeys = [];

@@ -134,3 +187,2 @@ let failedCaseKeys = [];

aioLogger.debug("Posting results to " + `/project/${aioConfig.jiraProjectId}/testcycle/${aioConfig.cycleDetails.cycleKeyToReportTo}/testcase/${caseKey}/testrun?createNewRun=${createNewRun}`)
aioLogger.debug(data)
return aioAPIClient

@@ -148,3 +200,3 @@ .post(`/project/${aioConfig.jiraProjectId}/testcycle/${aioConfig.cycleDetails.cycleKeyToReportTo}/testcase/${caseKey}/testrun?createNewRun=${createNewRun}`, data)

if(err.response) {
if (err.response.status == 429 && trialCounter < 3) {
if (err.response.status === 429 && trialCounter < 3) {
aioLogger.log("Reached AIO rate limits. Pausing..")

@@ -278,9 +330,9 @@ await sleep(rateLimitWaitTime);

const getOrCreateCycle = (aioConfig) => {
const getOrCreateCycle = async (aioConfig) => {
aioLogger.logStartEnd("Determining cycle to update");
initAPIClient(aioConfig);
if(!aioAPIClient) {
if (!aioAPIClient) {
return Promise.resolve("Please specify valid credentials to connect with AIO Tests.");
}
if(!aioConfig.cycleDetails) {
if (!aioConfig.cycleDetails) {
aioLogger.error("Please specify cycleDetails in config. eg. \"cycleDetails\": {\"cycleKey\":\"AT-CY-11\"}", true);

@@ -290,57 +342,76 @@ return Promise.resolve();

let aioCycleConfig = aioConfig.cycleDetails;
if(aioCycleConfig.createNewCycle) {
if(!(createNewCycleOptions.includes(aioCycleConfig.createNewCycle))){
return Promise.resolve(
`Invalid value for createNewCycle "${aioCycleConfig.createNewCycle}". Valid values include ${createNewCycleOptions}.`
);
}
if((!aioCycleConfig.createNewCycle || "false" === aioCycleConfig.createNewCycle) && aioCycleConfig.cycleKey){
aioCycleConfig["cycleKeyToReportTo"] = aioCycleConfig.cycleKey;
return Promise.resolve();
}
if(aioCycleConfig.createNewCycle === true || "true" === aioCycleConfig.createNewCycle || aioCycleConfig.createNewCycle === CREATE_IF_ABSENT) {
let cycleTitle = aioCycleConfig.cycleName;
if(!!!cycleTitle){
return Promise.resolve("createNewCycle is true in config. New cycle name is mandatory.", true)
} else {
aioLogger.log("Creating cycle : " + cycleTitle);
let folderCreationPromise = getOrCreateFolder(aioConfig.jiraProjectId, aioCycleConfig);
return folderCreationPromise.then((folderCreationResponse) => {
aioLogger.debug("Folder task resolved. Creating cycle.")
let createCycleBody = {
title: cycleTitle
let customFields = aioCycleConfig.customFields;
if (!!!cycleTitle) {
return Promise.resolve("createNewCycle is set to " + aioCycleConfig.createNewCycle +" in config. Please set cycleName.")
}
if(aioCycleConfig.createNewCycle === CREATE_IF_ABSENT) {
let results = await findExistingCycleThroughName(aioConfig);
if (results === true) {
aioLogger.debug("Existing cycle found")
//Cycle found and set.
return;
}
if (results !== false) {
//Error while finding cycle.
aioLogger.log(results)
return;
}
}
aioLogger.log("Creating cycle : " + cycleTitle);
let folderCreationPromise = getOrCreateFolder(aioConfig.jiraProjectId, aioCycleConfig);
return folderCreationPromise.then((folderCreationResponse) => {
aioLogger.debug("Folder task resolved. Creating cycle.")
let createCycleBody = {
title: cycleTitle,
customFields: customFields || null
}
if (folderCreationResponse) {
createCycleBody.folder = folderCreationResponse.data;
}
if (aioCycleConfig.tasks && aioCycleConfig.tasks.length > 0 && Array.isArray(aioCycleConfig.tasks)) {
let jiraTasks = aioCycleConfig.tasks.filter(f => f && !!f.trim());
if (jiraTasks.length > 0) {
createCycleBody.jiraTaskIDs = jiraTasks;
}
if(folderCreationResponse) {
createCycleBody.folder = folderCreationResponse.data;
}
if(aioCycleConfig.tasks && aioCycleConfig.tasks.length > 0 && Array.isArray(aioCycleConfig.tasks)) {
let jiraTasks = aioCycleConfig.tasks.filter(f => f && !!f.trim());
if(jiraTasks.length > 0) {
createCycleBody.jiraTaskIDs = jiraTasks;
}
aioLogger.debug("Cycle endpoint " + "/project/" + aioConfig.jiraProjectId + "/testcycle/detail");
return aioAPIClient.post("/project/" + aioConfig.jiraProjectId + "/testcycle/detail", createCycleBody)
.then(function (response) {
aioCycleConfig["cycleKeyToReportTo"] = response.data.key;
aioLogger.log("Cycle created successfully : " + aioCycleConfig.cycleKeyToReportTo)
})
.catch(function (error) {
debugLogError(error);
if (error.response) {
if (error.response.status === 401 || error.response.status === 403) {
return Promise.resolve("Authorization error. Please check credentials.")
} else {
return Promise.resolve(error.response.status + " : " + error.response.data);
}
}
}
aioLogger.debug("Cycle endpoint " + "/project/"+ aioConfig.jiraProjectId+"/testcycle/detail");
aioLogger.debug(createCycleBody)
return aioAPIClient.post("/project/"+ aioConfig.jiraProjectId+"/testcycle/detail", createCycleBody)
.then(function (response) {
aioCycleConfig["cycleKeyToReportTo"] = response.data.key;
aioLogger.log("Cycle created successfully : " + aioCycleConfig.cycleKeyToReportTo )
})
.catch(function (error) {
debugLogError(error);
if(error.response) {
if (error.response.status === 401 || error.response.status === 403) {
return Promise.resolve("Authorization error. Please check credentials.")
} else {
return Promise.resolve(error.response.status + " : " + error.response.data);
}
}
});
}).catch((error) => {
debugLogError(error);
if(error.response) {
aioLogger.error(error.response.status + " : " + error.response.data)
}
return Promise.resolve("Error in fetching or creating cycle folder. " +
"Please check format of folder, for eg. [\"Cloud\",\"Release1\"]");
})
}
} else {
if(!!!aioCycleConfig.cycleKey) {
return Promise.resolve("createNewCycle is false in config. Please specify a cycle key (eg. AT-CY-11) as \"cycleKey\":\"AT-CY=11\"", true);
} else {
aioCycleConfig["cycleKeyToReportTo"] = aioCycleConfig.cycleKey;
}
return Promise.resolve();
});
}).catch((error) => {
debugLogError(error);
if (error.response) {
aioLogger.error(error.response.status + " : " + error.response.data)
}
return Promise.resolve("Error in fetching or creating cycle folder. " +
"Please check format of folder, for eg. [\"Cloud\",\"Release1\"]");
})
}
return Promise.resolve("createNewCycle is false in config. Please specify a cycle key (eg. AT-CY-11) as \"cycleKey\":\"AT-CY=11\" or cycle name (eg. NVTES) as \"cycleName\":\"NVTES\" ", true);
}

@@ -350,2 +421,37 @@

async function findExistingCycleThroughName(aioConfig) {
if (aioConfig.parallelBuild && aioConfig.parallelBuild.masterBuild === false) {
let to = aioConfig.parallelBuild.waitForSeconds? aioConfig.parallelBuild.waitForSeconds: 2;
aioLogger.log(`Waiting for ${to} seconds for master build to finish`)
await new Promise(resolve => setTimeout(resolve, to*1000));
}
let body = {
"title": {
"comparisonType": "EXACT_MATCH",
"value": aioConfig.cycleDetails.cycleName.trim()
}
}
aioLogger.log("Finding cycle with name : " + aioConfig.cycleDetails.cycleName.trim())
return aioAPIClient.post(`/project/${aioConfig.jiraProjectId}/testcycle/search`, body)
.then(function (response) {
const items = response?.data?.items;
if (items && items.length > 0) {
aioConfig.cycleDetails["cycleKeyToReportTo"] = items[0]?.key;
return true;
} else {
return false;
}
})
.catch(function (error) {
debugLogError(error);
if (error.response) {
if (error.response.status === 401 || error.response.status === 403) {
return Promise.resolve("Authorization error. Please check credentials.")
} else {
return Promise.resolve(error.response.status + " : " + error.response.data);
}
}
});
}
function getAIORunStatus(cypressStatusString) {

@@ -372,2 +478,2 @@ switch(cypressStatusString) {

module.exports = { reportSpecResults, getOrCreateCycle }
module.exports = { reportSpecResults, getOrCreateCycle, updateRunFields }

@@ -18,8 +18,9 @@

const registerAIOTestsPlugin = (on, config) => {
on('before:run', () => {
const registerAIOTestsPlugin = async (on, config) => {
on('before:run', async () => {
let aioConfig = getAIOConfig(config, true);
if(aioConfig) {
return reporter.getOrCreateCycle(aioConfig).then((data) => {
if(aioConfig.cycleDetails.cycleKeyToReportTo) {
if (aioConfig) {
try {
const data = await reporter.getOrCreateCycle(aioConfig);
if (aioConfig.cycleDetails.cycleKeyToReportTo) {
aioLogger.log("Reporting results to cycle : " + aioConfig.cycleDetails.cycleKeyToReportTo);

@@ -29,3 +30,5 @@ } else {

}
})
} catch (err) {
aioLogger.error("An error occurred: " + err.message);
}
}

@@ -42,4 +45,14 @@ });

})
on('after:run', async () => {
let aioConfig = getAIOConfig(config);
if(aioConfig && aioConfig.runDetails) {
return reporter.updateRunFields( aioConfig ).then(() => {
aioLogger.logStartEnd("Updating run fields completed.");
})
}
});
};
module.exports = { registerAIOTestsPlugin }

Sorry, the diff of this file is not supported yet

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