lambdatest-cypress-cli
Version:
The lambdatest-cypress-cli is LambdaTest's command-line interface (CLI) aimed to help you run your Cypress tests on LambdaTest platform.
386 lines (333 loc) • 16.4 kB
JavaScript
const LambdatestLog = (message) => {
if (!Cypress.env('LAMBDATEST_LOGS')) return;
cy.task('lambdatest_log', message);
}
let globalScreenshots = null;
const captureScreenshot = Cypress.env("CAPTURE_SCREENSHOT") === "true";
const commandsToOverride = [
'visit', 'click', 'type', 'request', 'dblclick', 'rightclick', 'clear', 'check',
'uncheck', 'select', 'trigger', 'selectFile', 'scrollIntoView', 'scrollTo',
'blur', 'focus', 'go', 'reload', 'submit', 'viewport', 'origin'
];
const commandsToWrap = ['visit', 'click', 'type', 'request', 'dblclick', 'rightclick', 'clear', 'check', 'uncheck', 'select', 'trigger', 'selectFile', 'scrollIntoView', 'scroll', 'scrollTo', 'blur', 'focus', 'go', 'reload', 'submit', 'viewport', 'origin'];
const performNewLambdaScan = (originalFn, Subject, stateType, ...args) => {
let cycustomChaining = cy.wrap(null).processAccessibilityReport();
const updateSubj = (args, stateType, newSubject) =>
stateType === 'parent' ? args : [newSubject, ...args.slice(1)];
const runCustomizedChainingCommand = () => {
if (!Subject) {
let cypressCommandSubject = null;
const subjectFn = cy && cy.subject;
if (subjectFn !== null && subjectFn !== void 0) {
cypressCommandSubject = subjectFn.call(cy);
}
cycustomChaining
.then(() => cypressCommandSubject)
.then(() => {
originalFn(...args);
});
} else {
let cypressCommandChain = null, setTimeout = null;
// Extract timeout value if present
const timeoutArg = args.find(arg => arg !== null && arg !== void 0 ? arg.timeout : null);
if (timeoutArg !== null && timeoutArg !== void 0) {
setTimeout = timeoutArg.timeout;
}
const subjectChainFn = cy && cy.subjectChain;
if (subjectChainFn !== null && subjectChainFn !== void 0) {
cypressCommandChain = subjectChainFn.call(cy);
}
if (captureScreenshot) {
cy.log('Starting performScanSubjectQuery');
cycustomChaining
.performScanSubjectQuery(cypressCommandChain, setTimeout)
.then({ timeout: 30000 }, (newSubject) => {
const updatedArgs = updateSubj(args, stateType, newSubject);
const screenshotId= crypto.randomUUID();
const screenshotName = 'accessibility-screenshot-'+ screenshotId;
cy.screenshot(screenshotName, { capture: 'fullPage' });
cy.task('convertScreenshotToBase64', `cypress/screenshots/${Cypress.spec.name}/${screenshotName}.png`).then((result) => {
if (result && result.base64) {
const imageUrl = `data:image/png;base64,${result.base64}`;
const imageResolution = result.resolution;
// Create screenshots array
const screenshots = [
{
image_url: imageUrl,
image_resolution: `${imageResolution.width}x${imageResolution.height}`,
screenshotId: screenshotId
}
];
// Store globally for use in processAccessibilityReport
globalScreenshots = screenshots;
cy.task('deleteFile', `cypress/screenshots/${Cypress.spec.name}/${screenshotName}.png`).then((_) => {
});
} else {
cy.log('Failed to process screenshot');
}
});
const result = originalFn(...updatedArgs);
return result;
});
} else {
cycustomChaining.performScanSubjectQuery(cypressCommandChain, setTimeout).then({timeout: 30000}, (newSubject) => originalFn(...updateSubj(args, stateType, newSubject)));
}
}
}
runCustomizedChainingCommand();
}
Cypress.Commands.add('processAccessibilityReport', () => {
try {
cy.window().then((win) => {
return cy.wrap(processAccessibilityReport(win), { timeout: 45000 });
});
} catch(error) {
console.log(`Error in performing scan with error: ${error.message}`);
}
})
const setScanConfig = (win, payload) => {
return new Promise((resolve, reject) => {
const isHttpOrHttps = /^(http|https):$/.test(win.location.protocol);
if (!isHttpOrHttps) return resolve();
console.log('log', "Accessibility setting scan config");
function onScanComplete(event) {
win.document.removeEventListener("automation-custom-event", onScanComplete);
console.log('log', "Received scan config data: ", event.detail);
resolve(event.detail);
}
console.log('log', "Dispactched event");
win.document.addEventListener("automation-custom-event", onScanComplete);
const e = new CustomEvent("accessibility-extension-custom-event", { detail: payload });
win.document.dispatchEvent(e);
setTimeout(() => {
resolve(new Error('automation-custom-event not received within timeout'));
}, 45000);
});
};
const getScanData = (win, payload) => {
return new Promise((resolve, reject) => {
const isHttpOrHttps = /^(http|https):$/.test(win.location.protocol);
if (!isHttpOrHttps) return resolve();
function onReceiveSummary(event) {
win.document.removeEventListener("automation-custom-event", onReceiveSummary);
resolve(event.detail);
}
win.document.addEventListener("automation-custom-event", onReceiveSummary);
const e = new CustomEvent("accessibility-extension-custom-event", { detail: payload });
win.document.dispatchEvent(e);
setTimeout(() => {
resolve(new Error('automation-custom-event not received within timeout'));
}, 45000);
});
};
const sendScanData = (win, payload) => {
return new Promise((resolve, reject) => {
const isHttpOrHttps = /^(http|https):$/.test(win.location.protocol);
if (!isHttpOrHttps) return resolve();
function onReceiveSummary(event) {
win.document.removeEventListener("automation-custom-event", onReceiveSummary);
resolve(event.detail);
}
win.document.addEventListener("automation-custom-event", onReceiveSummary);
const e = new CustomEvent("accessibility-extension-custom-event", { detail: payload });
win.document.dispatchEvent(e);
setTimeout(() => {
resolve(new Error('automation-custom-event not received within timeout'));
}, 45000);
});
};
const processAccessibilityReport = async (windowNew) => {
try {
let wcagCriteriaValue = Cypress.env("WCAG_CRITERIA") || "wcag21a";
let bestPracticeValue = Cypress.env("BEST_PRACTICE") === "true";
let needsReviewValue = Cypress.env("NEEDS_REVIEW") !== "false"; // Default to true
let captureScreenshot = Cypress.env("CAPTURE_SCREENSHOT") === "true";
let passedTestCases = Cypress.env("PASSED_TEST_CASES") === "true";
const payloadToSend = {
message: 'SET_CONFIG',
wcagCriteria: wcagCriteriaValue,
bestPractice: bestPracticeValue,
needsReview: needsReviewValue,
captureScreenshot: captureScreenshot,
passedTestCases: passedTestCases
};
console.log('log', "SET SCAN: Payload to send: ", payloadToSend);
try {
let setResult = await setScanConfig(windowNew, payloadToSend);
console.log('SET SCAN: response:', setResult);
} catch (err) {
console.error("SET SCAN: Error while setting scan", err);
return ;
}
let scanData;
try {
const payload = {message: 'GET_LATEST_SCAN_DATA'};
scanData = await getScanData(windowNew, payload);
LambdatestLog("GET SCAN:LambdaTest Accessibility: Scanning URL");
if (captureScreenshot) {
if (scanData && scanData.data && scanData.data.length > 0 && globalScreenshots) {
const firstDataItem = scanData.data[0];
if (firstDataItem.events && firstDataItem.events.length > 0) {
const firstEvent = firstDataItem.events[0];
if (firstEvent.issues && firstEvent.issues.length > 0) {
// Update screenshotId with the actual screenshotId
globalScreenshots[0].screenshotId=firstEvent.issues[0].screenshotId;
}
}
for (let i = 0; i < scanData.data.length; i++) {
if (scanData.data[i].screenshots && Array.isArray(scanData.data[i].screenshots)) {
scanData.data[i].screenshots = globalScreenshots;
break;
}
}
}
globalScreenshots = null;
}
} catch (err) {
console.error("GET SCAN:Error while setting scan", err);
return ;
}
console.log("Logging response before sending to API:", scanData);
try {
const testId = Cypress.env("TEST_ID") || "dummy1234"
const reportAPI = Cypress.env("GENERATE_REPORT_API") || "http://localhost:43000/api/v1.0/cypress/generateAccessibilityReport"
const filePath = Cypress.env("ACCESSIBILITY_REPORT_PATH") || ('cypress/results/accessibilityReport_' + testId + '.json');
console.log("TestID is",testId);
const payloadToSend = {
message: 'SEND_ACCESSIBILITY_DATA',
testId : testId,
scanData: scanData,
accessibilityReportPath:filePath,
apiUrl: reportAPI
};
try{
let response = await sendScanData(windowNew,payloadToSend);
console.log("Accessibility Report Response:", response);
}catch(e){
console.error("Error in Accessibility Report Response:",e);
}
}catch(err) {
console.error("Error while making api", err);
}
} catch (error) {
LambdatestLog("ERROR", error);
}
}
function oldprocessAccessibilityReport(win){
let wcagCriteriaValue = Cypress.env("WCAG_CRITERIA") || "wcag21a";
let bestPracticeValue = Cypress.env("BEST_PRACTICE") || false;
let needsReviewValue = Cypress.env("NEEDS_REVIEW") || true;
bestPracticeValue = bestPracticeValue == "true" ? true : false;
needsReviewValue = needsReviewValue == "true" ? true : false;
const payloadToSend = {
message: 'SET_CONFIG',
wcagCriteria: wcagCriteriaValue,
bestPractice: bestPracticeValue,
needsReview: needsReviewValue
}
console.log('log', "payload to send " + payloadToSend);
let testId = Cypress.env("TEST_ID") || ""
const filePath = Cypress.env("ACCESSIBILITY_REPORT_PATH") || 'cypress/results/accessibilityReport_' + testId + '.json';
cy.wrap(setScanConfig(win, payloadToSend), {timeout: 30000}).then((res) => {
console.log('logging config reponse', res);
const payload = {
message: 'GET_LATEST_SCAN_DATA',
}
cy.wrap(getScanData(win, payload), {timeout: 45000}).then((res) => {
LambdatestLog('log', "scanning data ");
cy.task('initializeFile', filePath).then((filePath) => {
cy.task('readFileIfExists', filePath,{ log: true, timeout: 45000 }).then((result) => {
let resultsArray = [{}];
console.log('logging report', res);
// If the file is not empty, parse the existing content
if (result.exists && result.content) {
try {
resultsArray = JSON.parse(result.content);
} catch (e) {
console.log("parsing error for content " , result.content)
console.log('Error parsing JSON file:', e);
return;
}
} else if(!result.exists) {
console.log('accessibility file does not exist');
}
if (res) {
console.log('scanned data recieved is', res.message);
}
if (res && res.message == "GET_LATEST_SCAN_DATA") {
try {
// Append the new result
resultsArray.push(res);
console.log('resultsarray logging', resultsArray);
} catch (e) {
console.log('Error pushing issues to array:', e);
}
}
// Write the updated content back to the file
cy.writeFile(filePath, resultsArray, { log: true, timeout: 45000 });
});
});
});
});
}
const overRideCommands = JSON.parse(Cypress.env("ACCESSIBILITY_OVERIDE_COMMANDS") || "false");
if (overRideCommands) {
commandsToOverride.forEach((command) => {
Cypress.Commands.overwrite(command, (originalFn, ...args) => {
let isAccessibilityLoaded = Cypress.env("ACCESSIBILITY") || false;
const state = cy.state('current'), Subject = 'getSubjectFromChain' in cy;
const stateName = state === null || state === void 0 ? void 0 : state.get('name');
let stateType = null;
if (!isAccessibilityLoaded || (stateName && stateName !== command)) {
return originalFn(...args);
}
if(state !== null && state !== void 0){
stateType = state.get('type');
}
performNewLambdaScan(originalFn, Subject, stateType, ...args);
});
});
}else{
Cypress.on('command:start', async (command) => {
if(!command || !command.attributes) return;
if(command.attributes.name == 'window' || command.attributes.name == 'then' || command.attributes.name == 'wrap' || command.attributes.name == 'wait') {
return;
}
if (!commandsToWrap.includes(command.attributes.name)) return;
let isAccessibilityLoaded = Cypress.env("ACCESSIBILITY") || false;
if (!isAccessibilityLoaded){
console.log('log', "accessibility not enabled " + isAccessibilityLoaded);
return;
}
console.log('log', "debugging scan form command " + command.attributes.name);
cy.window().then((win) => {
oldprocessAccessibilityReport(win);
})
})
}
afterEach(() => {
if(overRideCommands){
cy.window().then(async (win) => {
let isAccessibilityLoaded = Cypress.env("ACCESSIBILITY") || false;
if (!isAccessibilityLoaded) return cy.wrap({});
cy.wrap(processAccessibilityReport(win), {timeout: 45000})
});
}else{
console.log("after each hook")
let isAccessibilityLoaded = Cypress.env("ACCESSIBILITY") || false;
if (!isAccessibilityLoaded){
console.log('log', "accessibility not enabled " + isAccessibilityLoaded);
return;
}
cy.window().then((win) => {
oldprocessAccessibilityReport(win);
})
}
})
if (!Cypress.Commands.hasOwnProperty('_lambdaTestAcessibilityQueryAdded') && (overRideCommands)) {
Cypress.Commands.addQuery('performScanSubjectQuery', function (chaining, setTimeout) {
this.set('timeout', setTimeout);
return () => cy.getSubjectFromChain(chaining);
});
Cypress.Commands._lambdaTestAcessibilityQueryAdded = true;
}