nightwatchjs / nightwatch

Integrated end-to-end testing framework written in Node.js and using W3C Webdriver API. Developed at @browserstack
https://nightwatchjs.org
MIT License
11.79k stars 1.31k forks source link

Using nightwatch, is there a possibility to pass a global property from command line? #498

Closed sand3r closed 9 years ago

sand3r commented 9 years ago

The app I'm testing has different domains (for development, testing, acceptance, etc.). Is it possible to set a global property (preferably as param for nightwatch) so that I can easily kick off tests for those different domains/environments?

MateuszJeziorski commented 9 years ago

Sure you are. example solution:

Firstly lets create Global.js file. Add path to the file inside nightwatch.json:

"globals_path": "Global.js"

In Global.js define before method (it is executed once before any of test):

var self = module.exports = {
    environment: undefined,
    before: function (done) {
       // parseArgumentsAndGetEnv is function you need to implement on your own to find your env param
        self.environment = parseArgumentsAndGetEnv(process.argv);
        console.log("Run against: " + self.environment);

        done();
    }
};

Now in tests you can use this variable:

if (browser.globals.environment == 'Test') {
   // do something
} else if (browser.globals.environment == 'Prod') {
  // do something else
}
sand3r commented 9 years ago

Thanks a lot! Will implement this today!

peterbollen commented 9 years ago

Perhaps this is worth checking out https://www.npmjs.com/package/yargs

beatfactor commented 9 years ago

You can also define per-environment globals like so:

module.exports = {
  globalVar : 'test-value',
  // for development environment have a different value set
  development : {
    globalVar : 'dev-value'
  },

  acceptance : {
    globalVar : 'other-value'
  }
}

If this doesn't work for you, feel free to re-open.

GrayedFox commented 9 years ago

Oh man... thank you @beatfactor, been trying to figure out something like this for ages.

AnastasiaPetrovskaya commented 8 years ago

@MateuszJeziorski I'm trying to use your example, but unfortunately in tests the variable environment is undefind, maybe you can suggest me something?

MateuszJeziorski commented 8 years ago

@AnastasiaPetrovskaya: could you post your globals.js, test code and nightwatch.config you're using? also are you running tests parallel using test workers or it does not work for you even without parallel runner? what version of nightwatch you're using, is before called at all in your case?

AnastasiaPetrovskaya commented 8 years ago

my globals.js file:

var self = module.exports = {
  someGlobal : 'Here I am',
  totalAm : undefined,

  before: function(done) {
    var my_env = {};
    for (e in process.env) my_env[e] = process.env[e];
    my_env["LOTO_ENV"] = "test";
    api = spawn('nodejs', ['index.js'], {cwd : '../api', env : my_env, detached: true, stdio: 'ignore'});
    sadmin = spawn('python', ['server.py'], {cwd : '../sadmin', env : my_env, detached: true, stdio: 'ignore'});
    api.unref();
    sadmin.unref();

    db.prepareDb(url, insertedClient1, insertedClient2, insertedClient3, totalAmounts, 
        function(insertedClient1, insertedClient2, insertedClient3, totalAmount) {
      self.totalAm = totalAmount;
      console.log('self',self.totalAm);
      done();
    });
  },

  after : function() {
    fs.readFile('../sadmin/tmp/pids/server.pid', 'utf8', function (err, data) {
      if (err) {
        console.log(err);
      } else {
        process.kill(data, 'SIGTERM');
      }
    });
    fs.readFile('../api/tmp/pids/server.pid', 'utf8', function (err, data) {
      if (err) {
        console.log(err);
      } else {
        process.kill(data, 'SIGTERM');
      }
    });
  }
};

my nightwatch.json

{
  "src_folders": ["Sadmin"],
  "output_folder" : "reports",
  "custom_commands_path" : "./js/commands",
  "custom_assertions_path" : "",
  "page_objects_path" : "",
  "globals_path" : "globals.js",
  "globals" : "",
  "test_workers": {"enabled": true, "workers" : "auto"},
  "live_output": true,

  "selenium" : {
    "start_process" : true,
    "server_path" : "./selenium-server-standalone-2.43.1.jar",
    "log_path" : "",
    "host" : "127.0.0.1",
    "port" : 4448,
    "cli_args": {
      "webdriver.chrome.driver" : "./chromedriver"
    }
  },
  "test_settings" : {
    "jenkins" : {
      "launch_url" : "http://localhost",
      "selenium_port"  : 4445,
      "selenium_host"  : "127.0.0.1",
      "disable_colors" : true,
      "skip_testcases_on_fail": false,
      "end_session_on_fail":false,
      "screenshots" : {
        "enabled" : true,
        "on_failure" : true,
        "path" : "reports"
      },
      "desiredCapabilities": {
        "browserName": "chrome",
        "javascriptEnabled": true,
        "acceptSslCerts": true
      }
    },

    "default" : {
      "launch_url" : "http://localhost",
      "selenium_port"  : 4448,
      "selenium_host"  : "127.0.0.1",
      "skip_testcases_on_fail": false,
      "end_session_on_fail":false,
      "screenshots" : {
        "enabled" : true,
        "on_failure" : true,
        "path" : "reports"
      },
      "filter": "Sadmin/sadmin.js",
      "desiredCapabilities": {
        "browserName": "chrome",
        "javascriptEnabled": true,
        "acceptSslCerts": true
      }
    },

    "sales" : {
      "launch_url" : "http://localhost",
      "selenium_port"  : 4448,
      "selenium_host"  : "127.0.0.1",
      "skip_testcases_on_fail": false,
      "end_session_on_fail":false,
      "screenshots" : {
        "enabled" : true,
        "on_failure" : true,
        "path" : "reports"
      },
      "filter": "Sadmin/sadmin_sales.js",
      "desiredCapabilities": {
        "browserName": "chrome",
        "javascriptEnabled": true,
        "acceptSslCerts": true
      }
    }
  }
}

before is called and I'm running tests parallel using test workers, and the example of the test

  'LogIn As Owner': function(client) {
    //проверка главной страницы
    client.logIn(BASE_URL + '/logout', 'owner' , 'user');
    client.pause(2000);
    client.checkMenu('owner', DEFAULT_TIMEOUT);
    client.mainPage('owner', DEFAULT_TIMEOUT);
    console.log('globals', client.globals);
  },

the result of console.log is

globals { someGlobal: 'Here I am',
  totalAm: undefined,
  before: [Function],
  after: [Function] }

nightwatch v0.8.4

MateuszJeziorski commented 8 years ago

I have similar problem using test workers, seems each worker gets his own copy of global.js but before is triggered in just of them

my workaround is to use getter instead property and check if environment was set, if not I'm setting it once again

var args = require('minimist')(process.argv);
var environment;

function getEnvironment() {
    return args["e"] || "default";
}

var self = module.exports = {
    get environment() {
        if (!environment) {
            environment = getEnvironment();
        }
        return environment;
    }
};

and in tests I'm doing:

var env = browser.globals.environment;

in your case you could do something silimar

var totalAm;

var self = module.exports = {
    getTotalAm: function(callback) {
        if (totalAm === undefined) {
            // async call to get totalAm from DB and return it using callback
        } else {
            callback(totalAm);
        } 
    }
};

and in your test:

client.globals.getTotalAm(function(totalAm) {
  console.log("TotalAm:", totalAm);
});
leandroromero commented 8 years ago

Hi, i don't solve the similar problem. Need to pass a global variable to line command.

In Global.js implements @MateuszJeziorski comments.

var args = require('minimist')(process.argv);
var globalSite = '',

function getSite() {
    return args["site"] || "default";
}

module.exports = {
    get site() {
        if (!site) {
            globalSite = getSite();
        }
        return site;
    }
};

In mi test named coreSpecs.js

module.exports = {
before: function(browser) {
        var site = browser.globals.globalSite;
        console.log(site);
}
};

In console execute

nightwatch -site mla -t tests/e2e/groups/mobile/coreSpecs.js

But not works... :(. The console log

ERROR There was an error while starting the test runner:

Error: Invalid testing environment specified: mla
    at Object.CliRunner.parseTestSettings (/usr/local/lib/node_modules/nightwatch/lib/runner/cli/clirunner.js:447:15)
    at Object.CliRunner.setup (/usr/local/lib/node_modules/nightwatch/lib/runner/cli/clirunner.js:51:8)
    at Object.exports.runner (/usr/local/lib/node_modules/nightwatch/lib/index.js:540:17)
    at /usr/local/lib/node_modules/nightwatch/bin/runner.js:9:16
    at Object.exports.cli (/usr/local/lib/node_modules/nightwatch/lib/index.js:534:5)
    at Object.<anonymous> (/usr/local/lib/node_modules/nightwatch/bin/runner.js:8:14)
    at Module._compile (module.js:460:26)
    at Object.Module._extensions..js (module.js:478:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)

Thanks guys

MateuszJeziorski commented 8 years ago

1) In Global.js change your code to:

module.exports = {
    get site() {
        if (!globalSite) {
            globalSite = getSite();
        }
        return globalSite;
    }
};

my example may be misleading, because I have there a) method environment b) property environment

2) In your test file

module.exports = { 
   before: function(browser) {
        var site = browser.globals.site;
        console.log(site);
   }
};

3) I'm not sure if this works

nightwatch -site mla -t tests/e2e/groups/mobile/coreSpecs.js

please try:

nightwatch --site mla --t tests/e2e/groups/mobile/coreSpecs.js

4) You're missing nightwatch environment

nightwatch --env chrome --site mla --t tests/e2e/groups/mobile/coreSpecs.js

assuming you have defined chrome in nightwatch.json. Check http://nightwatchjs.org/guide#test-settings

leandroromero commented 8 years ago

Thanks @MateuszJeziorski Its works! You're the best :+1:

shripadbothaleAvalara commented 7 years ago

Hi I am trying to use globals in test as said by @MateuszJeziorski but getting environment as undefined in test below is my global.js var self = (module.exports = { environment: undefined, before: function(done) { self.environment = process.env.TEST_ENV; if (self.environment == "CI") { console.log("Run against: CI"); self.environment= “CI_URL”; } else if (self.environment == "PROD") { self.environment= “Prod_URL”; } else if (self.environment == "SBX") { console.log("Run against: SBX"); self.environment= “SBX_URL”; } else { console.log("No execution environment is specified running against: QA"); self.environment= “QA_URL; // } done(); } });

In my nightwatch configuration i have used "globals_path": "configuration/globals.js",

In test i am trying console.log("In Test File environment:"+ browser.globals.environment); and it is coming as undefined.

Output of execution

Run against: CI (Value is set in global.js) Starting selenium server... started - PID: 74046

[Cup Login] Test Suite

In Test File environment:undefined (Undefined in test env)

Anyone please suggest if i am missing anything?

jehon commented 7 years ago

A bit late in the dance...

On the "client", you have the

client.options.desiredCapabilities

which come out from your nightwatch.js. That allow you to configure your variable by browser, if of any use :-)

nnk1996 commented 6 years ago

@jehon how exactly do you use it? is it something like

client.options.desiredCapabilities(property,value)

I tried using it and got an error stating

client.options.desiredCapabilities is not a function

tejam1253 commented 6 years ago

@anyone : is there any way to pass the username and password through command line my Step definition looks like this

When(/^I login $/, async () => { await login.waitForElementVisible('@form') login.setValue('@username', 'username') login.setValue('@password', 'password') login.click('@login') })

ritdhwaj commented 6 years ago

You can pass these as enviornment variables

tejam1253 commented 6 years ago

globals: { 'username': process.env.USERNAME, 'password': process.env.PASSWORD }, ive written the code in nightwatch.config but doesnt seem to work

abitha90k commented 6 years ago

Hi, I am using nightwatch for test automation. with the comments from @MateuszJeziorski on jan 8 2016, I am able to provide the data from command line. Is there a way to provide a set of data in the command line, so that the test can take it one by one to run the tests?

Any pointers with respect to this, can be helpful!

nsberrow commented 6 years ago

Managed to figure out how to do a API call to get cookies in order to set cookies before globals are set:

It's still a little rough around the edges but it works at least, hope someone else can save themselves a couple of days:


let request = require("request-promise");

function setAPI(self) {
  request.post({
    uri: 'https://<api-endpoint>/login',
    method: "POST",
    rejectUnauthorized: false,
    json: true,
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    form: {
      email: '<email-address>', password: '<password>'
    },
  }, function (error) {
    if (error) {
      console.log(error);
    }
  })
    .then(function(response) {
      self.output.body = response;
      return self.output.body;
    });
}

let self = module.exports = {
  output: {
    body: 'yo'
  },
  tokens: {
    csrf_token:' ',
    jwt: '',
  },
  before : (browser, done) => {
    self.output.body = setAPI(self);
    chromedriver.start();
    done();
  },
  after: (done) => {
    self.tokens.csrf_token = self.output.body.response.csrf_token;
    self.tokens.jwt = self.output.body.response.jwt;
    chromedriver.stop();
    done();
  },
};
kriztaljimenez commented 6 years ago

@nsberrow Hey, cool work with the latest post. You think we can consume this having the cookie reused to bypass succeeding login for multiple script execution?