Skip to content

Commit 358fa83

Browse files
committed
adding accessibility plugin
1 parent 4d61af0 commit 358fa83

File tree

5 files changed

+273
-1
lines changed

5 files changed

+273
-1
lines changed

accessibility/plugin/index.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
const path = require("node:path");
2+
const fs = require("fs");
3+
let counter =0;
4+
const Accessibility = (on, config) => {
5+
6+
on('task', {
7+
lambdatest_log(message) {
8+
console.log(message)
9+
return null
10+
},
11+
getCounterValue() {
12+
return counter;
13+
},
14+
incrementCounterValue() {
15+
counter += 1;
16+
return counter;
17+
},
18+
initializeFile(filePath) {
19+
if (!fs.existsSync(filePath)) {
20+
// counter = counter +1;
21+
// filePath = 'cypress/reports/accessibilityfinal-results' + counter + '.json';
22+
fs.writeFileSync(filePath, '[]');
23+
}
24+
return filePath;
25+
}
26+
})
27+
28+
let browser_validation = true;
29+
console.log(`debug point 1.`);
30+
31+
on('before:browser:launch', (browser = {}, launchOptions) => {
32+
try {
33+
console.log(`debug point 2. ext path` + process.env.ACCESSIBILITY_EXTENSION_PATH)
34+
if (process.env.ACCESSIBILITY_EXTENSION_PATH !== undefined) {
35+
// if (browser.name !== 'chrome') {
36+
// console.log(`Accessibility Automation will run only on Chrome browsers.`);
37+
// browser_validation = false;
38+
// }
39+
// if (browser.name === 'chrome' && browser.majorVersion <= 94) {
40+
// console.log(`Accessibility Automation will run only on Chrome browser version greater than 94.`);
41+
// browser_validation = false;
42+
// }
43+
// if (browser.isHeadless === true) {
44+
// console.log(`Accessibility Automation will not run on legacy headless mode. Switch to new headless mode or avoid using headless mode.`);
45+
// browser_validation = false;
46+
// }
47+
if (browser_validation) {
48+
49+
const accessibility_ext_path = process.env.ACCESSIBILITY_EXTENSION_PATH
50+
console.log(`debug point 3. ext path` + accessibility_ext_path)
51+
// launchOptions.extensions.push(accessibility_ext_path);
52+
//TODO: set dynamic path
53+
launchOptions.args.push(`--load-extension=` + accessibility_ext_path)
54+
return launchOptions
55+
}
56+
}
57+
} catch(err) {}
58+
59+
})
60+
console.log('log', "picking env from system " + process.env.TEST_VAR);
61+
config.env.TEST_VAR= process.env.TEST_VAR;
62+
config.env.WCAG_CRITERIA= process.env.WCAG_CRITERIA;
63+
config.env.BEST_PRACTICE= process.env.BEST_PRACTICE;
64+
config.env.NEEDS_REVIEW= process.env.NEEDS_REVIEW;
65+
66+
67+
return config;
68+
}
69+
70+
module.exports = Accessibility;

accessibility/scanner/index.js

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
const fs = require("fs")
2+
3+
const LambdatestLog = (message) => {
4+
if (!Cypress.env('LAMBDATEST_LOGS')) return;
5+
cy.task('lambdatest_log', message);
6+
}
7+
8+
const commandsToWrap = ['visit', 'click', 'type', 'request', 'dblclick', 'rightclick', 'clear', 'check', 'uncheck', 'select', 'trigger', 'selectFile', 'scrollIntoView', 'scroll', 'scrollTo', 'blur', 'focus', 'go', 'reload', 'submit', 'viewport', 'origin'];
9+
10+
const setScanConfig = (win, payload) =>
11+
new Promise(async (resolve, reject) => {
12+
const isHttpOrHttps = /^(http|https):$/.test(win.location.protocol);
13+
if (!isHttpOrHttps) {
14+
resolve();
15+
}
16+
17+
function startScan() {
18+
console.log('log', "Accessibility setting scan config")
19+
function onScanComplete(event) {
20+
win.document.removeEventListener("automation-custom-event", onScanComplete);
21+
console.log('log', "Recieved scan config data " + event.detail)
22+
resolve(event.detail);
23+
}
24+
25+
win.document.addEventListener("automation-custom-event", onScanComplete);
26+
const e = new CustomEvent("accessibility-extension-custom-event", { detail: payload });
27+
win.document.dispatchEvent(e);
28+
29+
// add timeout of 4 sec
30+
31+
setTimeout(() => {
32+
reject(new Error('automation-custom-event not received within timeout'));
33+
}, 9000); // Adding a custom timeout for the event
34+
}
35+
startScan();
36+
37+
})
38+
39+
const getScanData = (win, payload) =>
40+
new Promise( async (resolve,reject) => {
41+
const isHttpOrHttps = /^(http|https):$/.test(window.location.protocol);
42+
if (!isHttpOrHttps) {
43+
resolve();
44+
}
45+
46+
47+
function getSummary() {
48+
function onReceiveSummary(event) {
49+
50+
win.document.removeEventListener("automation-custom-event", onReceiveSummary);
51+
resolve(event.detail);
52+
}
53+
54+
55+
win.document.addEventListener("automation-custom-event", onReceiveSummary);
56+
const e = new CustomEvent("accessibility-extension-custom-event", { detail: payload });
57+
win.document.dispatchEvent(e);
58+
59+
setTimeout(() => {
60+
reject(new Error('automation-custom-event not received within timeout'));
61+
}, 9000); // Adding a custom timeout for the event
62+
63+
}
64+
65+
66+
getSummary();
67+
68+
})
69+
70+
const shouldScanForAccessibility = (attributes) => {
71+
if (Cypress.env("IS_ACCESSIBILITY_EXTENSION_LOADED") !== "true") return false;
72+
73+
const extensionPath = Cypress.env("ACCESSIBILITY_EXTENSION_PATH");
74+
const isHeaded = Cypress.browser.isHeaded;
75+
76+
if (!isHeaded || (extensionPath === undefined)) return false;
77+
78+
let shouldScanTestForAccessibility = true;
79+
80+
if (Cypress.env("INCLUDE_TAGS_FOR_ACCESSIBILITY") || Cypress.env("EXCLUDE_TAGS_FOR_ACCESSIBILITY")) {
81+
try {
82+
let includeTagArray = [];
83+
let excludeTagArray = [];
84+
if (Cypress.env("INCLUDE_TAGS_FOR_ACCESSIBILITY")) {
85+
includeTagArray = Cypress.env("INCLUDE_TAGS_FOR_ACCESSIBILITY").split(";")
86+
}
87+
if (Cypress.env("EXCLUDE_TAGS_FOR_ACCESSIBILITY")) {
88+
excludeTagArray = Cypress.env("EXCLUDE_TAGS_FOR_ACCESSIBILITY").split(";")
89+
}
90+
91+
const fullTestName = attributes.title;
92+
const excluded = excludeTagArray.some((exclude) => fullTestName.includes(exclude));
93+
const included = includeTagArray.length === 0 || includeTags.some((include) => fullTestName.includes(include));
94+
shouldScanTestForAccessibility = !excluded && included;
95+
} catch (error) {
96+
LambdatestLog("Error while validating test case for accessibility before scanning. Error : ", error);
97+
}
98+
}
99+
100+
return shouldScanTestForAccessibility;
101+
}
102+
103+
Cypress.on('command:start', async (command) => {
104+
if(!command || !command.attributes) return;
105+
if(command.attributes.name == 'window' || command.attributes.name == 'then' || command.attributes.name == 'wrap' || command.attributes.name == 'wait') {
106+
return;
107+
}
108+
109+
if (!commandsToWrap.includes(command.attributes.name)) return;
110+
111+
// const attributes = Cypress.mocha.getRunner().suite.ctx.currentTest || Cypress.mocha.getRunner().suite.ctx._runnable;
112+
113+
// let shouldScanTestForAccessibility = shouldScanForAccessibility(attributes);
114+
// if (!shouldScanTestForAccessibility) return;
115+
// console.log('log', "debugging scan form command " + command.attributes.name);
116+
console.log('log', "debugging scan form command " + command.attributes.name);
117+
cy.window().then((win) => {
118+
// LambdatestLog('Performing scan form command ' + command.attributes.name);
119+
let wcagCriteriaValue = Cypress.env("WCAG_CRITERIA") || "wcag21a";
120+
let bestPracticeValue = Cypress.env("BEST_PRACTICE") || false;
121+
let needsReviewValue = Cypress.env("NEEDS_REVIEW") || true;
122+
123+
const payloadToSend = {
124+
message: 'SET_CONFIG',
125+
wcagCriteria: wcagCriteriaValue,
126+
bestPractice: bestPracticeValue,
127+
needsReview: needsReviewValue
128+
}
129+
let testId = Cypress.env("TEST_ID") || ""
130+
const filePath = 'cypress/reports/accessibilityReport_' + testId + '.json';
131+
132+
cy.wrap(setScanConfig(win, payloadToSend), {timeout: 30000}).then((res) => {
133+
// LambdatestLog('log', "logging report **************")
134+
console.log('logging config reponse', res);
135+
136+
const payload = {
137+
message: 'GET_LATEST_SCAN_DATA',
138+
}
139+
// cy.wait(5000);
140+
cy.wrap(getScanData(win, payload), {timeout: 30000}).then((res) => {
141+
LambdatestLog('log', "logging report **************")
142+
143+
144+
cy.task('initializeFile', filePath).then((filePath) => {
145+
cy.readFile(filePath, { log: true, timeout: 30000 }).then((fileContent) => {
146+
let resultsArray = [{}];
147+
console.log('logging report', res);
148+
// If the file is not empty, parse the existing content
149+
if (fileContent) {
150+
try {
151+
resultsArray = JSON.parse(JSON.stringify(fileContent));
152+
} catch (e) {
153+
console.log("parsing error for content " , fileContent)
154+
console.log('Error parsing JSON file:', e);
155+
return;
156+
}
157+
}
158+
console.log('debugging res', res.message);
159+
if (res.message == "GET_LATEST_SCAN_DATA") {
160+
// Append the new result
161+
resultsArray.push(res);
162+
console.log('resultsarray logging', resultsArray);
163+
}
164+
165+
// Write the updated content back to the file
166+
cy.writeFile(filePath, resultsArray, { log: true, timeout: 30000 });
167+
});
168+
});
169+
});
170+
171+
});
172+
})
173+
})
174+
175+
176+
Cypress.on('command:end', (command) => {
177+
178+
// console.log('log', "debugging scan form command end " + command.attributes.name);
179+
return;
180+
})

commands/utils/set_args.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,16 @@ function sync_args_from_cmd(args) {
383383
lt_config["run_settings"]["useNode18"] = false;
384384
}
385385

386+
if ("accessibility" in args) {
387+
if (args["accessibility"] == "true") {
388+
lt_config.run_settings.accessibility = true;
389+
} else {
390+
lt_config.run_settings.accessibility = false;
391+
}
392+
} else if (lt_config["run_settings"]["accessibility"] && !lt_config["run_settings"]["accessibility"]) {
393+
lt_config["run_settings"]["accessibility"] = false;
394+
}
395+
386396
if ("network_ws" in args) {
387397
if (args["network_ws"] == "true") {
388398
lt_config.run_settings.network_ws = true;

commands/utils/validate.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,14 @@ module.exports = validate_config = function (lt_config, validation_configs) {
198198
}
199199
}
200200

201-
//validate if network_http2 field contains expected value
201+
//validate if accessibility field contains expected value
202+
if ("accessibility" in lt_config["run_settings"]) {
203+
if (![true, false].includes(lt_config["run_settings"]["accessibility"])) {
204+
reject("Error!! boolean value is expected in accessibility key");
205+
}
206+
}
207+
208+
//validate if useNode18 field contains expected value
202209
if ("useNode18" in lt_config["run_settings"]) {
203210
if (![true, false].includes(lt_config["run_settings"]["useNode18"])) {
204211
reject("Error!! boolean value is expected in useNode18 key");

index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,11 @@ const argv = require("yargs")
245245
alias: "network_sse",
246246
describe: "Bypass sse events calls for Network logs",
247247
type: "bool",
248+
})
249+
.option("cypress_accessibility", {
250+
alias: "accessibility",
251+
describe: "enable accessibility testing for cypress.",
252+
type: "bool",
248253
});
249254
},
250255
function (argv) {

0 commit comments

Comments
 (0)