Skip to content

Commit e8b4b68

Browse files
js config implementation
1 parent b089471 commit e8b4b68

File tree

9 files changed

+178
-52
lines changed

9 files changed

+178
-52
lines changed

bin/commands/runs.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,7 @@ module.exports = function run(args, rawArgs) {
9999
// set the no-wrap
100100
utils.setNoWrap(bsConfig, args);
101101

102-
// set record feature caps
103-
utils.setRecordCaps(bsConfig, args);
102+
await packageInstaller.packageSetupAndInstaller(bsConfig, config.packageDirName, {markBlockStart, markBlockEnd});
104103

105104
// set build tag caps
106105
utils.setBuildTags(bsConfig, args);
@@ -140,6 +139,9 @@ module.exports = function run(args, rawArgs) {
140139
// accept the number of parallels
141140
utils.setParallels(bsConfig, args, specFiles.length);
142141

142+
// set record feature caps
143+
utils.setRecordCaps(bsConfig, args, cypressConfigFile);
144+
143145
// warn if specFiles cross our limit
144146
utils.warnSpecLimit(bsConfig, args, specFiles, rawArgs, buildReportData);
145147
markBlockEnd('preArchiveSteps');

bin/helpers/capabilityHelper.js

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const fs = require('fs'),
22
path = require('path');
3+
const { readCypressConfigFile } = require('./readCypressConfigUtil');
34

45
const logger = require("./logger").winstonLogger,
56
Constants = require("./constants"),
@@ -194,34 +195,28 @@ const validate = (bsConfig, args) => {
194195
logger.debug(`Checking for cypress config file at ${cypressConfigFilePath}`);
195196
if (!fs.existsSync(cypressConfigFilePath) && bsConfig.run_settings.cypress_config_filename !== 'false') reject(Constants.validationMessages.INVALID_CYPRESS_CONFIG_FILE);
196197

197-
if (bsConfig.run_settings.cypressTestSuiteType === Constants.CYPRESS_V10_AND_ABOVE_TYPE) {
198-
logger.debug(`Validating ${bsConfig.run_settings.cypress_config_filename}`);
199-
// TODO: add validations for cypress_config_filename
200-
} else {
201-
logger.debug("Validating cypress.json");
202-
try {
203-
if (bsConfig.run_settings.cypress_config_filename !== 'false') {
204-
205-
if (bsConfig.run_settings.cypressTestSuiteType === Constants.CYPRESS_V10_AND_ABOVE_TYPE) {
206-
if (cypressConfigFilePath.endsWith("cypress.config.js")) {
207-
cypressConfigFile = require(cypressConfigFilePath);
208-
} else {
209-
cypressConfigFile = {};
210-
}
211-
} else {
212-
let cypressJsonContent = fs.readFileSync(cypressConfigFilePath);
213-
cypressConfigFile = JSON.parse(cypressJsonContent);
214-
}
215-
216-
// Cypress Json Base Url & Local true check
217-
if (!Utils.isUndefined(cypressConfigFile.baseUrl) && cypressConfigFile.baseUrl.includes("localhost") && !Utils.getLocalFlag(bsConfig.connection_settings)) reject(Constants.validationMessages.LOCAL_NOT_SET.replace("<baseUrlValue>", cypressConfigFile.baseUrl));
218-
219-
// Detect if the user is not using the right directory structure, and throw an error
220-
if (!Utils.isUndefined(cypressConfigFile.integrationFolder) && !Utils.isCypressProjDirValid(bsConfig.run_settings.cypressProjectDir,cypressConfigFile.integrationFolder)) reject(Constants.validationMessages.INCORRECT_DIRECTORY_STRUCTURE);
198+
logger.debug(`Validating ${bsConfig.run_settings.cypress_config_filename}`);
199+
try {
200+
if (bsConfig.run_settings.cypressTestSuiteType === Constants.CYPRESS_V10_AND_ABOVE_TYPE) {
201+
const completeCypressConfigFile = readCypressConfigFile(bsConfig)
202+
if (!Utils.isUndefined(completeCypressConfigFile)) {
203+
// check if cypress config was exported using export default
204+
cypressConfigFile = !Utils.isUndefined(completeCypressConfigFile.default) ? completeCypressConfigFile.default : completeCypressConfigFile
221205
}
222-
} catch(error){
223-
reject(Constants.validationMessages.INVALID_CYPRESS_JSON)
206+
207+
// TODO: add validations for cypress_config_filename
208+
} else {
209+
let cypressJsonContent = fs.readFileSync(cypressConfigFilePath);
210+
cypressConfigFile = JSON.parse(cypressJsonContent);
224211
}
212+
213+
// Cypress Json Base Url & Local true check
214+
if (!Utils.isUndefined(cypressConfigFile.baseUrl) && cypressConfigFile.baseUrl.includes("localhost") && !Utils.getLocalFlag(bsConfig.connection_settings)) reject(Constants.validationMessages.LOCAL_NOT_SET.replace("<baseUrlValue>", cypressConfigFile.baseUrl));
215+
216+
// Detect if the user is not using the right directory structure, and throw an error
217+
if (!Utils.isUndefined(cypressConfigFile.integrationFolder) && !Utils.isCypressProjDirValid(bsConfig.run_settings.cypressProjectDir,cypressConfigFile.integrationFolder)) reject(Constants.validationMessages.INCORRECT_DIRECTORY_STRUCTURE);
218+
} catch(error){
219+
reject(Constants.validationMessages.INVALID_CYPRESS_JSON)
225220
}
226221

227222
//check if home_directory is present or not in user run_settings

bin/helpers/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ config.packageFileName = "bstackPackages.tar.gz";
2424
config.packageDirName = "tmpBstackPackages";
2525
config.retries = 5;
2626
config.networkErrorExitCode = 2;
27+
config.configJsonFileName = 'tmpCypressConfig.json'
2728

2829
module.exports = config;

bin/helpers/constants.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@ const userMessages = {
4343
"There was some issue while checking if zip is already uploaded.",
4444
ZIP_DELETE_FAILED: "Could not delete tests.zip successfully.",
4545
ZIP_DELETED: "Deleted tests.zip successfully.",
46-
NPM_INSTALL_AND_UPLOAD:
47-
"Installing required dependencies and building the package to upload to BrowserStack",
46+
NPM_INSTALL:
47+
"Installing required dependencies",
48+
NPM_UPLOAD:
49+
"Building the package to upload to BrowserStack",
4850
NPM_DELETE_FAILED: "Could not delete the dependency packages.",
4951
NPM_DELETED: "Deleted dependency packages successfully.",
5052
API_DEPRECATED:
@@ -420,6 +422,8 @@ const CYPRESS_CONFIG_FILE_MAPPING = {
420422

421423
const CYPRESS_CONFIG_FILE_NAMES = Object.keys(CYPRESS_CONFIG_FILE_MAPPING);
422424

425+
const CYPRESS_V10_AND_ABOVE_CONFIG_FILE_EXTENSIONS = ['js', 'ts', 'cjs', 'mjs']
426+
423427
module.exports = Object.freeze({
424428
syncCLI,
425429
userMessages,
@@ -450,5 +454,6 @@ module.exports = Object.freeze({
450454
CYPRESS_V9_AND_OLDER_TYPE,
451455
CYPRESS_V10_AND_ABOVE_TYPE,
452456
CYPRESS_CONFIG_FILE_MAPPING,
453-
CYPRESS_CONFIG_FILE_NAMES
457+
CYPRESS_CONFIG_FILE_NAMES,
458+
CYPRESS_V10_AND_ABOVE_CONFIG_FILE_EXTENSIONS
454459
});

bin/helpers/packageInstaller.js

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -128,16 +128,13 @@ const packageArchiver = (packageDir, packageFile) => {
128128
})
129129
}
130130

131-
const packageWrapper = (bsConfig, packageDir, packageFile, md5data, instrumentBlocks) => {
131+
const packageSetupAndInstaller = (bsConfig, packageDir, instrumentBlocks) => {
132132
return new Promise(function (resolve) {
133133
let obj = {
134-
packageArchieveCreated: false
134+
packagesInstalled: false
135135
};
136-
if (md5data.packageUrlPresent || !utils.isTrueString(bsConfig.run_settings.cache_dependencies)) {
137-
logger.debug("Skipping the caching of npm packages since BrowserStack has already cached your npm dependencies that have not changed since the last run.")
138-
return resolve(obj);
139-
}
140-
logger.info(Constants.userMessages.NPM_INSTALL_AND_UPLOAD);
136+
137+
logger.info(Constants.userMessages.NPM_INSTALL);
141138
instrumentBlocks.markBlockStart("packageInstaller.folderSetup");
142139
logger.debug("Started setting up package folder");
143140
return setupPackageFolder(bsConfig.run_settings, packageDir).then((_result) => {
@@ -150,10 +147,30 @@ const packageWrapper = (bsConfig, packageDir, packageFile, md5data, instrumentBl
150147
}).then((_result) => {
151148
logger.debug("Completed installing dependencies");
152149
instrumentBlocks.markBlockEnd("packageInstaller.packageInstall");
153-
instrumentBlocks.markBlockStart("packageInstaller.packageArchive");
154-
logger.debug("Started archiving node_modules")
155-
return packageArchiver(packageDir, packageFile);
156-
}).then((_result) => {
150+
Object.assign(obj, { packagesInstalled: true });
151+
return resolve(obj);
152+
}).catch((err) => {
153+
logger.warn(`Error occured while installing npm dependencies. Dependencies will be installed in runtime. This will have a negative impact on performance. Reach out to browserstack.com/contact, if you persistantly face this issue.`);
154+
obj.error = err.stack ? err.stack.toString().substring(0,100) : err.toString().substring(0,100);
155+
return resolve(obj);
156+
})
157+
})
158+
}
159+
160+
const packageWrapper = (bsConfig, packageDir, packageFile, md5data, instrumentBlocks) => {
161+
return new Promise(function (resolve) {
162+
let obj = {
163+
packageArchieveCreated: false
164+
};
165+
if (md5data.packageUrlPresent || !utils.isTrueString(bsConfig.run_settings.cache_dependencies)) {
166+
logger.debug("Skipping the caching of npm packages since BrowserStack has already cached your npm dependencies that have not changed since the last run.")
167+
return resolve(obj);
168+
}
169+
logger.info(Constants.userMessages.NPM_UPLOAD);
170+
instrumentBlocks.markBlockStart("packageInstaller.packageArchive");
171+
logger.debug("Started archiving node_modules")
172+
return packageArchiver(packageDir, packageFile)
173+
.then((_result) => {
157174
logger.debug("Archiving of node_modules completed");
158175
instrumentBlocks.markBlockEnd("packageInstaller.packageArchive");
159176
Object.assign(obj, { packageArchieveCreated: true });
@@ -167,3 +184,4 @@ const packageWrapper = (bsConfig, packageDir, packageFile, md5data, instrumentBl
167184
}
168185

169186
exports.packageWrapper = packageWrapper;
187+
exports.packageSetupAndInstaller = packageSetupAndInstaller;

bin/helpers/readCypressConfigUtil.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"use strict";
2+
const path = require("path");
3+
const fs = require("fs");
4+
const { execSync } = require('child_process');
5+
6+
const config = require('./config');
7+
const constants = require("./constants");
8+
const logger = require('./logger').winstonLogger;
9+
10+
const detectLanguage = (cypress_config_filename) => {
11+
const extension = cypress_config_filename.split('.').pop()
12+
return constants.CYPRESS_V10_AND_ABOVE_CONFIG_FILE_EXTENSIONS.includes(extension) ? extension : 'js'
13+
}
14+
15+
exports.readCypressConfigFile = (bsConfig) => {
16+
try {
17+
const cypress_config_filepath = path.resolve(bsConfig.run_settings.cypressConfigFilePath)
18+
const cypress_config_filename = bsConfig.run_settings.cypress_config_filename
19+
const bstack_node_modules_path = `${path.resolve(config.packageDirName)}/node_modules`
20+
const conf_lang = detectLanguage(cypress_config_filename)
21+
const require_module_helper_path = `${__dirname}/requireModule.js`
22+
23+
logger.debug(`cypress config path: ${cypress_config_filepath}`);
24+
25+
if (conf_lang == 'js' || conf_lang == 'cjs') {
26+
execSync(`NODE_PATH=${bstack_node_modules_path} node ${require_module_helper_path} ${cypress_config_filepath}`)
27+
const cypress_config = JSON.parse(fs.readFileSync(config.configJsonFileName).toString())
28+
if (fs.existsSync(config.configJsonFileName)) {
29+
fs.unlinkSync(config.configJsonFileName)
30+
}
31+
return cypress_config
32+
}
33+
} catch (error) {
34+
logger.error(`Error while reading cypress config: ${error.message}`)
35+
// TODO: Add instrumention if error occurred
36+
}
37+
}

bin/helpers/requireModule.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// NOTE: DO NOT change the name or location of file, the execution of this file is invoked using fixed path
2+
// helper file to load and read js modules
3+
const fs = require('fs');
4+
const config = require('./config');
5+
const moduleName = process.argv[2];
6+
7+
const mod = require(moduleName)
8+
9+
if (fs.existsSync(config.configJsonFileName)) {
10+
fs.unlinkSync(config.configJsonFileName)
11+
}
12+
13+
// write module in temporary json file
14+
fs.writeFileSync(config.configJsonFileName, JSON.stringify(mod))

bin/helpers/utils.js

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -405,25 +405,24 @@ exports.setRecordKeyFlag = (bsConfig, args) => {
405405
return bsConfig.run_settings["record-key"];
406406
}
407407

408-
exports.setProjectId = (bsConfig, args) => {
408+
exports.setProjectId = (bsConfig, args, cypressConfigFile) => {
409409
if(!this.isUndefined(args["projectId"])) {
410410
return args["projectId"];
411411
} else if(!this.isUndefined(process.env.CYPRESS_PROJECT_ID)) {
412412
return process.env.CYPRESS_PROJECT_ID;
413413
} else if(!this.isUndefined(bsConfig.run_settings["projectId"])) {
414414
return bsConfig.run_settings["projectId"];
415415
} else {
416-
let cypressConfigFile = this.getCypressConfigFile(bsConfig);
417416
if (!this.isUndefined(cypressConfigFile) && !this.isUndefined(cypressConfigFile["projectId"])) {
418417
return cypressConfigFile["projectId"];
419418
}
420419
}
421420
}
422421

423-
exports.setRecordCaps = (bsConfig, args) => {
422+
exports.setRecordCaps = (bsConfig, args, cypressConfigFile) => {
424423
bsConfig.run_settings["record"] = this.setRecordFlag(bsConfig, args);
425424
bsConfig.run_settings["record-key"] = this.setRecordKeyFlag(bsConfig, args);
426-
bsConfig.run_settings["projectId"] = this.setProjectId(bsConfig, args);
425+
bsConfig.run_settings["projectId"] = this.setProjectId(bsConfig, args, cypressConfigFile);
427426
}
428427

429428
exports.verifyNodeVersionOption = () => {
@@ -987,15 +986,69 @@ exports.getFilesToIgnore = (runSettings, excludeFiles, logging = true) => {
987986
}
988987

989988
exports.getNumberOfSpecFiles = (bsConfig, args, cypressConfig) => {
990-
let defaultSpecFolder = Constants.DEFAULT_CYPRESS_SPEC_PATH;
989+
let defaultSpecFolder
990+
let testFolderPath
991+
let globCypressConfigSpecPatterns = []
992+
let globSearchPattern = this.sanitizeSpecsPattern(bsConfig.run_settings.specs);
993+
991994
if (bsConfig.run_settings.cypressTestSuiteType === Constants.CYPRESS_V10_AND_ABOVE_TYPE) {
992-
defaultSpecFolder = Constants.DEFAULT_CYPRESS_10_SPEC_PATH;
995+
defaultSpecFolder = Constants.DEFAULT_CYPRESS_10_SPEC_PATH
996+
testFolderPath = defaultSpecFolder
997+
if(!this.isUndefined(cypressConfig) && !this.isUndefined(cypressConfig.e2e)) {
998+
if(!this.isUndefined(cypressConfig.e2e.specPattern)) {
999+
globCypressConfigSpecPatterns = Array.isArray(cypressConfig.e2e.specPattern) ?
1000+
cypressConfig.e2e.specPattern : [cypressConfig.e2e.specPattern];
1001+
} else {
1002+
console.log('herer', [`${testFolderPath}/**/*.+(${Constants.specFileTypes.join("|")})`])
1003+
globCypressConfigSpecPatterns = [`${testFolderPath}/**/*.+(${Constants.specFileTypes.join("|")})`]
1004+
}
1005+
} else {
1006+
// if not able read cypress config, use bstack specs arg(existing logic, which is not correct)
1007+
globCypressConfigSpecPatterns = globSearchPattern ? [globSearchPattern] : [`${testFolderPath}/**/*.+(${Constants.specFileTypes.join("|")})`]
1008+
}
1009+
} else {
1010+
defaultSpecFolder = Constants.DEFAULT_CYPRESS_SPEC_PATH
1011+
// console.log('cypressConfig.integrationFolder', cypressConfig.integrationFolder)
1012+
let testFolderPath = cypressConfig.integrationFolder && cypressConfig.integrationFolder !== '.' ?
1013+
cypressConfig.integrationFolder : defaultSpecFolder;
1014+
if(!this.isUndefined(cypressConfig.testFiles)) {
1015+
if (Array.isArray(cypressConfig.testFiles)) {
1016+
cypressConfig.testFiles.forEach(specPattern => {
1017+
globCypressConfigSpecPatterns.push(`${testFolderPath}/${specPattern}`)
1018+
});
1019+
} else {
1020+
globCypressConfigSpecPatterns = [`${testFolderPath}/${specPattern}`]
1021+
}
1022+
} else {
1023+
globCypressConfigSpecPatterns = [`${testFolderPath}/**/*.+(${Constants.specFileTypes.join("|")})`]
1024+
}
9931025
}
994-
let testFolderPath = cypressConfig.integrationFolder || defaultSpecFolder;
995-
let globSearchPattern = this.sanitizeSpecsPattern(bsConfig.run_settings.specs) || `${testFolderPath}/**/*.+(${Constants.specFileTypes.join("|")})`;
1026+
9961027
let ignoreFiles = args.exclude || bsConfig.run_settings.exclude;
997-
let files = glob.sync(globSearchPattern, {cwd: bsConfig.run_settings.cypressProjectDir, matchBase: true, ignore: ignoreFiles});
998-
logger.debug(`${files ? files.length : 0} spec files found at ${testFolderPath}`);
1028+
// TODO: remove console logs
1029+
let fileMatchedWithConfigSpecPattern = [];
1030+
globCypressConfigSpecPatterns.forEach(specPattern => {
1031+
fileMatchedWithConfigSpecPattern.push(
1032+
...glob.sync(specPattern, {
1033+
cwd: bsConfig.run_settings.cypressProjectDir, matchBase: true, ignore: ignoreFiles
1034+
})
1035+
);
1036+
});
1037+
1038+
console.log('configSpecPattern', fileMatchedWithConfigSpecPattern)
1039+
let files
1040+
1041+
if (globSearchPattern) {
1042+
let fileMatchedWithBstackSpecPattern = glob.sync(globSearchPattern, {
1043+
cwd: bsConfig.run_settings.cypressProjectDir, matchBase: true, ignore: ignoreFiles
1044+
});
1045+
console.log('specArg', fileMatchedWithBstackSpecPattern);
1046+
files = fileMatchedWithBstackSpecPattern.filter(file => fileMatchedWithConfigSpecPattern.includes(file))
1047+
} else {
1048+
files = fileMatchedWithConfigSpecPattern;
1049+
}
1050+
console.log('files', files)
1051+
logger.debug(`${files ? files.length : 0} spec files found`);
9991052
return files;
10001053
};
10011054

bin/helpers/zipUpload.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const uploadSuits = (bsConfig, filePath, opts, obj) => {
2828
obj.startTime = Date.now();
2929

3030
if (opts.urlPresent) {
31+
opts.cleanupMethod();
3132
return resolve({ [opts.md5ReturnKey]: opts.url });
3233
}
3334
if (!opts.archivePresent) {

0 commit comments

Comments
 (0)