Skip to content

Commit 0882343

Browse files
authored
Merge branch 'master' into o11y-cypress-locally
2 parents 2059c51 + ec95b1c commit 0882343

File tree

10 files changed

+786
-19
lines changed

10 files changed

+786
-19
lines changed

bin/commands/runs.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,10 @@ module.exports = function run(args, rawArgs) {
111111
/*
112112
Send build start to Observability
113113
*/
114-
if(isTestObservabilitySession) await launchTestSession(bsConfig, bsConfigPath);
114+
if(isTestObservabilitySession) {
115+
await launchTestSession(bsConfig, bsConfigPath);
116+
utils.setO11yProcessHooks(null, bsConfig, args, null, buildReportData);
117+
}
115118

116119
// accept the system env list from bsconf and set it
117120
utils.setSystemEnvs(bsConfig);
@@ -186,7 +189,7 @@ module.exports = function run(args, rawArgs) {
186189
let specFiles = utils.getNumberOfSpecFiles(bsConfig, args, cypressConfigFile);
187190
markBlockEnd('getNumberOfSpecFiles');
188191

189-
bsConfig['run_settings']['video_config'] = utils.getVideoConfig(cypressConfigFile);
192+
bsConfig['run_settings']['video_config'] = utils.getVideoConfig(cypressConfigFile, bsConfig);
190193

191194
// return the number of parallels user specified
192195
let userSpecifiedParallels = utils.getParallels(bsConfig, args);
@@ -248,6 +251,14 @@ module.exports = function run(args, rawArgs) {
248251
if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'true') {
249252
supportFileCleanup();
250253
}
254+
// Set config args for enforce_settings
255+
if ( !utils.isUndefinedOrFalse(bsConfig.run_settings.enforce_settings) ) {
256+
markBlockStart('setEnforceSettingsConfig');
257+
logger.debug('Started setting the configs');
258+
utils.setEnforceSettingsConfig(bsConfig);
259+
logger.debug('Completed setting the configs');
260+
markBlockEnd('setEnforceSettingsConfig');
261+
}
251262
// Create build
252263
//setup Local Testing
253264
markBlockStart('localSetup');
@@ -264,6 +275,9 @@ module.exports = function run(args, rawArgs) {
264275
markBlockEnd('createBuild');
265276
markBlockEnd('total');
266277
utils.setProcessHooks(data.build_id, bsConfig, bs_local, args, buildReportData);
278+
if(isTestObservabilitySession) {
279+
utils.setO11yProcessHooks(data.build_id, bsConfig, bs_local, args, buildReportData);
280+
}
267281
let message = `${data.message}! ${Constants.userMessages.BUILD_CREATED} with build id: ${data.build_id}`;
268282
let dashboardLink = `${Constants.userMessages.VISIT_DASHBOARD} ${data.dashboard_url}`;
269283
buildReportData = { 'build_id': data.build_id, 'parallels': userSpecifiedParallels, ...buildReportData }

bin/helpers/capabilityHelper.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ const validate = (bsConfig, args) => {
184184
reject(Constants.validationMessages.EMPTY_CYPRESS_CONFIG_FILE);
185185
}
186186

187+
if ( bsConfig && bsConfig.run_settings && bsConfig.run_settings.enforce_settings && bsConfig.run_settings.enforce_settings.toString() === 'true' && Utils.isUndefined(bsConfig.run_settings.specs) ) {
188+
reject(Constants.validationMessages.EMPTY_SPECS_IN_BROWSERSTACK_JSON);
189+
}
190+
187191
// validate parallels specified in browserstack.json if parallels are not specified via arguments
188192
if (!Utils.isUndefined(args) && Utils.isUndefined(args.parallels) && !Utils.isParallelValid(bsConfig.run_settings.parallels)) reject(Constants.validationMessages.INVALID_PARALLELS_CONFIGURATION);
189193

@@ -214,7 +218,8 @@ const validate = (bsConfig, args) => {
214218

215219
logger.debug(`Validating ${bsConfig.run_settings.cypress_config_filename}`);
216220
try {
217-
if (bsConfig.run_settings.cypress_config_filename !== 'false') {
221+
// Not reading cypress config file upon enforce_settings
222+
if (Utils.isUndefinedOrFalse(bsConfig.run_settings.enforce_settings) && bsConfig.run_settings.cypress_config_filename !== 'false') {
218223
if (bsConfig.run_settings.cypressTestSuiteType === Constants.CYPRESS_V10_AND_ABOVE_TYPE) {
219224
const completeCypressConfigFile = readCypressConfigFile(bsConfig)
220225
if (!Utils.isUndefined(completeCypressConfigFile)) {
@@ -234,6 +239,11 @@ const validate = (bsConfig, args) => {
234239
// Detect if the user is not using the right directory structure, and throw an error
235240
if (!Utils.isUndefined(cypressConfigFile.integrationFolder) && !Utils.isCypressProjDirValid(bsConfig.run_settings.cypressProjectDir,cypressConfigFile.integrationFolder)) reject(Constants.validationMessages.INCORRECT_DIRECTORY_STRUCTURE);
236241
}
242+
else {
243+
logger.debug("Validating baseurl and integrationFolder in browserstack.json");
244+
if (!Utils.isUndefined(bsConfig.run_settings.baseUrl) && bsConfig.run_settings.baseUrl.includes("localhost") && !Utils.getLocalFlag(bsConfig.connection_settings)) reject(Constants.validationMessages.LOCAL_NOT_SET.replace("<baseUrlValue>", bsConfig.run_settings.baseUrl));
245+
if (!Utils.isUndefined(bsConfig.run_settings.integrationFolder) && !Utils.isCypressProjDirValid(bsConfig.run_settings.cypressProjectDir,bsConfig.run_settings.integrationFolder)) reject(Constants.validationMessages.INCORRECT_DIRECTORY_STRUCTURE);
246+
}
237247
} catch(error){
238248
reject(Constants.validationMessages.INVALID_CYPRESS_JSON)
239249
}

bin/helpers/constants.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ const userMessages = {
7272
UPLOADING_NPM_PACKAGES_SUCCESS: "Uploaded node_modules successfully",
7373
SKIP_UPLOADING_TESTS:
7474
"Skipping zip upload since BrowserStack already has your test suite that has not changed since the last run.",
75+
SKIP_NPM_INSTALL:
76+
"Skipping NPM Install as the enforce_settings has been passed.",
7577
SKIP_UPLOADING_NPM_PACKAGES:
7678
"Skipping the upload of node_modules since BrowserStack has already cached your npm dependencies that have not changed since the last run.",
7779
LOCAL_TRUE: "you will now be able to test localhost / private URLs",
@@ -134,6 +136,8 @@ const validationMessages = {
134136
"cypress_proj_dir is not set in run_settings. See https://www.browserstack.com/docs/automate/cypress/sample-tutorial to learn more.",
135137
EMPTY_CYPRESS_CONFIG_FILE:
136138
"cypress_config_file is not set in run_settings. See https://www.browserstack.com/docs/automate/cypress/configuration-file to learn more.",
139+
EMPTY_SPECS_IN_BROWSERSTACK_JSON:
140+
"specs is required when enforce_settings is true in run_settings of browserstack.json",
137141
VALIDATED: "browserstack.json file is validated",
138142
NOT_VALID: "browserstack.json is not valid",
139143
NOT_VALID_JSON: "browerstack.json is not a valid json",

bin/helpers/packageInstaller.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,11 @@ const packageSetupAndInstaller = (bsConfig, packageDir, instrumentBlocks) => {
133133
let obj = {
134134
packagesInstalled: false
135135
};
136-
136+
if (bsConfig && bsConfig.run_settings && bsConfig.run_settings.enforce_settings && bsConfig.run_settings.enforce_settings.toString() === 'true' ) {
137+
logger.info("Enforce_settings is enabled in run_settings");
138+
logger.debug(Constants.userMessages.SKIP_NPM_INSTALL);
139+
return resolve(obj);
140+
}
137141
logger.info(Constants.userMessages.NPM_INSTALL);
138142
instrumentBlocks.markBlockStart("packageInstaller.folderSetup");
139143
logger.debug("Started setting up package folder");

bin/helpers/utils.js

Lines changed: 93 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const usageReporting = require("./usageReporting"),
2222
config = require("../helpers/config"),
2323
pkg = require('../../package.json'),
2424
transports = require('./logger').transports,
25-
{ findGitConfig, printBuildLink, isTestObservabilitySession, isBrowserstackInfra, shouldReRunObservabilityTests } = require('../testObservability/helper/helper'),
25+
o11yHelpers = require('../testObservability/helper/helper'),
2626
{ OBSERVABILITY_ENV_VARS, TEST_OBSERVABILITY_REPORTER } = require('../testObservability/helper/constants');
2727

2828
const request = require('request');
@@ -434,7 +434,8 @@ exports.setProjectId = (bsConfig, args, cypressConfigFile) => {
434434
} else if(!this.isUndefined(bsConfig.run_settings["projectId"])) {
435435
return bsConfig.run_settings["projectId"];
436436
} else {
437-
if (!this.isUndefined(cypressConfigFile) && !this.isUndefined(cypressConfigFile["projectId"])) {
437+
// ignore reading cypressconfig if enforce_settings is passed
438+
if (this.isUndefinedOrFalse(bsConfig.run_settings.enforce_settings) && !this.isUndefined(cypressConfigFile) && !this.isUndefined(cypressConfigFile["projectId"])) {
438439
return cypressConfigFile["projectId"];
439440
}
440441
}
@@ -480,7 +481,7 @@ exports.setNodeVersion = (bsConfig, args) => {
480481
// specs can be passed via command line args as a string
481482
// command line args takes precedence over config
482483
exports.setUserSpecs = (bsConfig, args) => {
483-
if(isBrowserstackInfra() && isTestObservabilitySession() && shouldReRunObservabilityTests()) {
484+
if(o11yHelpers.isBrowserstackInfra() && o11yHelpers.isTestObservabilitySession() && o11yHelpers.shouldReRunObservabilityTests()) {
484485
bsConfig.run_settings.specs = process.env.BROWSERSTACK_RERUN_TESTS;
485486
return;
486487
}
@@ -580,8 +581,8 @@ exports.setSystemEnvs = (bsConfig) => {
580581
envKeys[key] = process.env[key];
581582
});
582583

583-
let gitConfigPath = findGitConfig(process.cwd());
584-
if(!isBrowserstackInfra()) process.env.OBSERVABILITY_GIT_CONFIG_PATH_LOCAL = gitConfigPath;
584+
let gitConfigPath = o11yHelpers.findGitConfig(process.cwd());
585+
if(!o11yHelpers.isBrowserstackInfra()) process.env.OBSERVABILITY_GIT_CONFIG_PATH_LOCAL = gitConfigPath;
585586
if(gitConfigPath) {
586587
const relativePathFromGitConfig = path.relative(gitConfigPath, process.cwd());
587588
envKeys["OBSERVABILITY_GIT_CONFIG_PATH"] = relativePathFromGitConfig ? relativePathFromGitConfig : 'DEFAULT';
@@ -628,6 +629,8 @@ exports.isPositiveInteger = (str) => {
628629

629630
exports.isTrueString = value => (!this.isUndefined(value) && value.toString().toLowerCase() === 'true');
630631

632+
exports.isUndefinedOrFalse = value => ( this.isUndefined(value) || value.toString().toLowerCase() === 'false');
633+
631634
exports.isFloat = (value) => Number(value) && Number(value) % 1 !== 0;
632635

633636
exports.isInteger = (value) => Number.isInteger(value);
@@ -1077,7 +1080,8 @@ exports.getNumberOfSpecFiles = (bsConfig, args, cypressConfig) => {
10771080
if (bsConfig.run_settings.cypressTestSuiteType === Constants.CYPRESS_V10_AND_ABOVE_TYPE) {
10781081
defaultSpecFolder = Constants.DEFAULT_CYPRESS_10_SPEC_PATH
10791082
testFolderPath = defaultSpecFolder
1080-
if(!this.isUndefined(cypressConfig) && !this.isUndefined(cypressConfig.e2e)) {
1083+
// Read cypress config if enforce_settings is not present
1084+
if(this.isUndefinedOrFalse(bsConfig.run_settings.enforce_settings) && !this.isUndefined(cypressConfig) && !this.isUndefined(cypressConfig.e2e)) {
10811085
if(!this.isUndefined(cypressConfig.e2e.specPattern)) {
10821086
globCypressConfigSpecPatterns = Array.isArray(cypressConfig.e2e.specPattern) ?
10831087
cypressConfig.e2e.specPattern : [cypressConfig.e2e.specPattern];
@@ -1184,8 +1188,8 @@ exports.handleSyncExit = (exitCode, dashboard_url) => {
11841188
syncCliLogger.info(Constants.userMessages.BUILD_REPORT_MESSAGE);
11851189
syncCliLogger.info(dashboard_url);
11861190
}
1187-
if(isTestObservabilitySession()) {
1188-
printBuildLink(true, exitCode);
1191+
if(o11yHelpers.isTestObservabilitySession()) {
1192+
o11yHelpers.printBuildLink(true, exitCode);
11891193
} else {
11901194
process.exit(exitCode);
11911195
}
@@ -1286,9 +1290,53 @@ exports.setConfig = (bsConfig, args) => {
12861290
}
12871291
}
12881292

1293+
exports.setVideoCliConfig = (bsConfig, videoConfig) => {
1294+
// set cli config for video for cypress 13 and above to attain default value of true.
1295+
if(this.isUndefined(videoConfig) || this.isUndefined(videoConfig.video) || this.isUndefined(videoConfig.videoUploadOnPasses) || this.isUndefined(bsConfig)) return;
1296+
let user_cypress_version = (bsConfig && bsConfig.run_settings && bsConfig.run_settings.cypress_version) ? bsConfig.run_settings.cypress_version.toString() : undefined;
1297+
let cypress_major_version = (user_cypress_version && user_cypress_version.match(/^(\d+)/)) ? user_cypress_version.split(".")[0] : undefined;
1298+
let config_args = (bsConfig && bsConfig.run_settings && bsConfig.run_settings.config) ? bsConfig.run_settings.config : undefined;
1299+
if(this.isUndefined(user_cypress_version) || this.isUndefined(cypress_major_version) || parseInt(cypress_major_version) >= 13 ) {
1300+
let video_args = `video=${videoConfig.video},videoUploadOnPasses=${videoConfig.videoUploadOnPasses}`;
1301+
config_args = this.isUndefined(config_args) ? video_args : config_args + ',' + video_args;
1302+
logger.debug(`Setting default video true for cypress 13 and above in cli for cypress version ${user_cypress_version} with cli args - ${config_args}`)
1303+
}
1304+
if (bsConfig.run_settings && this.isNotUndefined(config_args)) bsConfig["run_settings"]["config"] = config_args;
1305+
}
1306+
1307+
// set configs if enforce_settings is passed
1308+
exports.setEnforceSettingsConfig = (bsConfig) => {
1309+
if ( this.isUndefined(bsConfig) || this.isUndefined(bsConfig.run_settings) ) return;
1310+
let config_args = (bsConfig && bsConfig.run_settings && bsConfig.run_settings.config) ? bsConfig.run_settings.config : undefined;
1311+
if ( this.isUndefined(config_args) || !config_args.includes("video") ) {
1312+
let video_args = (this.isUndefined(bsConfig.run_settings.video_config) || this.isUndefined(bsConfig.run_settings.video_config.video) || !bsConfig.run_settings.video_config.video ) ? 'video=false' : 'video=true' ;
1313+
video_args += (this.isUndefined(bsConfig.run_settings.video_config) || this.isUndefined(bsConfig.run_settings.video_config.videoUploadOnPasses) || !bsConfig.run_settings.video_config.videoUploadOnPasses ) ? ',videoUploadOnPasses=false' : ',videoUploadOnPasses=true';
1314+
config_args = this.isUndefined(config_args) ? video_args : config_args + ',' + video_args;
1315+
logger.debug(`Setting video_args for enforce_settings to ${video_args}`);
1316+
}
1317+
if ( (bsConfig && bsConfig.run_settings && bsConfig.run_settings.baseUrl) && (this.isUndefined(config_args) || !config_args.includes("baseUrl")) ) {
1318+
let base_url_args = 'baseUrl='+bsConfig.run_settings.baseUrl;
1319+
config_args = this.isUndefined(config_args) ? base_url_args : config_args + ',' + base_url_args;
1320+
logger.debug(`Setting base_url_args for enforce_settings to ${base_url_args}`);
1321+
}
1322+
// set specs in config of specpattern to override cypress config
1323+
if( this.isNotUndefined(bsConfig.run_settings.specs) && bsConfig.run_settings.cypressTestSuiteType === Constants.CYPRESS_V10_AND_ABOVE_TYPE && (this.isUndefined(config_args) || !config_args.includes("specPattern")) ) {
1324+
// doing this only for cypress 10 and above as --spec is given precedence for cypress 9.
1325+
let specConfigs = bsConfig.run_settings.specs;
1326+
// if multiple specs are passed, convert it into an array.
1327+
if(specConfigs && specConfigs.includes(',')) {
1328+
specConfigs = JSON.stringify(specConfigs.split(','));
1329+
}
1330+
let spec_pattern_args = 'specPattern="'+specConfigs+'"';
1331+
config_args = this.isUndefined(config_args) ? spec_pattern_args : config_args + ',' + spec_pattern_args;
1332+
}
1333+
if ( this.isNotUndefined(config_args) ) bsConfig["run_settings"]["config"] = config_args;
1334+
logger.debug(`Setting conifg_args for enforce_settings to ${config_args}`);
1335+
}
1336+
12891337
// blindly send other passed configs with run_settings and handle at backend
12901338
exports.setOtherConfigs = (bsConfig, args) => {
1291-
if(isTestObservabilitySession() && process.env.BS_TESTOPS_JWT) {
1339+
if(o11yHelpers.isTestObservabilitySession() && process.env.BS_TESTOPS_JWT) {
12921340
bsConfig["run_settings"]["reporter"] = TEST_OBSERVABILITY_REPORTER;
12931341
return;
12941342
}
@@ -1453,14 +1501,37 @@ exports.setProcessHooks = (buildId, bsConfig, bsLocal, args, buildReportData) =>
14531501
process.on('uncaughtException', processExitHandler.bind(this, bindData));
14541502
}
14551503

1504+
exports.setO11yProcessHooks = (() => {
1505+
let bindData = {};
1506+
let handlerAdded = false;
1507+
return (buildId, bsConfig, bsLocal, args, buildReportData) => {
1508+
bindData.buildId = buildId;
1509+
bindData.bsConfig = bsConfig;
1510+
bindData.bsLocal = bsLocal;
1511+
bindData.args = args;
1512+
bindData.buildReportData = buildReportData;
1513+
if (handlerAdded) return;
1514+
handlerAdded = true;
1515+
process.on('beforeExit', processO11yExitHandler.bind(this, bindData));
1516+
}
1517+
})()
1518+
14561519
async function processExitHandler(exitData){
14571520
logger.warn(Constants.userMessages.PROCESS_KILL_MESSAGE);
14581521
await this.stopBrowserStackBuild(exitData.bsConfig, exitData.args, exitData.buildId, null, exitData.buildReportData);
14591522
await this.stopLocalBinary(exitData.bsConfig, exitData.bsLocalInstance, exitData.args, null, exitData.buildReportData);
1460-
await printBuildLink(true);
1523+
await o11yHelpers.printBuildLink(true);
14611524
process.exit(0);
14621525
}
14631526

1527+
async function processO11yExitHandler(exitData){
1528+
if (exitData.buildId) {
1529+
await o11yHelpers.printBuildLink(false);
1530+
} else {
1531+
await o11yHelpers.printBuildLink(true);
1532+
}
1533+
}
1534+
14641535
exports.fetchZipSize = (fileName) => {
14651536
try {
14661537
let stats = fs.statSync(fileName)
@@ -1499,14 +1570,23 @@ exports.fetchFolderSize = async (dir) => {
14991570
}
15001571
}
15011572

1502-
exports.getVideoConfig = (cypressConfig) => {
1573+
exports.getVideoConfig = (cypressConfig, bsConfig = {}) => {
15031574
let conf = {
15041575
video: true,
15051576
videoUploadOnPasses: true
15061577
}
1507-
if (!this.isUndefined(cypressConfig.video)) conf.video = cypressConfig.video;
1508-
if (!this.isUndefined(cypressConfig.videoUploadOnPasses)) conf.videoUploadOnPasses = cypressConfig.videoUploadOnPasses;
1578+
// Reading bsconfig in case of enforce_settings
1579+
if ( this.isUndefined(bsConfig.run_settings) || this.isUndefinedOrFalse(bsConfig.run_settings.enforce_settings) ) {
1580+
if (!this.isUndefined(cypressConfig.video)) conf.video = cypressConfig.video;
1581+
if (!this.isUndefined(cypressConfig.videoUploadOnPasses)) conf.videoUploadOnPasses = cypressConfig.videoUploadOnPasses;
1582+
}
1583+
else {
1584+
if (!this.isUndefined(bsConfig.run_settings) && !this.isUndefined(bsConfig.run_settings.video)) conf.video = bsConfig.run_settings.video;
1585+
if (!this.isUndefined(bsConfig.run_settings) && !this.isUndefined(bsConfig.run_settings.videoUploadOnPasses)) conf.videoUploadOnPasses = bsConfig.run_settings.videoUploadOnPasses;
1586+
}
15091587

1588+
// set video in cli config in case of cypress 13 or above as default value is false there.
1589+
this.setVideoCliConfig(bsConfig,conf);
15101590
logger.debug(`Setting video = ${conf.video}`);
15111591
logger.debug(`Setting videoUploadOnPasses = ${conf.videoUploadOnPasses}`);
15121592
return conf;

bin/testObservability/helper/helper.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,11 @@ const supportFileCleanup = () => {
6565
});
6666
}
6767

68+
exports.buildStopped = false;
69+
6870
exports.printBuildLink = async (shouldStopSession, exitCode = null) => {
69-
if(!this.isTestObservabilitySession()) return;
71+
if(!this.isTestObservabilitySession() || exports.buildStopped) return;
72+
exports.buildStopped = true;
7073
try {
7174
if(shouldStopSession) {
7275
supportFileCleanup();

0 commit comments

Comments
 (0)