Skip to content

Commit

Permalink
Merge branch 'master' into o11y-cypress-locally
Browse files Browse the repository at this point in the history
  • Loading branch information
pranavj1001 authored Dec 8, 2023
2 parents 2059c51 + ec95b1c commit 0882343
Show file tree
Hide file tree
Showing 10 changed files with 786 additions and 19 deletions.
18 changes: 16 additions & 2 deletions bin/commands/runs.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,10 @@ module.exports = function run(args, rawArgs) {
/*
Send build start to Observability
*/
if(isTestObservabilitySession) await launchTestSession(bsConfig, bsConfigPath);
if(isTestObservabilitySession) {
await launchTestSession(bsConfig, bsConfigPath);
utils.setO11yProcessHooks(null, bsConfig, args, null, buildReportData);
}

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

bsConfig['run_settings']['video_config'] = utils.getVideoConfig(cypressConfigFile);
bsConfig['run_settings']['video_config'] = utils.getVideoConfig(cypressConfigFile, bsConfig);

// return the number of parallels user specified
let userSpecifiedParallels = utils.getParallels(bsConfig, args);
Expand Down Expand Up @@ -248,6 +251,14 @@ module.exports = function run(args, rawArgs) {
if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'true') {
supportFileCleanup();
}
// Set config args for enforce_settings
if ( !utils.isUndefinedOrFalse(bsConfig.run_settings.enforce_settings) ) {
markBlockStart('setEnforceSettingsConfig');
logger.debug('Started setting the configs');
utils.setEnforceSettingsConfig(bsConfig);
logger.debug('Completed setting the configs');
markBlockEnd('setEnforceSettingsConfig');
}
// Create build
//setup Local Testing
markBlockStart('localSetup');
Expand All @@ -264,6 +275,9 @@ module.exports = function run(args, rawArgs) {
markBlockEnd('createBuild');
markBlockEnd('total');
utils.setProcessHooks(data.build_id, bsConfig, bs_local, args, buildReportData);
if(isTestObservabilitySession) {
utils.setO11yProcessHooks(data.build_id, bsConfig, bs_local, args, buildReportData);
}
let message = `${data.message}! ${Constants.userMessages.BUILD_CREATED} with build id: ${data.build_id}`;
let dashboardLink = `${Constants.userMessages.VISIT_DASHBOARD} ${data.dashboard_url}`;
buildReportData = { 'build_id': data.build_id, 'parallels': userSpecifiedParallels, ...buildReportData }
Expand Down
12 changes: 11 additions & 1 deletion bin/helpers/capabilityHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ const validate = (bsConfig, args) => {
reject(Constants.validationMessages.EMPTY_CYPRESS_CONFIG_FILE);
}

if ( bsConfig && bsConfig.run_settings && bsConfig.run_settings.enforce_settings && bsConfig.run_settings.enforce_settings.toString() === 'true' && Utils.isUndefined(bsConfig.run_settings.specs) ) {
reject(Constants.validationMessages.EMPTY_SPECS_IN_BROWSERSTACK_JSON);
}

// validate parallels specified in browserstack.json if parallels are not specified via arguments
if (!Utils.isUndefined(args) && Utils.isUndefined(args.parallels) && !Utils.isParallelValid(bsConfig.run_settings.parallels)) reject(Constants.validationMessages.INVALID_PARALLELS_CONFIGURATION);

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

logger.debug(`Validating ${bsConfig.run_settings.cypress_config_filename}`);
try {
if (bsConfig.run_settings.cypress_config_filename !== 'false') {
// Not reading cypress config file upon enforce_settings
if (Utils.isUndefinedOrFalse(bsConfig.run_settings.enforce_settings) && bsConfig.run_settings.cypress_config_filename !== 'false') {
if (bsConfig.run_settings.cypressTestSuiteType === Constants.CYPRESS_V10_AND_ABOVE_TYPE) {
const completeCypressConfigFile = readCypressConfigFile(bsConfig)
if (!Utils.isUndefined(completeCypressConfigFile)) {
Expand All @@ -234,6 +239,11 @@ const validate = (bsConfig, args) => {
// Detect if the user is not using the right directory structure, and throw an error
if (!Utils.isUndefined(cypressConfigFile.integrationFolder) && !Utils.isCypressProjDirValid(bsConfig.run_settings.cypressProjectDir,cypressConfigFile.integrationFolder)) reject(Constants.validationMessages.INCORRECT_DIRECTORY_STRUCTURE);
}
else {
logger.debug("Validating baseurl and integrationFolder in browserstack.json");
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));
if (!Utils.isUndefined(bsConfig.run_settings.integrationFolder) && !Utils.isCypressProjDirValid(bsConfig.run_settings.cypressProjectDir,bsConfig.run_settings.integrationFolder)) reject(Constants.validationMessages.INCORRECT_DIRECTORY_STRUCTURE);
}
} catch(error){
reject(Constants.validationMessages.INVALID_CYPRESS_JSON)
}
Expand Down
4 changes: 4 additions & 0 deletions bin/helpers/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ const userMessages = {
UPLOADING_NPM_PACKAGES_SUCCESS: "Uploaded node_modules successfully",
SKIP_UPLOADING_TESTS:
"Skipping zip upload since BrowserStack already has your test suite that has not changed since the last run.",
SKIP_NPM_INSTALL:
"Skipping NPM Install as the enforce_settings has been passed.",
SKIP_UPLOADING_NPM_PACKAGES:
"Skipping the upload of node_modules since BrowserStack has already cached your npm dependencies that have not changed since the last run.",
LOCAL_TRUE: "you will now be able to test localhost / private URLs",
Expand Down Expand Up @@ -134,6 +136,8 @@ const validationMessages = {
"cypress_proj_dir is not set in run_settings. See https://www.browserstack.com/docs/automate/cypress/sample-tutorial to learn more.",
EMPTY_CYPRESS_CONFIG_FILE:
"cypress_config_file is not set in run_settings. See https://www.browserstack.com/docs/automate/cypress/configuration-file to learn more.",
EMPTY_SPECS_IN_BROWSERSTACK_JSON:
"specs is required when enforce_settings is true in run_settings of browserstack.json",
VALIDATED: "browserstack.json file is validated",
NOT_VALID: "browserstack.json is not valid",
NOT_VALID_JSON: "browerstack.json is not a valid json",
Expand Down
6 changes: 5 additions & 1 deletion bin/helpers/packageInstaller.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,11 @@ const packageSetupAndInstaller = (bsConfig, packageDir, instrumentBlocks) => {
let obj = {
packagesInstalled: false
};

if (bsConfig && bsConfig.run_settings && bsConfig.run_settings.enforce_settings && bsConfig.run_settings.enforce_settings.toString() === 'true' ) {
logger.info("Enforce_settings is enabled in run_settings");
logger.debug(Constants.userMessages.SKIP_NPM_INSTALL);
return resolve(obj);
}
logger.info(Constants.userMessages.NPM_INSTALL);
instrumentBlocks.markBlockStart("packageInstaller.folderSetup");
logger.debug("Started setting up package folder");
Expand Down
106 changes: 93 additions & 13 deletions bin/helpers/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const usageReporting = require("./usageReporting"),
config = require("../helpers/config"),
pkg = require('../../package.json'),
transports = require('./logger').transports,
{ findGitConfig, printBuildLink, isTestObservabilitySession, isBrowserstackInfra, shouldReRunObservabilityTests } = require('../testObservability/helper/helper'),
o11yHelpers = require('../testObservability/helper/helper'),
{ OBSERVABILITY_ENV_VARS, TEST_OBSERVABILITY_REPORTER } = require('../testObservability/helper/constants');

const request = require('request');
Expand Down Expand Up @@ -434,7 +434,8 @@ exports.setProjectId = (bsConfig, args, cypressConfigFile) => {
} else if(!this.isUndefined(bsConfig.run_settings["projectId"])) {
return bsConfig.run_settings["projectId"];
} else {
if (!this.isUndefined(cypressConfigFile) && !this.isUndefined(cypressConfigFile["projectId"])) {
// ignore reading cypressconfig if enforce_settings is passed
if (this.isUndefinedOrFalse(bsConfig.run_settings.enforce_settings) && !this.isUndefined(cypressConfigFile) && !this.isUndefined(cypressConfigFile["projectId"])) {
return cypressConfigFile["projectId"];
}
}
Expand Down Expand Up @@ -480,7 +481,7 @@ exports.setNodeVersion = (bsConfig, args) => {
// specs can be passed via command line args as a string
// command line args takes precedence over config
exports.setUserSpecs = (bsConfig, args) => {
if(isBrowserstackInfra() && isTestObservabilitySession() && shouldReRunObservabilityTests()) {
if(o11yHelpers.isBrowserstackInfra() && o11yHelpers.isTestObservabilitySession() && o11yHelpers.shouldReRunObservabilityTests()) {
bsConfig.run_settings.specs = process.env.BROWSERSTACK_RERUN_TESTS;
return;
}
Expand Down Expand Up @@ -580,8 +581,8 @@ exports.setSystemEnvs = (bsConfig) => {
envKeys[key] = process.env[key];
});

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

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

exports.isUndefinedOrFalse = value => ( this.isUndefined(value) || value.toString().toLowerCase() === 'false');

exports.isFloat = (value) => Number(value) && Number(value) % 1 !== 0;

exports.isInteger = (value) => Number.isInteger(value);
Expand Down Expand Up @@ -1077,7 +1080,8 @@ exports.getNumberOfSpecFiles = (bsConfig, args, cypressConfig) => {
if (bsConfig.run_settings.cypressTestSuiteType === Constants.CYPRESS_V10_AND_ABOVE_TYPE) {
defaultSpecFolder = Constants.DEFAULT_CYPRESS_10_SPEC_PATH
testFolderPath = defaultSpecFolder
if(!this.isUndefined(cypressConfig) && !this.isUndefined(cypressConfig.e2e)) {
// Read cypress config if enforce_settings is not present
if(this.isUndefinedOrFalse(bsConfig.run_settings.enforce_settings) && !this.isUndefined(cypressConfig) && !this.isUndefined(cypressConfig.e2e)) {
if(!this.isUndefined(cypressConfig.e2e.specPattern)) {
globCypressConfigSpecPatterns = Array.isArray(cypressConfig.e2e.specPattern) ?
cypressConfig.e2e.specPattern : [cypressConfig.e2e.specPattern];
Expand Down Expand Up @@ -1184,8 +1188,8 @@ exports.handleSyncExit = (exitCode, dashboard_url) => {
syncCliLogger.info(Constants.userMessages.BUILD_REPORT_MESSAGE);
syncCliLogger.info(dashboard_url);
}
if(isTestObservabilitySession()) {
printBuildLink(true, exitCode);
if(o11yHelpers.isTestObservabilitySession()) {
o11yHelpers.printBuildLink(true, exitCode);
} else {
process.exit(exitCode);
}
Expand Down Expand Up @@ -1286,9 +1290,53 @@ exports.setConfig = (bsConfig, args) => {
}
}

exports.setVideoCliConfig = (bsConfig, videoConfig) => {
// set cli config for video for cypress 13 and above to attain default value of true.
if(this.isUndefined(videoConfig) || this.isUndefined(videoConfig.video) || this.isUndefined(videoConfig.videoUploadOnPasses) || this.isUndefined(bsConfig)) return;
let user_cypress_version = (bsConfig && bsConfig.run_settings && bsConfig.run_settings.cypress_version) ? bsConfig.run_settings.cypress_version.toString() : undefined;
let cypress_major_version = (user_cypress_version && user_cypress_version.match(/^(\d+)/)) ? user_cypress_version.split(".")[0] : undefined;
let config_args = (bsConfig && bsConfig.run_settings && bsConfig.run_settings.config) ? bsConfig.run_settings.config : undefined;
if(this.isUndefined(user_cypress_version) || this.isUndefined(cypress_major_version) || parseInt(cypress_major_version) >= 13 ) {
let video_args = `video=${videoConfig.video},videoUploadOnPasses=${videoConfig.videoUploadOnPasses}`;
config_args = this.isUndefined(config_args) ? video_args : config_args + ',' + video_args;
logger.debug(`Setting default video true for cypress 13 and above in cli for cypress version ${user_cypress_version} with cli args - ${config_args}`)
}
if (bsConfig.run_settings && this.isNotUndefined(config_args)) bsConfig["run_settings"]["config"] = config_args;
}

// set configs if enforce_settings is passed
exports.setEnforceSettingsConfig = (bsConfig) => {
if ( this.isUndefined(bsConfig) || this.isUndefined(bsConfig.run_settings) ) return;
let config_args = (bsConfig && bsConfig.run_settings && bsConfig.run_settings.config) ? bsConfig.run_settings.config : undefined;
if ( this.isUndefined(config_args) || !config_args.includes("video") ) {
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' ;
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';
config_args = this.isUndefined(config_args) ? video_args : config_args + ',' + video_args;
logger.debug(`Setting video_args for enforce_settings to ${video_args}`);
}
if ( (bsConfig && bsConfig.run_settings && bsConfig.run_settings.baseUrl) && (this.isUndefined(config_args) || !config_args.includes("baseUrl")) ) {
let base_url_args = 'baseUrl='+bsConfig.run_settings.baseUrl;
config_args = this.isUndefined(config_args) ? base_url_args : config_args + ',' + base_url_args;
logger.debug(`Setting base_url_args for enforce_settings to ${base_url_args}`);
}
// set specs in config of specpattern to override cypress config
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")) ) {
// doing this only for cypress 10 and above as --spec is given precedence for cypress 9.
let specConfigs = bsConfig.run_settings.specs;
// if multiple specs are passed, convert it into an array.
if(specConfigs && specConfigs.includes(',')) {
specConfigs = JSON.stringify(specConfigs.split(','));
}
let spec_pattern_args = 'specPattern="'+specConfigs+'"';
config_args = this.isUndefined(config_args) ? spec_pattern_args : config_args + ',' + spec_pattern_args;
}
if ( this.isNotUndefined(config_args) ) bsConfig["run_settings"]["config"] = config_args;
logger.debug(`Setting conifg_args for enforce_settings to ${config_args}`);
}

// blindly send other passed configs with run_settings and handle at backend
exports.setOtherConfigs = (bsConfig, args) => {
if(isTestObservabilitySession() && process.env.BS_TESTOPS_JWT) {
if(o11yHelpers.isTestObservabilitySession() && process.env.BS_TESTOPS_JWT) {
bsConfig["run_settings"]["reporter"] = TEST_OBSERVABILITY_REPORTER;
return;
}
Expand Down Expand Up @@ -1453,14 +1501,37 @@ exports.setProcessHooks = (buildId, bsConfig, bsLocal, args, buildReportData) =>
process.on('uncaughtException', processExitHandler.bind(this, bindData));
}

exports.setO11yProcessHooks = (() => {
let bindData = {};
let handlerAdded = false;
return (buildId, bsConfig, bsLocal, args, buildReportData) => {
bindData.buildId = buildId;
bindData.bsConfig = bsConfig;
bindData.bsLocal = bsLocal;
bindData.args = args;
bindData.buildReportData = buildReportData;
if (handlerAdded) return;
handlerAdded = true;
process.on('beforeExit', processO11yExitHandler.bind(this, bindData));
}
})()

async function processExitHandler(exitData){
logger.warn(Constants.userMessages.PROCESS_KILL_MESSAGE);
await this.stopBrowserStackBuild(exitData.bsConfig, exitData.args, exitData.buildId, null, exitData.buildReportData);
await this.stopLocalBinary(exitData.bsConfig, exitData.bsLocalInstance, exitData.args, null, exitData.buildReportData);
await printBuildLink(true);
await o11yHelpers.printBuildLink(true);
process.exit(0);
}

async function processO11yExitHandler(exitData){
if (exitData.buildId) {
await o11yHelpers.printBuildLink(false);
} else {
await o11yHelpers.printBuildLink(true);
}
}

exports.fetchZipSize = (fileName) => {
try {
let stats = fs.statSync(fileName)
Expand Down Expand Up @@ -1499,14 +1570,23 @@ exports.fetchFolderSize = async (dir) => {
}
}

exports.getVideoConfig = (cypressConfig) => {
exports.getVideoConfig = (cypressConfig, bsConfig = {}) => {
let conf = {
video: true,
videoUploadOnPasses: true
}
if (!this.isUndefined(cypressConfig.video)) conf.video = cypressConfig.video;
if (!this.isUndefined(cypressConfig.videoUploadOnPasses)) conf.videoUploadOnPasses = cypressConfig.videoUploadOnPasses;
// Reading bsconfig in case of enforce_settings
if ( this.isUndefined(bsConfig.run_settings) || this.isUndefinedOrFalse(bsConfig.run_settings.enforce_settings) ) {
if (!this.isUndefined(cypressConfig.video)) conf.video = cypressConfig.video;
if (!this.isUndefined(cypressConfig.videoUploadOnPasses)) conf.videoUploadOnPasses = cypressConfig.videoUploadOnPasses;
}
else {
if (!this.isUndefined(bsConfig.run_settings) && !this.isUndefined(bsConfig.run_settings.video)) conf.video = bsConfig.run_settings.video;
if (!this.isUndefined(bsConfig.run_settings) && !this.isUndefined(bsConfig.run_settings.videoUploadOnPasses)) conf.videoUploadOnPasses = bsConfig.run_settings.videoUploadOnPasses;
}

// set video in cli config in case of cypress 13 or above as default value is false there.
this.setVideoCliConfig(bsConfig,conf);
logger.debug(`Setting video = ${conf.video}`);
logger.debug(`Setting videoUploadOnPasses = ${conf.videoUploadOnPasses}`);
return conf;
Expand Down
5 changes: 4 additions & 1 deletion bin/testObservability/helper/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,11 @@ const supportFileCleanup = () => {
});
}

exports.buildStopped = false;

exports.printBuildLink = async (shouldStopSession, exitCode = null) => {
if(!this.isTestObservabilitySession()) return;
if(!this.isTestObservabilitySession() || exports.buildStopped) return;
exports.buildStopped = true;
try {
if(shouldStopSession) {
supportFileCleanup();
Expand Down
Loading

0 comments on commit 0882343

Please sign in to comment.