Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@
"by": "readonly",
"expect": "readonly",
"browser": "readonly",
"Key": "readonly"
"Key": "readonly",
"URLSearchParams": "readonly"

}
}
20 changes: 15 additions & 5 deletions nightwatch/globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ module.exports = {
});

eventBroadcaster.on('TestRunStarted', async (test) => {
process.env.VALID_ALLY_PLATFORM = accessibilityAutomation.validateA11yCaps(browser);
process.env.VALID_ALLY_PLATFORM = process.env.BROWSERSTACK_APP_AUTOMATE ? accessibilityAutomation.validateAppA11yCaps(test.metadata.sessionCapabilities) : accessibilityAutomation.validateA11yCaps(browser);
await accessibilityAutomation.beforeEachExecution(test);
if (testRunner !== 'cucumber'){
const uuid = TestMap.storeTestDetails(test);
Expand Down Expand Up @@ -357,7 +357,9 @@ module.exports = {
if (helper.isAccessibilitySession() && !settings.parallel_mode) {
accessibilityAutomation.setAccessibilityCapabilities(settings);
accessibilityAutomation.commandWrapper();
helper.patchBrowserTerminateCommand();
if (!process.env.BROWSERSTACK_APP_AUTOMATE){
helper.patchBrowserTerminateCommand();
};
}
} catch (err){
Logger.debug(`Exception while setting Accessibility Automation capabilities. Error ${err}`);
Expand Down Expand Up @@ -489,8 +491,14 @@ module.exports = {
},

async beforeEach(settings) {
browser.getAccessibilityResults = () => { return accessibilityAutomation.getAccessibilityResults() };
browser.getAccessibilityResultsSummary = () => { return accessibilityAutomation.getAccessibilityResultsSummary() };
if (helper.isAppAccessibilitySession()){
browser.getAccessibilityResults = () => { return accessibilityAutomation.getAppAccessibilityResults(browser) };
browser.getAccessibilityResultsSummary = () => { return accessibilityAutomation.getAppAccessibilityResultsSummary(browser) };
} else {
browser.getAccessibilityResults = () => { return accessibilityAutomation.getAccessibilityResults() };
browser.getAccessibilityResultsSummary = () => { return accessibilityAutomation.getAccessibilityResultsSummary() };
}
// await accessibilityAutomation.beforeEachExecution(browser);
},

// This will be run after each test suite is finished
Expand Down Expand Up @@ -531,7 +539,9 @@ module.exports = {
if (helper.isAccessibilitySession()) {
accessibilityAutomation.setAccessibilityCapabilities(settings);
accessibilityAutomation.commandWrapper();
helper.patchBrowserTerminateCommand();
if (!process.env.BROWSERSTACK_APP_AUTOMATE){
helper.patchBrowserTerminateCommand();
};
}
} catch (err){
Logger.debug(`Exception while setting Accessibility Automation capabilities. Error ${err}`);
Expand Down
18 changes: 10 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nightwatch/browserstack",
"version": "3.6.2",
"version": "3.7.1",
"description": "Nightwatch plugin for integration with browserstack.",
"main": "index.js",
"scripts": {
Expand Down Expand Up @@ -45,7 +45,8 @@
"@cypress/request": "^3.0.1",
"strip-ansi": "^6.0.1",
"winston-transport": "^4.5.0",
"uuid": "^9.0.0"
"uuid": "^9.0.0",
"glob": "^7.2.0"
},
"devDependencies": {
"chai": "^4.3.7",
Expand Down
139 changes: 135 additions & 4 deletions src/accessibilityAutomation.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const path = require('path');
const helper = require('./utils/helper');
const Logger = require('./utils/logger');
const {APP_ALLY_ENDPOINT, APP_ALLY_ISSUES_SUMMARY_ENDPOINT, APP_ALLY_ISSUES_ENDPOINT} = require('./utils/constants');
const util = require('util');
const AccessibilityScripts = require('./scripts/accessibilityScripts');

Expand Down Expand Up @@ -162,14 +163,38 @@ class AccessibilityAutomation {
return false;
}

validateAppA11yCaps(capabilities = {}) {
/* Check if the current driver platform is eligible for AppAccessibility scan */
if (
capabilities?.platformName &&
String(capabilities?.platformName).toLowerCase() === 'android' &&
capabilities?.platformVersion &&
parseInt(capabilities?.platformVersion?.toString()) < 11
) {
Logger.warn(
'App Accessibility Automation tests are supported on OS version 11 and above for Android devices.'
);

return false;
}

return true;
}

async beforeEachExecution(testMetaData) {
try {
this.currentTest = browser.currentTest;
this.currentTest.shouldScanTestForAccessibility = this.shouldScanTestForAccessibility(
testMetaData
);
this.currentTest.accessibilityScanStarted = true;
this._isAccessibilitySession = this.validateA11yCaps(browser);

this._isAppAccessibility = helper.isAppAccessibilitySession();
if (this._isAppAccessibility) {
this._isAccessibilitySession = this.validateAppA11yCaps(testMetaData.metadata.sessionCapabilities);
} else {
this._isAccessibilitySession = this.validateA11yCaps(browser);
}

if (this.isAccessibilityAutomationSession() && browser && this._isAccessibilitySession) {
try {
Expand Down Expand Up @@ -267,10 +292,9 @@ class AccessibilityAutomation {
}

if (this.currentTest.shouldScanTestForAccessibility === false) {
Logger.info('Skipping Accessibility scan for this test as it\'s disabled.');

return;
}

try {
const browser = browserInstance;

Expand All @@ -279,6 +303,16 @@ class AccessibilityAutomation {

return;
}

if (helper.isAppAccessibilitySession()){
const results = await browser.executeScript(
helper.formatString(AccessibilityScripts.performScan, JSON.stringify(this.getParamsForAppAccessibility(commandName))),
{}
);
Logger.debug(util.inspect(results));

return results;
}
AccessibilityAutomation.pendingAllyReq++;
const results = await browser.executeAsyncScript(AccessibilityScripts.performScan, {
method: commandName || ''
Expand All @@ -297,9 +331,79 @@ class AccessibilityAutomation {
}
}

async getAppAccessibilityResults(browser) {
if (!helper.isBrowserstackInfra()) {
return [];
}

if (!helper.isAppAccessibilitySession()) {
Logger.warn('Not an Accessibility Automation session, cannot retrieve Accessibility results.');

return [];
}

try {
const apiUrl = `${APP_ALLY_ENDPOINT}/${APP_ALLY_ISSUES_ENDPOINT}`;
const apiRespone = await this.getAppA11yResultResponse(apiUrl, browser, browser.sessionId);
const result = apiRespone?.data?.data?.issues;
Logger.debug(`Results: ${JSON.stringify(result)}`);

return result;
} catch (error) {
Logger.error('No accessibility results were found.');
Logger.debug(`getAppAccessibilityResults Failed. Error: ${error}`);

return [];
}

}

async getAppAccessibilityResultsSummary(browser) {
if (!helper.isBrowserstackInfra()) {
return {};
}

if (!helper.isAppAccessibilitySession()) {
Logger.warn('Not an Accessibility Automation session, cannot retrieve Accessibility results summary.');

return {};
}
try {
const apiUrl = `${APP_ALLY_ENDPOINT}/${APP_ALLY_ISSUES_SUMMARY_ENDPOINT}`;
const apiRespone = await this.getAppA11yResultResponse(apiUrl, browser, browser.sessionId);
const result = apiRespone?.data?.data?.summary;
Logger.debug(`Results Summary: ${JSON.stringify(result)}`);

return result;
} catch (error) {
Logger.error('No accessibility result summary were found.');
Logger.debug(`getAppAccessibilityResultsSummary Failed. Error: ${error}`);

return {};
}
}

async getAppA11yResultResponse(apiUrl, browser, sessionId){
Logger.debug('Performing scan before getting results/results summary');
await this.performScan(browser);

const upperTimeLimit = process.env.BSTACK_A11Y_POLLING_TIMEOUT ? Date.now() + parseInt(process.env.BSTACK_A11Y_POLLING_TIMEOUT) * 1000 : Date.now() + 30000;
const params = {test_run_uuid: process.env.TEST_RUN_UUID, session_id: sessionId, timestamp: Date.now()}; // Query params to pass
const header = {Authorization: `Bearer ${process.env.BSTACK_A11Y_JWT}`};
const apiRespone = await helper.pollApi(apiUrl, params, header, upperTimeLimit);
Logger.debug(`Polling Result: ${JSON.stringify(apiRespone.message)}`);

return apiRespone;

}


async saveAccessibilityResults(browser, dataForExtension = {}) {
Logger.debug('Performing scan before saving results');
await this.performScan(browser);
if (helper.isAppAccessibilitySession()){
return;
}
const results = await browser.executeAsyncScript(AccessibilityScripts.saveTestResults, dataForExtension);

return results;
Expand Down Expand Up @@ -336,7 +440,12 @@ class AccessibilityAutomation {
const originalCommandFn = originalCommand.command;

originalCommand.command = async function(...args) {
await accessibilityInstance.performScan(browser, commandName);
if (
!commandName.includes('execute') ||
!accessibilityInstance.shouldPatchExecuteScript(args.length ? args[0] : null)
) {
await accessibilityInstance.performScan(browser, commandName);
}

return originalCommandFn.apply(this, args);
};
Expand All @@ -347,6 +456,28 @@ class AccessibilityAutomation {
}
}
}

shouldPatchExecuteScript(script) {
if (!script || typeof script !== 'string') {
return true;
}

return (
script.toLowerCase().indexOf('browserstack_executor') !== -1 ||
script.toLowerCase().indexOf('browserstack_accessibility_automation_script') !== -1
);
}

getParamsForAppAccessibility(commandName) {
return {
'thTestRunUuid': process.env.TEST_RUN_UUID,
'thBuildUuid': process.env.BROWSERSTACK_TESTHUB_UUID,
'thJwtToken': process.env.BROWSERSTACK_TESTHUB_JWT,
'authHeader': process.env.BSTACK_A11Y_JWT,
'scanTimestamp': Date.now(),
'method': commandName
};
}
}

module.exports = AccessibilityAutomation;
1 change: 1 addition & 0 deletions src/testObservability.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ class TestObservability {
accessibilityScripts.store();
}
}
process.env.IS_APP_ACCESSIBILITY = accessibilityAutomation.isAccessibilityAutomationSession() && helper.isAppAutomate();

}

Expand Down
4 changes: 3 additions & 1 deletion src/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ exports.EVENTS = {
SCREENSHOT: 'testObservability:screenshot'
};
exports.ACCESSIBILITY_URL= 'https://accessibility.browserstack.com/api';

exports.APP_ALLY_ENDPOINT = 'https://app-accessibility.browserstack.com/automate';
exports.APP_ALLY_ISSUES_SUMMARY_ENDPOINT ='api/v1/issues-summary';
exports.APP_ALLY_ISSUES_ENDPOINT = 'api/v1/issues';
// Maximum size of VCS info which is allowed
exports.MAX_GIT_META_DATA_SIZE_IN_BYTES = 64 * 1024;

Expand Down
Loading