-
Notifications
You must be signed in to change notification settings - Fork 39
initial changes #707
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
agrawalsaurabhs
merged 21 commits into
browserstack:master
from
rev-doshi:cypress-accessibility
Oct 17, 2023
Merged
initial changes #707
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
7d9e7fb
initial changes
rev-doshi a88f32a
changes
rev-doshi ac5ccdf
chore: Support platform env params
sauravdas1997 3542abe
chore: Add accessibilityOptions to env vars
sauravdas1997 e46240b
refactor: Change log type
sauravdas1997 84ec374
Include exclude tags for accessibility
rev-doshi 14407d2
Merge branch 'cypress-accessibility' of github.com:rev-doshi/browsers…
rev-doshi e35c4c1
minor fixes
rev-doshi cab99db
refactor
rev-doshi 6cb2616
review changes
rev-doshi bea2579
os platform fix
rev-doshi 58aa803
review changes - try catch null handling, minor refactor
rev-doshi 3a0a1b9
minor fix
rev-doshi 7da618d
minor fix
rev-doshi 8315ed6
review changes
rev-doshi fc46a90
minor refactor
rev-doshi 20036d0
review changes
rev-doshi e3e89aa
added setBrowserstackCypressCliDependency for accessibility
rev-doshi 9eb7dde
minor fix
rev-doshi 309fefb
o11y refactor
rev-doshi 3441bb6
review changes
rev-doshi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
exports.API_URL = 'https://accessibility.browserstack.com/api'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
/* Event listeners + custom commands for Cypress */ | ||
|
||
Cypress.on('test:before:run', () => { | ||
try { | ||
if (Cypress.env("IS_ACCESSIBILITY_EXTENSION_LOADED") !== "true") return | ||
const extensionPath = Cypress.env("ACCESSIBILITY_EXTENSION_PATH") | ||
|
||
if (extensionPath !== undefined) { | ||
new Promise((resolve, reject) => { | ||
window.parent.addEventListener('A11Y_TAP_STARTED', () => { | ||
resolve("A11Y_TAP_STARTED"); | ||
}); | ||
const e = new CustomEvent('A11Y_FORCE_START'); | ||
window.parent.dispatchEvent(e); | ||
}) | ||
} | ||
} catch {} | ||
|
||
}); | ||
|
||
Cypress.on('test:after:run', (attributes, runnable) => { | ||
try { | ||
if (Cypress.env("IS_ACCESSIBILITY_EXTENSION_LOADED") !== "true") return | ||
const extensionPath = Cypress.env("ACCESSIBILITY_EXTENSION_PATH") | ||
const isHeaded = Cypress.browser.isHeaded; | ||
if (isHeaded && extensionPath !== undefined) { | ||
|
||
let shouldScanTestForAccessibility = true; | ||
if (Cypress.env("INCLUDE_TAGS_FOR_ACCESSIBILITY") || Cypress.env("EXCLUDE_TAGS_FOR_ACCESSIBILITY")) { | ||
|
||
try { | ||
let includeTagArray = []; | ||
let excludeTagArray = []; | ||
if (Cypress.env("INCLUDE_TAGS_FOR_ACCESSIBILITY")) { | ||
includeTagArray = Cypress.env("INCLUDE_TAGS_FOR_ACCESSIBILITY").split(";") | ||
} | ||
if (Cypress.env("EXCLUDE_TAGS_FOR_ACCESSIBILITY")) { | ||
excludeTagArray = Cypress.env("EXCLUDE_TAGS_FOR_ACCESSIBILITY").split(";") | ||
} | ||
|
||
const fullTestName = attributes.title; | ||
const excluded = excludeTagArray.some((exclude) => fullTestName.includes(exclude)); | ||
const included = includeTagArray.length === 0 || includeTags.some((include) => fullTestName.includes(include)); | ||
shouldScanTestForAccessibility = !excluded && included; | ||
} catch (error) { | ||
console.log("Error while validating test case for accessibility before scanning. Error : ", error); | ||
} | ||
} | ||
asambstack marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let os_data; | ||
if (Cypress.env("OS")) { | ||
os_data = Cypress.env("OS"); | ||
} else { | ||
os_data = Cypress.platform === 'linux' ? 'mac' : "win" | ||
asambstack marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
let filePath = ''; | ||
if (attributes.invocationDetails !== undefined && attributes.invocationDetails.relativeFile !== undefined) { | ||
filePath = attributes.invocationDetails.relativeFile; | ||
} | ||
const dataForExtension = { | ||
"saveResults": shouldScanTestForAccessibility, | ||
"testDetails": { | ||
"name": attributes.title, | ||
"testRunId": '5058', // variable not consumed, shouldn't matter what we send | ||
"filePath": filePath, | ||
"scopeList": [ | ||
filePath, | ||
attributes.title | ||
] | ||
}, | ||
"platform": { | ||
"os_name": os_data, | ||
"os_version": Cypress.env("OS_VERSION"), | ||
"browser_name": Cypress.browser.name, | ||
"browser_version": Cypress.browser.version | ||
} | ||
}; | ||
return new Promise((resolve, reject) => { | ||
if (dataForExtension.saveResults) { | ||
window.parent.addEventListener('A11Y_TAP_TRANSPORTER', (event) => { | ||
resolve(event.detail); | ||
}); | ||
} | ||
const e = new CustomEvent('A11Y_TEST_END', {detail: dataForExtension}); | ||
window.parent.dispatchEvent(e); | ||
if (dataForExtension.saveResults !== true ) | ||
resolve(); | ||
}); | ||
} | ||
|
||
} catch {} | ||
}); | ||
|
||
Cypress.Commands.add('getAccessibilityResultsSummary', () => { | ||
rev-doshi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
try { | ||
if (Cypress.env("IS_ACCESSIBILITY_EXTENSION_LOADED") !== "true") { | ||
console.log(`Not a Accessibility Automation session, cannot retrieve Accessibility results.`); | ||
return | ||
} | ||
return new Promise(function (resolve, reject) { | ||
try{ | ||
const e = new CustomEvent('A11Y_TAP_GET_RESULTS_SUMMARY'); | ||
const fn = function (event) { | ||
window.parent.removeEventListener('A11Y_RESULTS_SUMMARY_RESPONSE', fn); | ||
resolve(event.detail.summary); | ||
}; | ||
window.parent.addEventListener('A11Y_RESULTS_SUMMARY_RESPONSE', fn); | ||
window.parent.dispatchEvent(e); | ||
} catch (err) { | ||
console.log("No accessibility results summary was found."); | ||
reject(err); | ||
} | ||
}); | ||
} catch {} | ||
|
||
}); | ||
|
||
Cypress.Commands.add('getAccessibilityResults', () => { | ||
rev-doshi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
try { | ||
if (Cypress.env("IS_ACCESSIBILITY_EXTENSION_LOADED") !== "true") { | ||
console.log(`Not a Accessibility Automation session, cannot retrieve Accessibility results.`); | ||
return | ||
} | ||
return new Promise(function (resolve, reject) { | ||
try{ | ||
const e = new CustomEvent('A11Y_TAP_GET_RESULTS'); | ||
const fn = function (event) { | ||
window.parent.removeEventListener('A11Y_RESULTS_RESPONSE', fn); | ||
resolve(event.detail.summary); | ||
}; | ||
window.parent.addEventListener('A11Y_RESULTS_RESPONSE', fn); | ||
window.parent.dispatchEvent(e); | ||
} catch (err) { | ||
console.log("No accessibility results were found."); | ||
reject(err); | ||
} | ||
}); | ||
} catch {} | ||
|
||
}); | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
const logger = require("../helpers/logger").winstonLogger; | ||
const { API_URL } = require('./constants'); | ||
const utils = require('../helpers/utils'); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const request = require('request'); | ||
const os = require('os'); | ||
const glob = require('glob'); | ||
const helper = require('../helpers/helper'); | ||
const { CYPRESS_V10_AND_ABOVE_CONFIG_FILE_EXTENSIONS } = require('../helpers/constants'); | ||
const supportFileContentMap = {} | ||
|
||
exports.checkAccessibilityPlatform = (user_config) => { | ||
rev-doshi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let accessibility = false; | ||
try { | ||
user_config.browsers.forEach(browser => { | ||
if (browser.accessibility) { | ||
accessibility = true; | ||
} | ||
}) | ||
} catch {} | ||
|
||
return accessibility; | ||
} | ||
|
||
exports.setAccessibilityCypressCapabilities = async (user_config, accessibilityResponse) => { | ||
if (utils.isUndefined(user_config.run_settings.accessibilityOptions)) { | ||
user_config.run_settings.accessibilityOptions = {} | ||
} | ||
user_config.run_settings.accessibilityOptions["authToken"] = accessibilityResponse.data.accessibilityToken; | ||
user_config.run_settings.accessibilityOptions["auth"] = accessibilityResponse.data.accessibilityToken; | ||
user_config.run_settings.accessibilityOptions["scannerVersion"] = accessibilityResponse.data.scannerVersion; | ||
user_config.run_settings.system_env_vars.push(`ACCESSIBILITY_AUTH=${accessibilityResponse.data.accessibilityToken}`) | ||
user_config.run_settings.system_env_vars.push(`ACCESSIBILITY_SCANNERVERSION=${accessibilityResponse.data.scannerVersion}`) | ||
} | ||
|
||
exports.isAccessibilitySupportedCypressVersion = (cypress_config_filename) => { | ||
const extension = cypress_config_filename.split('.').pop(); | ||
return CYPRESS_V10_AND_ABOVE_CONFIG_FILE_EXTENSIONS.includes(extension); | ||
} | ||
|
||
exports.createAccessibilityTestRun = async (user_config, framework) => { | ||
|
||
try { | ||
if (!this.isAccessibilitySupportedCypressVersion(user_config.run_settings.cypress_config_file) ){ | ||
logger.warn(`Accessibility Testing is not supported on Cypress version 9 and below.`) | ||
process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'false'; | ||
user_config.run_settings.accessibility = false; | ||
return; | ||
} | ||
const userName = user_config["auth"]["username"]; | ||
const accessKey = user_config["auth"]["access_key"]; | ||
let settings = utils.isUndefined(user_config.run_settings.accessibilityOptions) ? {} : user_config.run_settings.accessibilityOptions | ||
|
||
const { | ||
buildName, | ||
projectName, | ||
buildDescription | ||
} = helper.getBuildDetails(user_config); | ||
|
||
const data = { | ||
'projectName': projectName, | ||
'buildName': buildName, | ||
'startTime': (new Date()).toISOString(), | ||
'description': buildDescription, | ||
'source': { | ||
frameworkName: "Cypress", | ||
frameworkVersion: helper.getPackageVersion('cypress', user_config), | ||
sdkVersion: helper.getAgentVersion() | ||
}, | ||
'settings': settings, | ||
'versionControl': await helper.getGitMetaData(), | ||
'ciInfo': helper.getCiInfo(), | ||
'hostInfo': { | ||
hostname: os.hostname(), | ||
platform: os.platform(), | ||
type: os.type(), | ||
version: os.version(), | ||
arch: os.arch() | ||
}, | ||
'browserstackAutomation': process.env.BROWSERSTACK_AUTOMATION === 'true' | ||
}; | ||
|
||
const config = { | ||
auth: { | ||
user: userName, | ||
pass: accessKey | ||
}, | ||
headers: { | ||
'Content-Type': 'application/json' | ||
} | ||
}; | ||
|
||
const response = await nodeRequest( | ||
'POST', 'test_runs', data, config, API_URL | ||
); | ||
if(!utils.isUndefined(response.data)) { | ||
process.env.BS_A11Y_JWT = response.data.data.accessibilityToken; | ||
process.env.BS_A11Y_TEST_RUN_ID = response.data.data.id; | ||
} | ||
if (process.env.BS_A11Y_JWT) { | ||
process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'true'; | ||
} | ||
logger.debug(`BrowserStack Accessibility Automation Test Run ID: ${response.data.data.id}`); | ||
|
||
this.setAccessibilityCypressCapabilities(user_config, response.data); | ||
setAccessibilityEventListeners(); | ||
helper.setBrowserstackCypressCliDependency(user_config); | ||
|
||
} catch (error) { | ||
if (error.response) { | ||
logger.error( | ||
`Exception while creating test run for BrowserStack Accessibility Automation: ${ | ||
error.response.status | ||
} ${error.response.statusText} ${JSON.stringify(error.response.data)}` | ||
); | ||
} else { | ||
if(error.message === 'Invalid configuration passed.') { | ||
logger.error( | ||
`Exception while creating test run for BrowserStack Accessibility Automation: ${ | ||
error.message || error.stack | ||
}` | ||
); | ||
for(const errorkey of error.errors){ | ||
logger.error(errorkey.message); | ||
} | ||
|
||
} else { | ||
logger.error( | ||
`Exception while creating test run for BrowserStack Accessibility Automation: ${ | ||
error.message || error.stack | ||
}` | ||
); | ||
} | ||
// since create accessibility session failed | ||
process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'false'; | ||
user_config.run_settings.accessibility = false; | ||
} | ||
} | ||
} | ||
|
||
const nodeRequest = (type, url, data, config) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use common nodeRequest method + remove debugging logs |
||
return new Promise(async (resolve, reject) => { | ||
const options = {...config,...{ | ||
method: type, | ||
url: `${API_URL}/${url}`, | ||
body: data, | ||
json: config.headers['Content-Type'] === 'application/json', | ||
}}; | ||
|
||
request(options, function callback(error, response, body) { | ||
if(error) { | ||
logger.info("error in nodeRequest", error); | ||
reject(error); | ||
} else if(!(response.statusCode == 201 || response.statusCode == 200)) { | ||
logger.info("response.statusCode in nodeRequest", response.statusCode); | ||
reject(response && response.body ? response.body : `Received response from BrowserStack Server with status : ${response.statusCode}`); | ||
} else { | ||
try { | ||
if(typeof(body) !== 'object') body = JSON.parse(body); | ||
} catch(e) { | ||
if(!url.includes('/stop')) { | ||
reject('Not a JSON response from BrowserStack Server'); | ||
} | ||
} | ||
resolve({ | ||
data: body | ||
}); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
exports.supportFileCleanup = () => { | ||
logger.debug("Cleaning up support file changes added for accessibility. ") | ||
Object.keys(supportFileContentMap).forEach(file => { | ||
try { | ||
fs.writeFileSync(file, supportFileContentMap[file], {encoding: 'utf-8'}); | ||
} catch(e) { | ||
logger.debug(`Error while replacing file content for ${file} with it's original content with error : ${e}`, true, e); | ||
} | ||
}); | ||
} | ||
|
||
const getAccessibilityCypressCommandEventListener = () => { | ||
return ( | ||
`require('browserstack-cypress-cli/bin/accessibility-automation/cypress');` | ||
); | ||
} | ||
|
||
const setAccessibilityEventListeners = () => { | ||
karanshah-browserstack marked this conversation as resolved.
Show resolved
Hide resolved
|
||
try { | ||
const cypressCommandEventListener = getAccessibilityCypressCommandEventListener(); | ||
glob(process.cwd() + '/cypress/support/*.js', {}, (err, files) => { | ||
if(err) return logger.debug('EXCEPTION IN BUILD START EVENT : Unable to parse cypress support files'); | ||
files.forEach(file => { | ||
try { | ||
if(!file.includes('commands.js')) { | ||
const defaultFileContent = fs.readFileSync(file, {encoding: 'utf-8'}); | ||
|
||
if(!defaultFileContent.includes(cypressCommandEventListener)) { | ||
let newFileContent = defaultFileContent + | ||
'\n' + | ||
cypressCommandEventListener + | ||
'\n' | ||
fs.writeFileSync(file, newFileContent, {encoding: 'utf-8'}); | ||
supportFileContentMap[file] = defaultFileContent; | ||
} | ||
} | ||
} catch(e) { | ||
logger.debug(`Unable to modify file contents for ${file} to set event listeners with error ${e}`, true, e); | ||
} | ||
}); | ||
}); | ||
} catch(e) { | ||
logger.debug(`Unable to parse support files to set event listeners with error ${e}`, true, e); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.