Skip to content
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

update sanitizeSpecsPattern logic #788

Merged
merged 5 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion bin/commands/runs.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ module.exports = function run(args, rawArgs) {
if ( !utils.isUndefinedOrFalse(bsConfig.run_settings.enforce_settings) ) {
markBlockStart('setEnforceSettingsConfig');
logger.debug('Started setting the configs');
utils.setEnforceSettingsConfig(bsConfig);
utils.setEnforceSettingsConfig(bsConfig, args);
logger.debug('Completed setting the configs');
markBlockEnd('setEnforceSettingsConfig');
}
Expand Down
71 changes: 66 additions & 5 deletions bin/helpers/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -1163,7 +1163,7 @@ exports.getNumberOfSpecFiles = (bsConfig, args, cypressConfig, turboScaleSession
};

exports.sanitizeSpecsPattern = (pattern) => {
return pattern && pattern.split(",").length > 1 ? "{" + pattern + "}" : pattern;
return pattern && !(pattern.includes("{") && pattern.includes("}")) && pattern.split(",").length > 1 ? "{" + pattern + "}" : pattern;
}

exports.generateUniqueHash = () => {
Expand Down Expand Up @@ -1319,7 +1319,7 @@ exports.setVideoCliConfig = (bsConfig, videoConfig) => {
}

// set configs if enforce_settings is passed
exports.setEnforceSettingsConfig = (bsConfig) => {
exports.setEnforceSettingsConfig = (bsConfig, args) => {
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") ) {
Expand All @@ -1338,16 +1338,77 @@ exports.setEnforceSettingsConfig = (bsConfig) => {
// 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(','));
if (specConfigs && !Array.isArray(specConfigs)) {
if (specConfigs.includes(',')) {
specConfigs = this.splitStringByCharButIgnoreIfWithinARange(specConfigs, ',', '{', '}');
} else {
specConfigs = [specConfigs];
}
}
let spec_pattern_args = `specPattern=${specConfigs}`;
let ignoreFiles = args.exclude || bsConfig.run_settings.exclude
let specFilesMatched = [];
specConfigs.forEach(specPattern => {
specFilesMatched.push(
...glob.sync(specPattern, {
cwd: bsConfig.run_settings.cypressProjectDir, matchBase: true, ignore: ignoreFiles
})
);
});
logger.debug(`${specFilesMatched && specFilesMatched.length > 0 ? specFilesMatched.length : 0} spec files found with the provided specPattern for enforce_settings`);
// If spec files were found then lets we'll load the matched spec files
// If spec files were not found then we'll let cypress decide the loading of spec files
let spec_pattern_args = `specPattern=${JSON.stringify(specFilesMatched && specFilesMatched.length > 0 ? specFilesMatched : 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}`);
}

/**
* Splits a string by a specified splitChar.
* If leftLimiter and rightLimiter are specified then string won't be splitted if the splitChar is within the range
*
* @param {String} str - the string that needs to be splitted
* @param {String} splitChar - the split string/char from which the string will be splited
* @param {String} [leftLimiter] - the starting string/char of the range
* @param {String} [rightLimiter] - the ending string/char of the range
*
* @example Example usage of splitStringByCharButIgnoreIfWithinARange.
* // returns ["folder/A/B", "folder/{C,D}/E"]
* utils.splitStringByCharButIgnoreIfWithinARange("folder/A/B,folder/{C,D}/E", ",", "{", "}");
* @returns String[] | null
*/
exports.splitStringByCharButIgnoreIfWithinARange = (str, splitChar, leftLimiter, rightLimiter) => {
if (typeof(str) !== 'string' || this.isUndefined(splitChar)) return null;

if (this.isUndefined(leftLimiter) || this.isUndefined(rightLimiter)) return str.split(splitChar);

let result = [];
let buffer = '';
let openBraceCount = 0;

for (let i = 0; i < str.length; i++) {
if (str[i] === leftLimiter) {
openBraceCount++;
} else if (str[i] === rightLimiter) {
openBraceCount--;
}

if (str[i] === splitChar && openBraceCount === 0) {
result.push(buffer);
buffer = '';
} else {
buffer += str[i];
}
}

if (buffer !== '') {
result.push(buffer);
}

return result;
}

// blindly send other passed configs with run_settings and handle at backend
exports.setOtherConfigs = (bsConfig, args) => {
if(o11yHelpers.isTestObservabilitySession() && process.env.BS_TESTOPS_JWT) {
Expand Down
105 changes: 93 additions & 12 deletions test/unit/bin/helpers/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2721,6 +2721,10 @@ describe('utils', () => {
expect(utils.sanitizeSpecsPattern('pattern3')).to.eq('pattern3');
});

it('should not wrap pattern around {} when input already has {}', () => {
expect(utils.sanitizeSpecsPattern('pattern/{folderA,folderB}/*.spec.ts')).to.eq('pattern/{folderA,folderB}/*.spec.ts');
});

it('should return undefined when --spec is undefined', () => {
expect(utils.sanitizeSpecsPattern(undefined)).to.eq(undefined);
});
Expand Down Expand Up @@ -3094,56 +3098,133 @@ describe('utils', () => {
describe('setEnforceSettingsConfig', () => {
it('the video config should be assigned to bsconfig run_settings config', () => {
let bsConfig = {
run_settings: { video_config: { video:true, videoUploadOnPasses:true} },
run_settings: {
video_config: { video:true, videoUploadOnPasses:true },
cypressProjectDir: 'cypressProjectDir',
},
};
let args = {
config: 'video=true,videoUploadOnPasses=true'
}
utils.setEnforceSettingsConfig(bsConfig);
utils.setEnforceSettingsConfig(bsConfig, args);
expect(args.config).to.be.eql(bsConfig.run_settings.config);
});
it('the specPattern config should be assigned as strings for single string to bsconfig run_settings config', () => {
it('the specPattern config should be assigned as array for single spec string to bsconfig run_settings config', () => {
let bsConfig = {
run_settings: { specs: 'somerandomspecs', cypressTestSuiteType: 'CYPRESS_V10_AND_ABOVE_TYPE' },
run_settings: {
specs: 'somerandomspecs',
cypressTestSuiteType: 'CYPRESS_V10_AND_ABOVE_TYPE',
cypressProjectDir: 'cypressProjectDir',
},
};
let args = {
config: 'video=false,videoUploadOnPasses=false,specPattern=somerandomspecs'
exclude: "",
config: 'video=false,videoUploadOnPasses=false,specPattern=["somerandomspecs"]'
}
utils.setEnforceSettingsConfig(bsConfig);
utils.setEnforceSettingsConfig(bsConfig, args);
expect(args.config).to.be.eql(bsConfig.run_settings.config);
});
it('the specPattern config should be assigned as array for multiple spec strings to bsconfig run_settings config', () => {
let bsConfig = {
run_settings: { specs: 'somerandomspecs1,somerandomspecs2', cypressTestSuiteType: 'CYPRESS_V10_AND_ABOVE_TYPE' },
run_settings: {
specs: 'somerandomspecs1,somerandomspecs2',
cypressTestSuiteType: 'CYPRESS_V10_AND_ABOVE_TYPE',
cypressProjectDir: 'cypressProjectDir',
},
};
let args = {
exclude: "",
config: 'video=false,videoUploadOnPasses=false,specPattern=["somerandomspecs1","somerandomspecs2"]'
}
utils.setEnforceSettingsConfig(bsConfig);
utils.setEnforceSettingsConfig(bsConfig, args);
expect(args.config).to.be.eql(bsConfig.run_settings.config);
});
it('the specPattern config should not be assigned just on the basis of "," as array for single spec string to bsconfig run_settings config', () => {
let bsConfig = {
run_settings: {
specs: 'folders/{sample1,sample2}/somerandomspecs',
cypressTestSuiteType: 'CYPRESS_V10_AND_ABOVE_TYPE',
cypressProjectDir: 'cypressProjectDir',
},
};
let args = {
exclude: "",
config: 'video=false,videoUploadOnPasses=false,specPattern=["folders/{sample1,sample2}/somerandomspecs"]'
}
utils.setEnforceSettingsConfig(bsConfig, args);
expect(args.config).to.be.eql(bsConfig.run_settings.config);
});
it('the specPattern config should not be assigned just on the basis of "," as array for multiple spec strings to bsconfig run_settings config', () => {
let bsConfig = {
run_settings: {
specs: 'folders/{sample1,sample2}/somerandomspecs,folders2/sample3/somerandomspecs2',
cypressTestSuiteType: 'CYPRESS_V10_AND_ABOVE_TYPE',
cypressProjectDir: 'cypressProjectDir',
},
};
let args = {
exclude: "",
config: 'video=false,videoUploadOnPasses=false,specPattern=["folders/{sample1,sample2}/somerandomspecs","folders2/sample3/somerandomspecs2"]'
}
utils.setEnforceSettingsConfig(bsConfig, args);
expect(args.config).to.be.eql(bsConfig.run_settings.config);
});
it('the testFiles config should be assigned to bsconfig run_settings config', () => {
let bsConfig = {
run_settings: { specs: 'somerandomspecs', cypressTestSuiteType: 'CYPRESS_V9_AND_OLDER_TYPE' },
};
let args = {
config: 'video=false,videoUploadOnPasses=false'
config: 'video=false,videoUploadOnPasses=false',
cypressProjectDir: 'cypressProjectDir',
}
utils.setEnforceSettingsConfig(bsConfig);
utils.setEnforceSettingsConfig(bsConfig, args);
expect(args.config).to.be.eql(bsConfig.run_settings.config);
});
it('the baseUrl config should be assigned to bsconfig run_settings config', () => {
let bsConfig = {
run_settings: { baseUrl: 'http://localhost:8080' },
run_settings: {
baseUrl: 'http://localhost:8080',
cypressProjectDir: 'cypressProjectDir',
},
};
let args = {
config: 'video=false,videoUploadOnPasses=false,baseUrl=http://localhost:8080'
}
utils.setEnforceSettingsConfig(bsConfig);
utils.setEnforceSettingsConfig(bsConfig, args);
expect(args.config).to.be.eql(bsConfig.run_settings.config);
});
});

describe('splitStringByCharButIgnoreIfWithinARange', () => {
it('should return null if string is not provided', () => {
expect(utils.splitStringByCharButIgnoreIfWithinARange()).to.be.eql(null);
});

it('should return null if splitChar is not provided', () => {
expect(utils.splitStringByCharButIgnoreIfWithinARange("some")).to.be.eql(null);
});

it('should return splitted string even if leftLimiter and rightLimiter is not provided', () => {
expect(utils.splitStringByCharButIgnoreIfWithinARange("some,random,text", ",")).to.be.eql(["some", "random", "text"]);
});

it('should return splitted string even if leftLimiter is provided but rightLimiter is not provided', () => {
expect(utils.splitStringByCharButIgnoreIfWithinARange("some,random,{text,here},and,here", ",", "{")).to.be.eql(["some", "random", "{text", "here}", "and", "here"]);
});

it('should return splitted string even if leftLimiter is not provided but rightLimiter is provided', () => {
expect(utils.splitStringByCharButIgnoreIfWithinARange("some,random,{text,here},and,here", ",", null, "}")).to.be.eql(["some", "random", "{text", "here}", "and", "here"]);
});

it('should return splitted string and ignore splitting if splitChar is withing the leftLimiter and rightLimiter', () => {
expect(utils.splitStringByCharButIgnoreIfWithinARange("some,random,{text,here},and,here", ",", "{", "}")).to.be.eql(["some", "random", "{text,here}", "and", "here"]);
});

it('should return splitted string and ignore splitting if splitChar is withing the leftLimiter and rightLimiter', () => {
expect(utils.splitStringByCharButIgnoreIfWithinARange("some,random,{text,here}", ",", "{", "}")).to.be.eql(["some", "random", "{text,here}"]);
});
});

describe('generateUniqueHash', () => {
beforeEach(() => {
let interfaceList = {
Expand Down
Loading