diff --git a/bin/commands/runs.js b/bin/commands/runs.js index e6b8c713..81599162 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -45,6 +45,9 @@ module.exports = function run(args) { //accept the local identifier from env variable if provided utils.setLocalIdentifier(bsConfig); + // run test in headed mode + utils.setHeaded(bsConfig, args); + // Validate browserstack.json values and parallels specified via arguments return capabilityHelper.validate(bsConfig, args).then(function (cypressJson) { diff --git a/bin/helpers/capabilityHelper.js b/bin/helpers/capabilityHelper.js index 9cecfe81..71858623 100644 --- a/bin/helpers/capabilityHelper.js +++ b/bin/helpers/capabilityHelper.js @@ -84,6 +84,12 @@ const caps = (bsConfig, zip) => { if (!Utils.isUndefined(bsConfig.run_settings.cypress_version)){ obj.cypress_version = bsConfig.run_settings.cypress_version; } + + if (!Utils.isUndefined(bsConfig.run_settings.headless) && String(bsConfig.run_settings.headless) === "false"){ + obj.headless = bsConfig.run_settings.headless; + } else { + logger.info(`Running your tests in headless mode. Use --headed arg to run in headful mode.`); + } } if(obj.parallels === Constants.cliMessages.RUN.DEFAULT_PARALLEL_MESSAGE) obj.parallels = undefined diff --git a/bin/helpers/constants.js b/bin/helpers/constants.js index 8c409689..df5c55b3 100644 --- a/bin/helpers/constants.js +++ b/bin/helpers/constants.js @@ -93,6 +93,7 @@ const cliMessages = { ENV_DESCRIPTION: "Specify the environment variables for your spec files", SYNC_DESCRIPTION: "Makes the run command in sync", BUILD_REPORT_MESSAGE: "See the entire build report here", + HEADED: "Run your tests in a headed browser instead of a headless browser", }, COMMON: { DISABLE_USAGE_REPORTING: "Disable usage reporting", diff --git a/bin/helpers/utils.js b/bin/helpers/utils.js index 094ad4d9..e6223313 100644 --- a/bin/helpers/utils.js +++ b/bin/helpers/utils.js @@ -333,6 +333,12 @@ exports.setLocalIdentifier = (bsConfig) => { } }; +exports.setHeaded = (bsConfig, args) => { + if (!this.isUndefined(args.headed) && args.headed === true) { + bsConfig.run_settings.headless = false; + } +}; + exports.getNumberOfSpecFiles = (bsConfig, args, cypressJson) => { let testFolderPath = cypressJson.integrationFolder || Constants.DEFAULT_CYPRESS_SPEC_PATH; let globSearchPatttern = bsConfig.run_settings.specs || `${testFolderPath}/**/*.+(${Constants.specFileTypes.join("|")})`; diff --git a/bin/runner.js b/bin/runner.js index 33bf92b6..35a5c11b 100755 --- a/bin/runner.js +++ b/bin/runner.js @@ -200,6 +200,11 @@ var argv = yargs default: false, describe: Constants.cliMessages.RUN.SYNC_DESCRIPTION, type: "boolean" + }, + 'headed': { + default: false, + describe: Constants.cliMessages.RUN.HEADED, + type: "boolean" } }) .help('help') diff --git a/bin/templates/configTemplate.js b/bin/templates/configTemplate.js index 972acb60..8593abc6 100644 --- a/bin/templates/configTemplate.js +++ b/bin/templates/configTemplate.js @@ -60,7 +60,8 @@ module.exports = function () { "npm_dependencies": { }, "package_config_options": { - } + }, + "headless": true }, "connection_settings": { "local": false, diff --git a/test/unit/bin/commands/runs.js b/test/unit/bin/commands/runs.js index 29e02007..468543f6 100644 --- a/test/unit/bin/commands/runs.js +++ b/test/unit/bin/commands/runs.js @@ -5,6 +5,7 @@ const chai = require("chai"), const Constants = require("../../../../bin/helpers/constants"), logger = require("../../../../bin/helpers/logger").winstonLogger, testObjects = require("../../support/fixtures/testObjects"); +const { setHeaded } = require("../../../../bin/helpers/utils"); const proxyquire = require("proxyquire").noCallThru(); @@ -97,6 +98,7 @@ describe("runs", () => { capabilityValidatorStub = sandbox.stub(); setLocalStub = sandbox.stub(); setLocalIdentifierStub = sandbox.stub(); + setHeadedStub = sandbox.stub(); deleteResultsStub = sandbox.stub(); setDefaultsStub = sandbox.stub(); }); @@ -126,6 +128,7 @@ describe("runs", () => { getConfigPath: getConfigPathStub, setLocal: setLocalStub, setLocalIdentifier: setLocalIdentifierStub, + setHeaded: setHeadedStub, deleteResults: deleteResultsStub, setDefaults: setDefaultsStub }, @@ -150,6 +153,7 @@ describe("runs", () => { sinon.assert.calledOnce(getErrorCodeFromMsgStub); sinon.assert.calledOnce(setLocalStub); sinon.assert.calledOnce(setLocalIdentifierStub); + sinon.assert.calledOnce(setHeadedStub); sinon.assert.calledOnce(deleteResultsStub); sinon.assert.calledOnce(setDefaultsStub); sinon.assert.calledOnceWithExactly( @@ -187,6 +191,7 @@ describe("runs", () => { deleteZipStub = sandbox.stub(); setLocalStub = sandbox.stub(); setLocalIdentifierStub = sandbox.stub(); + setHeadedStub = sandbox.stub(); deleteResultsStub = sandbox.stub(); getNumberOfSpecFilesStub = sandbox.stub().returns([]); setDefaultsStub = sandbox.stub(); @@ -217,6 +222,7 @@ describe("runs", () => { getConfigPath: getConfigPathStub, setLocal: setLocalStub, setLocalIdentifier: setLocalIdentifierStub, + setHeaded: setHeadedStub, deleteResults: deleteResultsStub, setDefaults: setDefaultsStub, getNumberOfSpecFiles: getNumberOfSpecFilesStub @@ -247,6 +253,7 @@ describe("runs", () => { sinon.assert.calledOnce(setParallelsStub); sinon.assert.calledOnce(setLocalStub); sinon.assert.calledOnce(setLocalIdentifierStub); + sinon.assert.calledOnce(setHeadedStub); sinon.assert.calledOnce(validateBstackJsonStub); sinon.assert.calledOnce(capabilityValidatorStub); sinon.assert.calledOnce(archiverStub); @@ -290,6 +297,7 @@ describe("runs", () => { deleteZipStub = sandbox.stub(); setLocalStub = sandbox.stub(); setLocalIdentifierStub = sandbox.stub(); + setHeadedStub = sandbox.stub(); deleteResultsStub = sandbox.stub(); getNumberOfSpecFilesStub = sandbox.stub().returns([]); setDefaultsStub = sandbox.stub(); @@ -320,6 +328,7 @@ describe("runs", () => { getConfigPath: getConfigPathStub, setLocal: setLocalStub, setLocalIdentifier: setLocalIdentifierStub, + setHeaded: setHeadedStub, deleteResults: deleteResultsStub, getNumberOfSpecFiles: getNumberOfSpecFilesStub, setDefaults: setDefaultsStub @@ -354,6 +363,7 @@ describe("runs", () => { sinon.assert.calledOnce(setParallelsStub); sinon.assert.calledOnce(setLocalStub); sinon.assert.calledOnce(setLocalIdentifierStub); + sinon.assert.calledOnce(setHeadedStub); sinon.assert.calledOnce(validateBstackJsonStub); sinon.assert.calledOnce(capabilityValidatorStub); sinon.assert.calledOnce(archiverStub); @@ -401,6 +411,7 @@ describe("runs", () => { deleteZipStub = sandbox.stub(); setLocalStub = sandbox.stub(); setLocalIdentifierStub = sandbox.stub(); + setHeadedStub = sandbox.stub(); deleteResultsStub = sandbox.stub(); getNumberOfSpecFilesStub = sandbox.stub().returns([]); setDefaultsStub = sandbox.stub(); @@ -431,6 +442,7 @@ describe("runs", () => { getConfigPath: getConfigPathStub, setLocal: setLocalStub, setLocalIdentifier: setLocalIdentifierStub, + setHeaded: setHeadedStub, deleteResults: deleteResultsStub, getNumberOfSpecFiles: getNumberOfSpecFilesStub, setDefaults: setDefaultsStub @@ -473,6 +485,7 @@ describe("runs", () => { sinon.assert.calledOnce(setParallelsStub); sinon.assert.calledOnce(setLocalStub); sinon.assert.calledOnce(setLocalIdentifierStub); + sinon.assert.calledOnce(setHeadedStub); sinon.assert.calledOnce(archiverStub); sinon.assert.calledOnce(setUsageReportingFlagStub); sinon.assert.calledOnce(zipUploadStub); @@ -525,6 +538,7 @@ describe("runs", () => { isUndefinedStub = sandbox.stub(); setLocalStub = sandbox.stub(); setLocalIdentifierStub = sandbox.stub(); + setHeadedStub = sandbox.stub(); getNumberOfSpecFilesStub = sandbox.stub().returns([]); }); @@ -554,6 +568,7 @@ describe("runs", () => { getConfigPath: getConfigPathStub, setLocal: setLocalStub, setLocalIdentifier: setLocalIdentifierStub, + setHeaded: setHeadedStub, exportResults: exportResultsStub, deleteResults: deleteResultsStub, setDefaults: setDefaultsStub, @@ -601,6 +616,7 @@ describe("runs", () => { sinon.assert.calledOnce(setParallelsStub); sinon.assert.calledOnce(setLocalStub); sinon.assert.calledOnce(setLocalIdentifierStub); + sinon.assert.calledOnce(setHeadedStub); sinon.assert.calledOnce(archiverStub); sinon.assert.calledOnce(setUsageReportingFlagStub); sinon.assert.calledOnce(zipUploadStub); diff --git a/test/unit/bin/helpers/capabilityHelper.js b/test/unit/bin/helpers/capabilityHelper.js index 7890362a..370183fb 100644 --- a/test/unit/bin/helpers/capabilityHelper.js +++ b/test/unit/bin/helpers/capabilityHelper.js @@ -414,6 +414,136 @@ describe("capabilityHelper.js", () => { }); }); }); + + context("headless in run_settings", () => { + it("sets headless if false", () => { + let headless = false; + let zip_url = "bs://"; + let bsConfig = { + auth: { + username: "random", + access_key: "random", + }, + browsers: [ + { + browser: "chrome", + os: "Windows 10", + versions: ["78", "77"], + }, + ], + run_settings: { + headless: headless + }, + }; + + return capabilityHelper + .caps(bsConfig, { zip_url: zip_url }) + .then(function (data) { + let parsed_data = JSON.parse(data); + chai.assert.equal(parsed_data.headless, headless); + chai.assert.equal(parsed_data.env, undefined); + }) + .catch((error) => { + chai.assert.fail("Promise error"); + }); + }); + + it("sets headless if string false", () => { + let headless = "false"; + let zip_url = "bs://"; + let bsConfig = { + auth: { + username: "random", + access_key: "random", + }, + browsers: [ + { + browser: "chrome", + os: "Windows 10", + versions: ["78", "77"], + }, + ], + run_settings: { + headless: headless + }, + }; + + return capabilityHelper + .caps(bsConfig, { zip_url: zip_url }) + .then(function (data) { + let parsed_data = JSON.parse(data); + chai.assert.equal(parsed_data.headless, headless); + chai.assert.equal(parsed_data.env, undefined); + }) + .catch((error) => { + chai.assert.fail("Promise error"); + }); + }); + + it("does not set headless if true", () => { + let headless = true; + let zip_url = "bs://"; + let bsConfig = { + auth: { + username: "random", + access_key: "random", + }, + browsers: [ + { + browser: "chrome", + os: "Windows 10", + versions: ["78", "77"], + }, + ], + run_settings: { + headless: headless + }, + }; + + return capabilityHelper + .caps(bsConfig, { zip_url: zip_url }) + .then(function (data) { + let parsed_data = JSON.parse(data); + chai.assert.equal(parsed_data.headless, undefined); + chai.assert.equal(parsed_data.env, undefined); + }) + .catch((error) => { + chai.assert.fail("Promise error"); + }); + }); + + it("does not set headless if truthy", () => { + let headless = "enable"; + let zip_url = "bs://"; + let bsConfig = { + auth: { + username: "random", + access_key: "random", + }, + browsers: [ + { + browser: "chrome", + os: "Windows 10", + versions: ["78", "77"], + }, + ], + run_settings: { + headless: headless + }, + }; + + return capabilityHelper + .caps(bsConfig, { zip_url: zip_url }) + .then(function (data) { + let parsed_data = JSON.parse(data); + chai.assert.equal(parsed_data.headless, undefined); + chai.assert.equal(parsed_data.env, undefined); + }) + .catch((error) => { + chai.assert.fail("Promise error"); + }); + }); + }); }); describe("validate", () => { diff --git a/test/unit/bin/helpers/utils.js b/test/unit/bin/helpers/utils.js index a28f9fba..7e3cfd04 100644 --- a/test/unit/bin/helpers/utils.js +++ b/test/unit/bin/helpers/utils.js @@ -145,7 +145,7 @@ describe('utils', () => { sandbox = sinon.createSandbox(); sandbox.stub(utils,'getBrowserCombinations').returns(['a','b']); }); - + afterEach(() => { sandbox.restore(); sinon.restore(); @@ -545,6 +545,32 @@ describe('utils', () => { }); }); + describe('setHeaded', () => { + it('sets the headless to false', () => { + let args = { + headed: true + }; + let bsConfig = { + run_settings: {} + }; + + utils.setHeaded(bsConfig, args); + expect(bsConfig.run_settings.headless).to.be.eq(false); + }); + + it('sets the headless to false', () => { + let args = { + headed: false + }; + let bsConfig = { + run_settings: {} + }; + + utils.setHeaded(bsConfig, args); + expect(bsConfig.run_settings.headless).to.be.eq(undefined); + }); + }); + describe('exportResults', () => { it('should export results to log/build_results.txt', () => { sinon.stub(fs, 'writeFileSync').returns(true);