Change to desiredCapabilities in beforeEach not reflecting - nightwatch.js

I am trying to record all browser request and responses. This can be done via browsermob-proxy api's.
For this, I have to change desired capabilities and change httpProxy for browser.
In beforeEach at global or file level, I am trying to change this. Though it reflects in browser object, actual browser is not initiated with those settings.
Simple example:
globalhook file
module.exports = {
before : function (done) {
},
beforeEach: function(browser, done){
browser.options.desiredCapabilities = {
"browserName": "chrome",
"proxy": {
"proxyType": "manual",
"httpProxy": "127.0.0.1:" + someport,
"sslProxy": "127.0.0.1:" + someport
},
"javascriptEnabled": true,
"acceptSslCerts": true,
}
done()
},
afterEach: function(browser, done){
//some code
}
after : function (done) {
//some code
},
}
If i change desired capabilities in before hook, chrome browser is taking those changes. Problem is with beforeEach [global, file level].
Further debugging, I've found setCapabilities function is run just before beforeEach Hook.
Could anyone please have a look or suggest if I am doing something wrong.

Thanks for moving the issue here.
The issue is that the desiredCapabilities are applied to a browser session.
beforeEach and afterEach run on the same browser session therefore any change in the desiredCapabilities won't be applied unless the session is restarted.
If you need to dynamically change the desiredCapabilities you have to structure your tests in the different way, e.g. split your tests in separate test classes

First of all, you probably want to use before() hook instead of beforeEach(), since beforeEach() will run before each test case and you won't be able to modify already started browser session. before() will run before browser session is initiated.
To solve your issue you need to define desiredCapabilities property on your test run module and in case you need to set some dynamic values, use before() hook to modify that object:
module.exports = {
desiredCapabilities: {
"browserName": "chrome",
"proxy": {
"proxyType": "manual",
"httpProxy": "127.0.0.1",
"sslProxy": "127.0.0.1"
},
"javascriptEnabled": true,
"acceptSslCerts": true,
},
before: function(client, done) {
this.desiredCapabilities.proxy.sslProxy = '127.0.0.1' + someport;
done();
}
}
I've searched official docs on this feature but couldn't find anything, though we used this in our tests and it worked well.
Update:
Since you only need to change proxy on desiredCapabilities object, there is a little hack:
// global hooks file:
module.exports = {
beforeEach: function(client, done) {
client.options.desiredCapabilities.proxy = {
"proxyType": "manual",
"httpProxy": "127.0.0.1:" + someport,
"sslProxy": "127.0.0.1:" + someport
};
done(client);
}
};
Changing desiredCapabilities object won't work, since reference to original object is already stored somewhere under the hood of Nightwatch. But nothing stops you from overriding proxy property on that object.
After checking sources and tests in Nightwatch I believe this is the only solution for your case.

Related

How to stop cypress from closing browser after each test case (it)?

I have a cy.js file like this
/// <reference types="cypress" />
context("Dummy test cases", () => {
it("open Google", () => {
cy.visit("www.google.com");
});
it("search a keyword", () => {
cy.get(".gLFyf").type("cypress{enter}");
});
});
As you can see I've 2 test cases. 1 is to open a website and the other is to do other tasks.
But the problem is that after finishing the first 'it' (test case 1), the browser closes and then the next case fails because there is no active browser.
Can you help me how to stop cypress from closing the browser after the execution of each test case?
I found Cypress is quite opinionated about some things, one at the top of the list is "test isolation" which means one test must not influence another test.
Note each it() is a test.
To make your code work, you must turn off test isolation.
If the cypress.config.js file add the option
const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
testIsolation: false,
},
})
Same if you are using typescript.
This got added in the new Version Cypress 12.0.0, in their
Changelogs its at the feature section:
Added a new configuration option called testIsolation, which defaults to true.
As #Joylette already said, in your config file just use testIsolation: false to deactivate it. If you ever use an older version use testIsolation: off, they renamed it in the newest version.

Cypress configuration interpolation

Is there a way to let configuration variables in 'cypress.json' point to another variable?
A little example:
{
"baseUrl": "https://example.org"
"env": {
"apiUrl": "${baseUrl}/api/v1"
}
}
I didn't found something about this in the documentation, but it would be very usefull to me.
There is no way to make interpolation inside cypress.json because it is simple JSON file. But, you can achieve it during runtime, like this (put this code inside your cypress/plugins/index.js):
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
config.baseUrl = `${config.baseUrl}${config.env.apiUrl}`
console.log(config.baseUrl) // https://example.org/api/v1
return config;
}
And your cypress.json:
{
"baseUrl": "https://example.org"
"env": {
"apiUrl": "/api/v1"
}
}

Protractor file download test fails when headless chrome

I am having an issue with a protractor test. It was working, but now (even thought nothing has changed) it is not.
The test is just opening the app (web application) and clicking on a button to download an image. The download should start straight away.
The problem is that the next instruction after the download event throws an exception, Failed: chrome not reachable. I am using the latest chrome and chrome driver versions.
The capabilites section for protractor is like this:
capabilities: {
browserName: 'chrome',
loggingPrefs: { browser: 'ALL' },
chromeOptions: {
args: ['--headless', '--window-size=1240,780'],
},
}
I am reading about using DevTools to enable downloads in headless mode (Page.setDownloadBehavior), but so far no luck.
Does anybody have this issue too? Any clue how to fix it?
Thanks.
There could be another easy way to do it, but this is what I have done in my test suite.
I used got library, however, you can use any library to send an HTTP post request.
Discussion about setting download directory in headless chrome: https://bugs.chromium.org/p/chromium/issues/detail?id=696481
let got = require('got');
let session = await browser.getSession();
let sessionId = session['id_'];
let params = {'cmd': 'Page.setDownloadBehavior', 'params': {'behavior': 'allow', 'downloadPath': downloadDir }}
await got.post('http://localhost:4444/wd/hub/session/'+ sessionId + '/chromium/send_command', {body: JSON.stringify(params)})
If you have not disabled ControlFlow in your protractor config, change ASync/Await to .then.
An easier solution is to add these lines to your protractor.conf.js:
exports.config = {
...
onPrepare() {
...
browser.driver.sendChromiumCommand('Page.setDownloadBehavior', {
behavior: 'allow',
downloadPath: downloadsPath
});
}
};
From: https://bugs.chromium.org/p/chromium/issues/detail?id=696481#c196
Appendix
If you are to lazy to find a Download Path just paste this at the top of your protractor.conf.js:
var path = require('path');
var downloadsPath = path.resolve(__dirname, './downloads');
It will download the file to the e2e/downloads folder. Just use the same code in your tests to find out if the file downloaded.
This works for me:
chromeOptions: {
'args': [
'--headless',
'--disable-gpu',
'--test-type=browser',
'--disable-extensions',
'--no-sandbox',
'--disable-infobars',
'--window-size=1920,1080',
//'--start-maximized'
"--disable-gpu",
],
prefs: {
'download.default_directory': 'C:\\downloads',
'download.prompt_for_download':false,
'download.directory_upgrade':true,
"safebrowsing.enabled":false,
"safebrowsing.disable_download_protection":true
},
},

Protractor proxy settings configuration is not passed to Saucelabs

To enable saucelabs proxy to work in older version of protractor, we were overriding sendRequest method by setting host and port in below index.js:
protractor\node_modules\selenium-webdriver\http\index.js
Now protractor allows you set the proxy through capabilities object (as shown below) which should be passed to index.js sendRequest new parameter called 'opt_proxy'.
capabilities: {
"browserName": "chrome",
'proxy': {
'proxyType': 'manual',
'httpProxy': 'appproxy.web.abc.com:84'
},
"chromeOptions": {
"args": [
"--disable-extensions",
"--test-type"
]
},
"customData": {
"usageBracket" : "1",
"displayName" : "Chrome",
"id" : "CH"
}
}
However, when I am still getting null for opt_proxy. Is there anything I am doing wrong? I even tried passing through CLI using --proxy="" but it still get null.
I have gotten my proxy configuration to work with Sauce Labs using the sauceAgent util provided within Protractor. Here is a code snippet from my protractor config file.
var HttpsProxyAgent = require("https-proxy-agent");
var agent = new HttpsProxyAgent('http://localhost:56193'); //Insert your proxy info here
exports.config = {
sauceUser: process.env.SAUCE_USERNAME,
sauceKey: process.env.SAUCE_ACCESS_KEY,
sauceAgent: agent,
capabilities: {
browserName: 'chrome',
chromeOptions: {
args: [
'--proxy-server=socks5://host:port',
]
},
},

How to skip login on each nightwatch test

Each of my Nightwatch.js tests requires authentication in order to run and for the time being I can't make authentication to be done via cookies (of course if test fill in a username and password it logs in, but it takes time this way)
I have a working PHPSESSID (tested in Fiddler) cookie and trying to set it via nightwatch setCookie function like this:
browser
.setCookie({
name : "PHPSESSID",
value : "gfnpqlflvlrkd2asj18ja2ewrt",
path : "/admin", //(Optional)
domain : "example.com", //(Optional)
secure : true, //(Optional)
httpOnly : false // (Optional)
})
.url("www.example.com/admin")
however www.example.com/admin redirects me back to www.example.com/login meaning authentication didn't pass.
Is there any solution?
I had this issue as well and just ended up creating a custom command. You'll need to create a new folder called custom-commands within your nightwatch test folder. In your nightwatch.JSON file you will need to specify the path to this folder like so:
"custom_commands_path" : "./nightwatch-tests/custom-commands"
Create a new test filed in this new folder with the login steps and use the name as your new command at the beginning of each test. For example, my file is called "login.js" and it looks like this:
var load_speed = 5000,
local_login_url = "https://";
exports.command = function(username, password) {
this
.url(local_login_url)
.waitForElementVisible('.login', load_speed)
.setValue('input[type=text]', username)
.setValue('input[type=password]', password)
.click('input[type=submit]')
.pause(load_speed)
.assert.elementPresent('.dashboard')
return this;
};
When I call the custom command in my test, it looks like this:
.login(username, password)
Maybe you can use the "before" or "beforeEach" hook.
http://nightwatchjs.org/guide#using-before-each-and-after-each-hooks
module.exports = {
before : function(browser) {
console.log('before all tests');
},
beforeEach : function(browser) {
console.log('before each test');
},
afterEach : function(browser) {
},
"test one" : function (browser) {
browser
// ...
},
"test two" : function (browser) {
browser
// ...
.end();
}
};

Resources