Skip to content

Commit 81c3235

Browse files
authored
Merge pull request #54 from browserstack/cypress_config_file_support
Cypress config file support
2 parents 9661f75 + 3886bd5 commit 81c3235

File tree

13 files changed

+266
-22
lines changed

13 files changed

+266
-22
lines changed

bin/commands/runs.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ module.exports = function run(args) {
2626
// accept the build name from command line if provided
2727
utils.setBuildName(bsConfig, args);
2828

29+
// set cypress config filename
30+
utils.setCypressConfigFilename(bsConfig, args);
31+
2932
// accept the specs list from command line if provided
3033
utils.setUserSpecs(bsConfig, args);
3134

bin/helpers/archiver.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ const fs = require("fs");
44
const archiver = require("archiver"),
55
Constants = require('../helpers/constants'),
66
logger = require("./logger").winstonLogger,
7-
utils = require('../helpers/utils');
7+
utils = require('../helpers/utils'),
8+
path = require('path');
89

910
const archiveSpecs = (runSettings, filePath, excludeFiles) => {
1011
return new Promise(function (resolve, reject) {
1112
var output = fs.createWriteStream(filePath);
1213

13-
var cypressFolderPath = runSettings.cypress_proj_dir;
14+
var cypressFolderPath = path.dirname(runSettings.cypressConfigFilePath);
1415

1516
var archive = archiver('zip', {
1617
zlib: { level: 9 } // Sets the compression level.
@@ -59,6 +60,13 @@ const archiveSpecs = (runSettings, filePath, excludeFiles) => {
5960
archive.append(packageJSONString, { name: 'browserstack-package.json' });
6061
}
6162

63+
// do not add cypress.json if arg provided is false
64+
if (runSettings.cypress_config_file && runSettings.cypress_config_filename !== 'false') {
65+
let cypressJSON = JSON.parse(fs.readFileSync(runSettings.cypressConfigFilePath));
66+
let cypressJSONString = JSON.stringify(cypressJSON, null, 4);
67+
archive.append(cypressJSONString, { name: 'cypress.json' });
68+
}
69+
6270
archive.finalize();
6371
});
6472
}

bin/helpers/capabilityHelper.js

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ const caps = (bsConfig, zip) => {
6868
obj.projectNotifyURL = bsConfig.run_settings.project_notify_URL;
6969
obj.parallels = bsConfig.run_settings.parallels;
7070

71+
if (!Utils.isUndefined(bsConfig.run_settings.cypress_config_filename)) {
72+
obj.cypress_config_filename = bsConfig.run_settings.cypress_config_filename;
73+
}
74+
7175
if (!Utils.isUndefined(bsConfig.run_settings.specs)){
7276
obj.specs = bsConfig.run_settings.specs;
7377
}
@@ -78,7 +82,7 @@ const caps = (bsConfig, zip) => {
7882
}
7983

8084
if(obj.parallels === Constants.cliMessages.RUN.DEFAULT_PARALLEL_MESSAGE) obj.parallels = undefined
81-
85+
8286
if (obj.project) logger.log(`Project name is: ${obj.project}`);
8387

8488
if (obj.customBuildName) logger.log(`Build name is: ${obj.customBuildName}`);
@@ -106,26 +110,34 @@ const validate = (bsConfig, args) => {
106110

107111
if (!bsConfig.run_settings) reject(Constants.validationMessages.EMPTY_RUN_SETTINGS);
108112

109-
if (!bsConfig.run_settings.cypress_proj_dir) reject(Constants.validationMessages.EMPTY_CYPRESS_PROJ_DIR);
113+
if (!bsConfig.run_settings.cypress_proj_dir && !bsConfig.run_settings.userProvidedCypessConfigFile) {
114+
reject(Constants.validationMessages.EMPTY_CYPRESS_PROJ_DIR);
115+
}
110116

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

114120
// if parallels specified via arguments validate only arguments
115121
if (!Utils.isUndefined(args) && !Utils.isUndefined(args.parallels) && !Utils.isParallelValid(args.parallels)) reject(Constants.validationMessages.INVALID_PARALLELS_CONFIGURATION);
116122

117-
if (!fs.existsSync(path.join(bsConfig.run_settings.cypress_proj_dir, 'cypress.json'))) reject(Constants.validationMessages.CYPRESS_JSON_NOT_FOUND + bsConfig.run_settings.cypress_proj_dir);
123+
// validate if config file provided exists or not when cypress_config_file provided
124+
// validate the cypressProjectDir key otherwise.
125+
let cypressConfigFilePath = bsConfig.run_settings.cypressConfigFilePath;
126+
127+
if (!fs.existsSync(cypressConfigFilePath) && bsConfig.run_settings.cypress_config_filename !== 'false') reject(Constants.validationMessages.INVALID_CYPRESS_CONFIG_FILE);
118128

119129
try {
120-
let cypressJson = fs.readFileSync(path.join(bsConfig.run_settings.cypress_proj_dir, 'cypress.json'));
121-
cypressJson = JSON.parse(cypressJson);
122-
// Cypress Json Base Url & Local true check
123-
if (!Utils.isUndefined(cypressJson.baseUrl) && cypressJson.baseUrl.includes("localhost") && !Utils.getLocalFlag(bsConfig.connection_settings)) reject(Constants.validationMessages.LOCAL_NOT_SET);
124-
125-
// Detect if the user is not using the right directory structure, and throw an error
126-
if (!Utils.isUndefined(cypressJson.integrationFolder) && !Utils.isCypressProjDirValid(bsConfig.run_settings.cypress_proj_dir,cypressJson.integrationFolder)) reject(Constants.validationMessages.INCORRECT_DIRECTORY_STRUCTURE);
127-
128-
} catch (error) {
130+
if (bsConfig.run_settings.cypress_config_filename !== 'false') {
131+
let cypressJsonContent = fs.readFileSync(cypressConfigFilePath);
132+
cypressJson = JSON.parse(cypressJsonContent);
133+
134+
// Cypress Json Base Url & Local true check
135+
if (!Utils.isUndefined(cypressJson.baseUrl) && cypressJson.baseUrl.includes("localhost") && !Utils.getLocalFlag(bsConfig.connection_settings)) reject(Constants.validationMessages.LOCAL_NOT_SET);
136+
137+
// Detect if the user is not using the right directory structure, and throw an error
138+
if (!Utils.isUndefined(cypressJson.integrationFolder) && !Utils.isCypressProjDirValid(bsConfig.run_settings.cypressProjectDir,cypressJson.integrationFolder)) reject(Constants.validationMessages.INCORRECT_DIRECTORY_STRUCTURE);
139+
}
140+
} catch(error){
129141
reject(Constants.validationMessages.INVALID_CYPRESS_JSON)
130142
}
131143

bin/helpers/constants.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const validationMessages = {
3030
NOT_VALID_JSON: "browerstack.json is not a valid json",
3131
INVALID_EXTENSION: "Invalid files, please remove these files and try again.",
3232
INVALID_PARALLELS_CONFIGURATION: "Invalid value specified for parallels to use. Maximum parallels to use should be a number greater than 0.",
33+
INVALID_CYPRESS_CONFIG_FILE: "Invalid cypress_config_file",
3334
CYPRESS_JSON_NOT_FOUND: "cypress.json file is not found at cypress_proj_dir path ",
3435
INVALID_CYPRESS_JSON: "cypress.json is not a valid json",
3536
INVALID_DEFAULT_AUTH_PARAMS: "Your username and access key are required to run your tests on BrowserStack. Learn more at https://www.browserstack.com/docs/automate/cypress/authentication",
@@ -60,7 +61,9 @@ const cliMessages = {
6061
PARALLEL_DESC: "The maximum number of parallels to use to run your test suite",
6162
INFO: "Run your tests on BrowserStack.",
6263
DESC: "Path to BrowserStack config",
64+
CYPRESS_DESC: "Path to Cypress config file",
6365
CONFIG_DEMAND: "config file is required",
66+
CYPRESS_CONFIG_DEMAND: "Cypress config file is required",
6467
BUILD_NAME: "The build name you want to use to name your test runs",
6568
EXCLUDE: "Exclude files matching a pattern from zipping and uploading",
6669
DEFAULT_PARALLEL_MESSAGE: "Here goes the number of parallels you want to run",
@@ -86,7 +89,7 @@ const messageTypes = {
8689

8790
const allowedFileTypes = ['js', 'json', 'txt', 'ts', 'feature', 'features', 'pdf', 'jpg', 'jpeg', 'png', 'zip'];
8891

89-
const filesToIgnoreWhileUploading = ['node_modules/**', 'package-lock.json', 'package.json', 'browserstack-package.json', 'tests.zip']
92+
const filesToIgnoreWhileUploading = ['node_modules/**', 'package-lock.json', 'package.json', 'browserstack-package.json', 'tests.zip', 'cypress.json']
9093

9194
module.exports = Object.freeze({
9295
userMessages,

bin/helpers/usageReporting.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ function ci_environment() {
127127
}
128128
// CircleCI
129129
if (env.CI === "true" && env.CIRCLECI === "true") {
130-
return "CircleCI";
130+
return "CircleCI";
131131
}
132132
// Travis CI
133133
if (env.CI === "true" && env.TRAVIS === "true") {

bin/helpers/utils.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ exports.getErrorCodeFromMsg = (errMsg) => {
5555
case Constants.validationMessages.INCORRECT_DIRECTORY_STRUCTURE:
5656
errorCode = "invalid_directory_structure";
5757
break;
58+
case Constants.validationMessages.INVALID_CYPRESS_CONFIG_FILE:
59+
errorCode = "invalid_cypress_config_file";
60+
break;
5861
}
5962
if (
6063
errMsg.includes("Please use --config-file <path to browserstack.json>.")
@@ -140,6 +143,43 @@ exports.setBuildName = (bsConfig, args) => {
140143
}
141144
};
142145

146+
exports.searchForOption = (option) => {
147+
return (process.argv.indexOf(option) > -1);
148+
}
149+
150+
exports.verifyCypressConfigFileOption = () => {
151+
let ccfOptionsSet = (this.searchForOption('-ccf') || this.searchForOption('--ccf'));
152+
let cypressConfigFileSet = (this.searchForOption('-cypress-config-file') || this.searchForOption('--cypress-config-file'));
153+
let cypressConfigOptionsSet = (this.searchForOption('-cypressConfigFile') || this.searchForOption('--cypressConfigFile'));
154+
return (ccfOptionsSet || cypressConfigFileSet || cypressConfigOptionsSet);
155+
}
156+
157+
// TODO: Remove when cleaningup cypress_proj_dir
158+
//
159+
// 1. Remove demand from runner.js for --ccf option.
160+
// 2. Remove the strict check functions: verifyCypressConfigFileOption
161+
// 3. Just use the args.cypressConfigFile for checking the value for cypress config file.
162+
exports.setCypressConfigFilename = (bsConfig, args) => {
163+
let userProvidedCypessConfigFile = this.verifyCypressConfigFileOption();
164+
165+
bsConfig.run_settings.userProvidedCypessConfigFile = (userProvidedCypessConfigFile || (!this.isUndefined(bsConfig.run_settings.cypress_config_file)));
166+
167+
if (userProvidedCypessConfigFile || this.isUndefined(bsConfig.run_settings.cypress_config_file)) {
168+
bsConfig.run_settings.cypress_config_file = args.cypressConfigFile;
169+
bsConfig.run_settings.cypress_config_filename = path.basename(args.cypressConfigFile);
170+
} else if (!this.isUndefined(bsConfig.run_settings.cypress_config_file)) {
171+
bsConfig.run_settings.cypress_config_filename = path.basename(bsConfig.run_settings.cypress_config_file);
172+
}
173+
174+
if (bsConfig.run_settings.userProvidedCypessConfigFile){
175+
bsConfig.run_settings.cypressConfigFilePath = bsConfig.run_settings.cypress_config_file;
176+
bsConfig.run_settings.cypressProjectDir = path.dirname(bsConfig.run_settings.cypress_config_file);
177+
} else {
178+
bsConfig.run_settings.cypressConfigFilePath = path.join(bsConfig.run_settings.cypress_proj_dir, 'cypress.json');
179+
bsConfig.run_settings.cypressProjectDir = bsConfig.run_settings.cypress_proj_dir;
180+
}
181+
}
182+
143183
// specs can be passed from bstack configuration file
144184
// specs can be passed via command line args as a string
145185
// command line args takes precedence over config

bin/runner.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,15 @@ var argv = yargs
136136
demand: true,
137137
demand: Constants.cliMessages.RUN.CONFIG_DEMAND
138138
},
139+
'ccf': {
140+
alias: 'cypress-config-file',
141+
describe: Constants.cliMessages.RUN.CYPRESS_DESC,
142+
default: './cypress.json',
143+
type: 'string',
144+
nargs: 1,
145+
demand: true,
146+
demand: Constants.cliMessages.RUN.CYPRESS_CONFIG_DEMAND
147+
},
139148
'disable-usage-reporting': {
140149
default: undefined,
141150
description: Constants.cliMessages.COMMON.DISABLE_USAGE_REPORTING,

bin/templates/configTemplate.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ module.exports = function () {
5252
}
5353
],
5454
"run_settings": {
55-
"cypress_proj_dir" : "/path/to/directory-that-contains-<cypress.json>-file",
55+
"cypress_config_file" : "/path/to/<cypress config file>.json",
5656
"project_name": "project-name",
5757
"build_name": "build-name",
5858
"exclude": [],

test/unit/bin/commands/runs.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ describe("runs", () => {
8585
setUsernameStub = sandbox.stub();
8686
setAccessKeyStub = sandbox.stub();
8787
setBuildNameStub = sandbox.stub();
88+
setCypressConfigFilenameStub = sandbox.stub();
8889
setUserSpecsStub = sandbox.stub();
8990
setTestEnvsStub = sandbox.stub();
9091
getConfigPathStub = sandbox.stub();
@@ -118,6 +119,7 @@ describe("runs", () => {
118119
setUsername: setUsernameStub,
119120
setAccessKey: setAccessKeyStub,
120121
setBuildName: setBuildNameStub,
122+
setCypressConfigFilename: setCypressConfigFilenameStub,
121123
setUserSpecs: setUserSpecsStub,
122124
setTestEnvs: setTestEnvsStub,
123125
getConfigPath: getConfigPathStub,
@@ -169,6 +171,7 @@ describe("runs", () => {
169171
setAccessKeyStub = sandbox.stub();
170172
getConfigPathStub = sandbox.stub();
171173
setBuildNameStub = sandbox.stub();
174+
setCypressConfigFilenameStub = sandbox.stub();
172175
setUserSpecsStub = sandbox.stub();
173176
setTestEnvsStub = sandbox.stub();
174177
validateBstackJsonStub = sandbox.stub();
@@ -202,6 +205,7 @@ describe("runs", () => {
202205
setUsername: setUsernameStub,
203206
setAccessKey: setAccessKeyStub,
204207
setBuildName: setBuildNameStub,
208+
setCypressConfigFilename: setCypressConfigFilenameStub,
205209
setUserSpecs: setUserSpecsStub,
206210
setTestEnvs: setTestEnvsStub,
207211
setUsageReportingFlag: setUsageReportingFlagStub,
@@ -263,6 +267,7 @@ describe("runs", () => {
263267
setUsernameStub = sandbox.stub();
264268
setAccessKeyStub = sandbox.stub();
265269
setBuildNameStub = sandbox.stub();
270+
setCypressConfigFilenameStub = sandbox.stub();
266271
setUserSpecsStub = sandbox.stub();
267272
setTestEnvsStub = sandbox.stub();
268273
getConfigPathStub = sandbox.stub();
@@ -297,6 +302,7 @@ describe("runs", () => {
297302
setUsername: setUsernameStub,
298303
setAccessKey: setAccessKeyStub,
299304
setBuildName: setBuildNameStub,
305+
setCypressConfigFilename: setCypressConfigFilenameStub,
300306
setUserSpecs: setUserSpecsStub,
301307
setTestEnvs: setTestEnvsStub,
302308
setUsageReportingFlag: setUsageReportingFlagStub,
@@ -365,6 +371,7 @@ describe("runs", () => {
365371
setUsernameStub = sandbox.stub();
366372
setAccessKeyStub = sandbox.stub();
367373
setBuildNameStub = sandbox.stub();
374+
setCypressConfigFilenameStub = sandbox.stub();
368375
setUserSpecsStub = sandbox.stub();
369376
setTestEnvsStub = sandbox.stub();
370377
getConfigPathStub = sandbox.stub();
@@ -400,6 +407,7 @@ describe("runs", () => {
400407
setUsername: setUsernameStub,
401408
setAccessKey: setAccessKeyStub,
402409
setBuildName: setBuildNameStub,
410+
setCypressConfigFilename: setCypressConfigFilenameStub,
403411
setUserSpecs: setUserSpecsStub,
404412
setTestEnvs: setTestEnvsStub,
405413
setUsageReportingFlag: setUsageReportingFlagStub,
@@ -479,6 +487,7 @@ describe("runs", () => {
479487
setUsernameStub = sandbox.stub();
480488
setAccessKeyStub = sandbox.stub();
481489
setBuildNameStub = sandbox.stub();
490+
setCypressConfigFilenameStub = sandbox.stub();
482491
setUserSpecsStub = sandbox.stub();
483492
setTestEnvsStub = sandbox.stub();
484493
getConfigPathStub = sandbox.stub();
@@ -517,6 +526,7 @@ describe("runs", () => {
517526
setUsername: setUsernameStub,
518527
setAccessKey: setAccessKeyStub,
519528
setBuildName: setBuildNameStub,
529+
setCypressConfigFilename: setCypressConfigFilenameStub,
520530
setUserSpecs: setUserSpecsStub,
521531
setTestEnvs: setTestEnvsStub,
522532
setUsageReportingFlag: setUsageReportingFlagStub,

test/unit/bin/helpers/capabilityHelper.js

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,8 @@ describe("capabilityHelper.js", () => {
399399
},
400400
],
401401
run_settings: {
402-
cypress_proj_dir: "random path"
402+
cypress_proj_dir: "random path",
403+
cypressConfigFilePath: "random path"
403404
},
404405
};
405406
});
@@ -781,7 +782,9 @@ describe("capabilityHelper.js", () => {
781782
},
782783
],
783784
run_settings: {
784-
cypress_proj_dir: "random path"
785+
cypress_proj_dir: "random path",
786+
cypressConfigFilePath: "random path",
787+
cypressProjectDir: "random path"
785788
},
786789
};
787790
});
@@ -797,7 +800,7 @@ describe("capabilityHelper.js", () => {
797800
.catch((error) => {
798801
chai.assert.equal(
799802
error,
800-
Constants.validationMessages.CYPRESS_JSON_NOT_FOUND + "random path"
803+
Constants.validationMessages.INVALID_CYPRESS_CONFIG_FILE
801804
);
802805
fs.existsSync.restore();
803806
});
@@ -858,10 +861,42 @@ describe("capabilityHelper.js", () => {
858861
error,
859862
Constants.validationMessages.INCORRECT_DIRECTORY_STRUCTURE
860863
);
864+
861865
fs.existsSync.restore();
862866
fs.readFileSync.restore();
863867
});
864868
});
869+
870+
context("cypress config file set to false", () => {
871+
beforeEach(function() {
872+
readFileSpy = sinon.stub(fs, 'readFileSync');
873+
jsonParseSpy = sinon.stub(JSON, 'parse');
874+
});
875+
876+
afterEach(function() {
877+
readFileSpy.restore();
878+
jsonParseSpy.restore();
879+
});
880+
881+
it("does not validate with cypress config filename set to false", () => {
882+
// sinon.stub(fs, 'existsSync').returns(false);
883+
bsConfig.run_settings.cypressConfigFilePath = 'false';
884+
bsConfig.run_settings.cypress_config_filename = 'false';
885+
886+
return capabilityHelper
887+
.validate(bsConfig, {})
888+
.then(function (data) {
889+
sinon.assert.notCalled(readFileSpy);
890+
sinon.assert.notCalled(jsonParseSpy);
891+
})
892+
.catch((error) => {
893+
chai.assert.equal(
894+
error,
895+
Constants.validationMessages.INCORRECT_DIRECTORY_STRUCTURE
896+
);
897+
});
898+
})
899+
});
865900
});
866901
});
867902
});

test/unit/bin/helpers/usageReporting.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ describe("usageReporting", () => {
340340
expect(isUsageReportingEnabled()).to.be.undefined;
341341
});
342342
});
343-
343+
344344
describe("ci_environment", () => {
345345
afterEach(() => {
346346
delete process.env.JENKINS_URL;

0 commit comments

Comments
 (0)