Skip to content

Commit 3505d16

Browse files
Merge branch 'master' into HST-1508_incorrect_gridname_error_message
2 parents 3ff3150 + df48f6b commit 3505d16

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2925
-311
lines changed

bin/accessibility-automation/cypress/index.js

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
const browserStackLog = (message) => {
44
if (!Cypress.env('BROWSERSTACK_LOGS')) return;
55
cy.task('browserstack_log', message);
6-
}
6+
}
77

88
const commandsToWrap = ['visit', 'click', 'type', 'request', 'dblclick', 'rightclick', 'clear', 'check', 'uncheck', 'select', 'trigger', 'selectFile', 'scrollIntoView', 'scroll', 'scrollTo', 'blur', 'focus', 'go', 'reload', 'submit', 'viewport', 'origin'];
99
// scroll is not a default function in cypress.
@@ -333,27 +333,26 @@ afterEach(() => {
333333
let filePath = '';
334334
if (attributes.invocationDetails !== undefined && attributes.invocationDetails.relativeFile !== undefined) {
335335
filePath = attributes.invocationDetails.relativeFile;
336+
} else if (attributes.prevAttempts && attributes.prevAttempts.length > 0) {
337+
filePath = (attributes.prevAttempts[0].invocationDetails && attributes.prevAttempts[0].invocationDetails.relativeFile) || '';
336338
}
337-
const payloadToSend = {
338-
"saveResults": shouldScanTestForAccessibility,
339-
"testDetails": {
340-
"name": attributes.title,
341-
"testRunId": '5058', // variable not consumed, shouldn't matter what we send
342-
"filePath": filePath,
343-
"scopeList": [
344-
filePath,
345-
attributes.title
346-
]
347-
},
348-
"platform": {
349-
"os_name": os_data,
350-
"os_version": Cypress.env("OS_VERSION"),
351-
"browser_name": Cypress.browser.name,
352-
"browser_version": Cypress.browser.version
339+
340+
let testRunUuid = null;
341+
cy.task('get_test_run_uuid', { testIdentifier: attributes.title })
342+
.then((response) => {
343+
if (response && response.testRunUuid) {
344+
testRunUuid = response.testRunUuid;
353345
}
354-
};
355-
browserStackLog(`Saving accessibility test results`);
356-
cy.wrap(saveTestResults(win, payloadToSend), {timeout: 30000}).then(() => {
346+
347+
const payloadToSend = {
348+
"thTestRunUuid": testRunUuid,
349+
"thBuildUuid": Cypress.env("BROWSERSTACK_TESTHUB_UUID"),
350+
"thJwtToken": Cypress.env("BROWSERSTACK_TESTHUB_JWT")
351+
};
352+
browserStackLog(`Payload to send: ${JSON.stringify(payloadToSend)}`);
353+
354+
return cy.wrap(saveTestResults(win, payloadToSend), {timeout: 30000});
355+
}).then(() => {
357356
browserStackLog(`Saved accessibility test results`);
358357
})
359358

@@ -422,7 +421,10 @@ Cypress.Commands.add('getAccessibilityResults', () => {
422421
}
423422
});
424423

425-
Cypress.Commands.addQuery('performScanSubjectQuery', function (chaining, setTimeout) {
426-
this.set('timeout', setTimeout);
427-
return () => cy.getSubjectFromChain(chaining);
428-
});
424+
if (!Cypress.Commands.hasOwnProperty('_browserstackSDKQueryAdded')) {
425+
Cypress.Commands.addQuery('performScanSubjectQuery', function (chaining, setTimeout) {
426+
this.set('timeout', setTimeout);
427+
return () => cy.getSubjectFromChain(chaining);
428+
});
429+
Cypress.Commands._browserstackSDKQueryAdded = true;
430+
}

bin/accessibility-automation/helper.js

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ exports.checkAccessibilityPlatform = (user_config) => {
2121
}
2222
})
2323
} catch {}
24-
24+
2525
return accessibility;
2626
}
2727

@@ -109,39 +109,37 @@ exports.createAccessibilityTestRun = async (user_config, framework) => {
109109
logger.debug(`BrowserStack Accessibility Automation Test Run ID: ${response.data.data.id}`);
110110

111111
this.setAccessibilityCypressCapabilities(user_config, response.data);
112-
helper.setBrowserstackCypressCliDependency(user_config);
112+
if(user_config.run_settings.auto_import_dev_dependencies != true) helper.setBrowserstackCypressCliDependency(user_config);
113113

114114
} catch (error) {
115115
if (error.response) {
116-
logger.error("Incorrect Cred")
116+
logger.error("Incorrect Cred");
117117
logger.error(
118118
`Exception while creating test run for BrowserStack Accessibility Automation: ${
119119
error.response.status
120-
} ${error.response.statusText} ${JSON.stringify(error.response.data)}`
120+
} ${error.response.statusText} ${JSON.stringify(error.response.data)}
121+
`
121122
);
122-
} else {
123-
if(error.message === 'Invalid configuration passed.') {
124-
logger.error("Invalid configuration passed.")
125-
logger.error(
126-
`Exception while creating test run for BrowserStack Accessibility Automation: ${
127-
error.message || error.stack
128-
}`
129-
);
130-
for(const errorkey of error.errors){
131-
logger.error(errorkey.message);
132-
}
133-
134-
} else {
135-
logger.error(
136-
`Exception while creating test run for BrowserStack Accessibility Automation: ${
137-
error.message || error.stack
138-
}`
139-
);
123+
} else if (error.message === 'Invalid configuration passed.') {
124+
logger.error("Invalid configuration passed.");
125+
logger.error(
126+
`Exception while creating test run for BrowserStack Accessibility Automation: ${
127+
error.message || error.stack
128+
}`
129+
);
130+
for (const errorkey of error.errors) {
131+
logger.error(errorkey.message);
140132
}
141-
// since create accessibility session failed
142-
process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'false';
143-
user_config.run_settings.accessibility = false;
133+
} else {
134+
logger.error(
135+
`Exception while creating test run for BrowserStack Accessibility Automation: ${
136+
error.message || error.stack
137+
}`
138+
);
144139
}
140+
// since create accessibility session failed
141+
process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'false';
142+
user_config.run_settings.accessibility = false;
145143
}
146144
}
147145

@@ -216,22 +214,52 @@ const getAccessibilityCypressCommandEventListener = (extName) => {
216214

217215
exports.setAccessibilityEventListeners = (bsConfig) => {
218216
try {
219-
// Searching form command.js recursively
217+
220218
const supportFilesData = helper.getSupportFiles(bsConfig, true);
221219
if(!supportFilesData.supportFile) return;
222-
glob(process.cwd() + supportFilesData.supportFile, {}, (err, files) => {
223-
if(err) return logger.debug('EXCEPTION IN BUILD START EVENT : Unable to parse cypress support files');
220+
221+
const isPattern = glob.hasMagic(supportFilesData.supportFile);
222+
if(!isPattern) {
223+
logger.debug(`Using user defined support file: ${supportFilesData.supportFile}`);
224+
let file;
225+
try {
226+
file = process.cwd() + supportFilesData.supportFile;
227+
const defaultFileContent = fs.readFileSync(file, {encoding: 'utf-8'});
228+
let cypressCommandEventListener = getAccessibilityCypressCommandEventListener(path.extname(file));
229+
const alreadyIncludes = defaultFileContent.includes(cypressCommandEventListener);
230+
if(!alreadyIncludes) {
231+
let newFileContent = defaultFileContent +
232+
'\n' +
233+
cypressCommandEventListener +
234+
'\n';
235+
fs.writeFileSync(file, newFileContent, {encoding: 'utf-8'});
236+
supportFileContentMap[file] = supportFilesData.cleanupParams ? supportFilesData.cleanupParams : defaultFileContent;
237+
}
238+
} catch(e) {
239+
logger.debug(`Unable to modify file contents for ${file} to set event listeners with error ${e}`, true, e);
240+
}
241+
return;
242+
}
243+
244+
const globPattern = process.cwd() + supportFilesData.supportFile;
245+
glob(globPattern, {}, (err, files) => {
246+
if(err) {
247+
logger.debug('EXCEPTION IN BUILD START EVENT : Unable to parse cypress support files');
248+
return;
249+
}
250+
224251
files.forEach(file => {
225252
try {
226-
if(!file.includes('commands.js') && !file.includes('commands.ts')) {
253+
const fileName = path.basename(file);
254+
if(['e2e.js', 'e2e.ts', 'component.ts', 'component.js'].includes(fileName) && !file.includes('node_modules')) {
255+
227256
const defaultFileContent = fs.readFileSync(file, {encoding: 'utf-8'});
228-
229257
let cypressCommandEventListener = getAccessibilityCypressCommandEventListener(path.extname(file));
230258
if(!defaultFileContent.includes(cypressCommandEventListener)) {
231-
let newFileContent = defaultFileContent +
259+
let newFileContent = defaultFileContent +
232260
'\n' +
233261
cypressCommandEventListener +
234-
'\n'
262+
'\n';
235263
fs.writeFileSync(file, newFileContent, {encoding: 'utf-8'});
236264
supportFileContentMap[file] = supportFilesData.cleanupParams ? supportFilesData.cleanupParams : defaultFileContent;
237265
}

bin/accessibility-automation/plugin/index.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const path = require("node:path");
22
const { decodeJWTToken } = require("../../helpers/utils");
33
const utils = require('../../helpers/utils');
4+
const http = require('http');
45

56
const browserstackAccessibility = (on, config) => {
67
let browser_validation = true;
@@ -14,6 +15,51 @@ const browserstackAccessibility = (on, config) => {
1415

1516
return null
1617
},
18+
get_test_run_uuid({ testIdentifier, retries = 15, interval = 300 } = {}) {
19+
return new Promise((resolve) => {
20+
if(!testIdentifier) return resolve(null);
21+
const port = process.env.REPORTER_API_PORT_NO;
22+
let attempt = 0;
23+
const fetchUuid = () => {
24+
const options = {
25+
hostname: '127.0.0.1',
26+
port,
27+
path: `/test-uuid?testIdentifier=${encodeURIComponent(testIdentifier)}`,
28+
method: 'GET',
29+
timeout: 2000
30+
};
31+
const httpModule = http;
32+
const req = httpModule.request(options, (res) => {
33+
let data = '';
34+
res.on('data', (chunk) => data += chunk);
35+
res.on('end', () => {
36+
if(res.statusCode === 200) {
37+
try {
38+
const json = JSON.parse(data || '{}');
39+
return resolve({ testRunUuid: json.testRunUuid || null });
40+
} catch(e) {
41+
return resolve(null);
42+
}
43+
} else if (res.statusCode === 404) {
44+
// Server up but endpoint not responding as expected – stop retrying.
45+
return resolve(null);
46+
} else {
47+
retryOrResolve();
48+
}
49+
});
50+
});
51+
req.on('error', () => retryOrResolve());
52+
req.on('timeout', () => { req.destroy(); retryOrResolve(); });
53+
req.end();
54+
};
55+
const retryOrResolve = () => {
56+
attempt += 1;
57+
if(attempt >= retries) return resolve(null);
58+
setTimeout(fetchUuid, interval);
59+
};
60+
fetchUuid();
61+
});
62+
}
1763
})
1864
on('before:browser:launch', (browser = {}, launchOptions) => {
1965
try {
@@ -51,6 +97,10 @@ const browserstackAccessibility = (on, config) => {
5197
config.env.ACCESSIBILITY_EXTENSION_PATH = process.env.ACCESSIBILITY_EXTENSION_PATH
5298
config.env.OS_VERSION = process.env.OS_VERSION
5399
config.env.OS = process.env.OS
100+
config.env.BROWSERSTACK_TESTHUB_UUID = process.env.BROWSERSTACK_TESTHUB_UUID
101+
config.env.BROWSERSTACK_TESTHUB_JWT = process.env.BROWSERSTACK_TESTHUB_JWT
102+
config.env.BROWSERSTACK_TESTHUB_API_PORT = process.env.BROWSERSTACK_TESTHUB_API_PORT
103+
config.env.REPORTER_API_PORT_NO = process.env.REPORTER_API_PORT_NO
54104

55105
config.env.IS_ACCESSIBILITY_EXTENSION_LOADED = browser_validation.toString()
56106

bin/commands/runs.js

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ const {
3737
supportFileCleanup
3838
} = require('../accessibility-automation/helper');
3939
const { isTurboScaleSession, getTurboScaleGridDetails, patchCypressConfigFileContent, atsFileCleanup } = require('../helpers/atsHelper');
40-
40+
const { shouldProcessEventForTesthub, checkAndSetAccessibility, findAvailablePort } = require('../testhub/utils');
41+
const TestHubHandler = require('../testhub/testhubHandler');
4142

4243
module.exports = function run(args, rawArgs) {
43-
44+
utils.normalizeTestReportingEnvVars();
4445
markBlockStart('preBuild');
4546
// set debug mode (--cli-debug)
4647
utils.setDebugMode(args);
@@ -112,9 +113,15 @@ module.exports = function run(args, rawArgs) {
112113
// set build tag caps
113114
utils.setBuildTags(bsConfig, args);
114115

115-
// Send build start to Observability
116-
if(isTestObservabilitySession) {
117-
await launchTestSession(bsConfig, bsConfigPath);
116+
checkAndSetAccessibility(bsConfig, isAccessibilitySession);
117+
118+
const preferredPort = 5348;
119+
const port = await findAvailablePort(preferredPort);
120+
process.env.REPORTER_API_PORT_NO = port
121+
122+
// Send build start to TEST REPORTING AND ANALYTICS
123+
if(shouldProcessEventForTesthub()) {
124+
await TestHubHandler.launchBuild(bsConfig, bsConfigPath);
118125
utils.setO11yProcessHooks(null, bsConfig, args, null, buildReportData);
119126
}
120127

@@ -143,13 +150,12 @@ module.exports = function run(args, rawArgs) {
143150
// set the no-wrap
144151
utils.setNoWrap(bsConfig, args);
145152

153+
// process auto-import dev dependencies
154+
utils.processAutoImportDependencies(bsConfig.run_settings);
155+
146156
// add cypress dependency if missing
147157
utils.setCypressNpmDependency(bsConfig);
148158

149-
if (isAccessibilitySession && isBrowserstackInfra) {
150-
await createAccessibilityTestRun(bsConfig);
151-
}
152-
153159
if (turboScaleSession) {
154160
const gridDetails = await getTurboScaleGridDetails(bsConfig, args, rawArgs);
155161

@@ -192,18 +198,22 @@ module.exports = function run(args, rawArgs) {
192198
logger.debug("Completed setting the configs");
193199

194200
if(!isBrowserstackInfra) {
201+
if(process.env.BS_TESTOPS_BUILD_COMPLETED) {
202+
setEventListeners(bsConfig);
203+
}
204+
195205
return runCypressTestsLocally(bsConfig, args, rawArgs);
196206
}
197207

198208
// Validate browserstack.json values and parallels specified via arguments
199209
markBlockStart('validateConfig');
200210
logger.debug("Started configs validation");
201211
return capabilityHelper.validate(bsConfig, args).then(function (cypressConfigFile) {
202-
if(process.env.BROWSERSTACK_TEST_ACCESSIBILITY) {
212+
if(process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'true') {
203213
setAccessibilityEventListeners(bsConfig);
204214
}
205215
if(process.env.BS_TESTOPS_BUILD_COMPLETED) {
206-
// setEventListeners(bsConfig);
216+
setEventListeners(bsConfig);
207217
}
208218
markBlockEnd('validateConfig');
209219
logger.debug("Completed configs validation");
@@ -365,10 +375,10 @@ module.exports = function run(args, rawArgs) {
365375
}
366376

367377
// Generate custom report!
368-
reportGenerator(bsConfig, data.build_id, args, rawArgs, buildReportData, function(){
378+
reportGenerator(bsConfig, data.build_id, args, rawArgs, buildReportData, function(modifiedExitCode=exitCode){
369379
utils.sendUsageReport(bsConfig, args, `${message}\n${dashboardLink}`, Constants.messageTypes.SUCCESS, null, buildReportData, rawArgs);
370380
markBlockEnd('postBuild');
371-
utils.handleSyncExit(exitCode, data.dashboard_url);
381+
utils.handleSyncExit(modifiedExitCode, data.dashboard_url);
372382
});
373383
} else if(!turboScaleSession){
374384
let stacktraceUrl = getStackTraceUrl();

bin/helpers/atsHelper.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const path = require('path');
22
const fs = require('fs');
33
const { consoleHolder } = require('../testObservability/helper/constants');
44
const HttpsProxyAgent = require('https-proxy-agent');
5-
5+
const { v4: uuidv4 } = require('uuid');
66
const axios = require('axios'),
77
logger = require('./logger').winstonLogger,
88
utils = require('./utils'),
@@ -86,6 +86,7 @@ exports.getTurboScaleGridDetails = async (bsConfig, args, rawArgs) => {
8686
}
8787
resolve(responseData);
8888
}).catch(error => {
89+
logger.warn(`Grid with name - ${gridName} not found`);
8990
logger.warn(utils.formatRequest(error, null, null));
9091
utils.sendUsageReport(bsConfig, args, error, Constants.messageTypes.ERROR, 'get_ats_details_failed', null, rawArgs);
9192
resolve({});
@@ -112,7 +113,9 @@ exports.patchCypressConfigFileContent = (bsConfig) => {
112113

113114
let confPath = bsConfig.run_settings.cypress_config_file;
114115
let patchedConfPathList = confPath.split(path.sep);
115-
patchedConfPathList[patchedConfPathList.length - 1] = 'patched_ats_config_file.js'
116+
const uniqueNamePatchFileName = `patched_ats_config_file_${uuidv4()}.js`;
117+
patchedConfPathList[patchedConfPathList.length - 1] = uniqueNamePatchFileName;
118+
logger.debug("Patch file name is " + uniqueNamePatchFileName);
116119
const patchedConfPath = patchedConfPathList.join(path.sep);
117120

118121
bsConfig.run_settings.patched_cypress_config_file = patchedConfPath;

bin/helpers/build.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ const createBuild = (bsConfig, zip) => {
6565
if(error.response) {
6666
logger.error(utils.formatRequest(error.response.statusText, error.response, error.response.data));
6767
reject(`${Constants.userMessages.BUILD_FAILED} Error: ${error.response.data.message}`);
68+
} else {
69+
reject(error);
6870
}
6971
}
7072
}).catch(function(err){

0 commit comments

Comments
 (0)