How to skip login on each nightwatch test - nightwatch.js

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();
}
};

Related

How do I create a HttpOrigin for Cloudfront to use a Lambda function url?

Trying to setup a Cloudfront behaviour to use a Lambda function url with code like this:
this.distribution = new Distribution(this, id + "Distro", {
comment: id + "Distro",
defaultBehavior: {
origin: new S3Origin(s3Site),
viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
},
additionalBehaviors: {
[`api-prd-v2/*`]: {
compress: true,
originRequestPolicy: originRequestPolicy,
origin: new HttpOrigin(functionUrl.url, {
protocolPolicy: OriginProtocolPolicy.HTTPS_ONLY,
originSslProtocols: [OriginSslPolicy.TLS_V1_2],
}),
allowedMethods: AllowedMethods.ALLOW_ALL,
viewerProtocolPolicy: ViewerProtocolPolicy.HTTPS_ONLY,
cachePolicy: apiCachePolicy,
},
The functionUrl object is created in a different stack and passed in to the cloudformation stack, the definition looks like:
this.functionUrl = new FunctionUrl(this, 'LambdaApiUrl', {
function: this.lambdaFunction,
authType: FunctionUrlAuthType.NONE,
cors: {
allowedOrigins: ["*"],
allowedMethods: [HttpMethod.GET, HttpMethod.POST],
allowCredentials: true,
maxAge: Duration.minutes(1)
}
});
The above code fails because "The parameter origin name cannot contain a colon".
Presumably, this is because functionUrl.url evaluates to something like https://xxx.lambda-url.ap-southeast-2.on.aws/ (note the https://) whereas the HttpOrigin parameter should just be the domain name like xxx.lambda-url.ap-southeast-2.on.aws.
I can't just write code to hack the url up though (i.e. functionUrl.url.replace("https://", "")) because when my code executes, the value or the url property is a token like ${Token[TOKEN.350]}.
The function url is working properly: if I hard-code the HttpOrigin to the function url's value (i.e. like xxx.lambda-url.ap-southeast-2.on.aws) - it works fine.
How do I use CDK code to setup the reference from Cloudfront to the function url?
I'm using aws-cdk version 2.21.1.
There is an open issue to add support: https://github.com/aws/aws-cdk/issues/20090
Use CloudFormation Intrinsic Functions to parse the url string:
cdk.Fn.select(2, cdk.Fn.split('/', functionUrl.url));
// -> 7w3ryzihloepxxxxxxxapzpagi0ojzwo.lambda-url.us-east-1.on.aws

How to run the same test with multiple logins, URL's, and body elements in cypress.io

I have a simple test I want to create in cypress that would require a test where using a settings file I would create 1 test that executes for each entry in the settings file. The file would contain user/pwd/url/elementID and be used to login for each user at a custom URL, and validate that a specific elementID is displayed, logout, and do it again - iterating through the settings file until each is tested.
I want to do something like:
forEach(URL,uname,pwd,elementID) do
cy.request(URL)
cy.get('input:uname').btn.click
cy.get('input:pwd').btn.click
cy.get(data-cy=elementID).should(be present)
cy.get(btn.logout).btn.click
I highly doubt the above code is correct - but hopefully you get the idea. Main goal is to create a simple and quick script that will quickly iterate through an array to smoke test the functionality.
You can still iterate over your test data and create a test case out of each:
[
{
url,
uname,
pwd,
elementID,
}
].forEach(testData => {
it(`Test ${testData.uname} on ${testData.url}`, () => {
// your test code
});
});
Of course the array:
[
{
url,
uname,
pwd,
elementID,
}
]
does not need to be there in the same file, you can have it somewhere separate and import it into your spec file.
Caveat: You can only visit URLs from the same origin in one test! This code will only work if all URLs you want to test are from the same origin (i.e. same
Save your data in json format and put them in Cypress folder "fixtures"
[
{"user":"username1","pwd":"pwuser1","url":"url1","elementID":"#element_name1"},
{"user":"username2","pwd":"pwuser2","url":"url2","elementID":"#element_name2"}
]
(Don't forget the # in front of the element_name id)
Then this is your smoke_test.spec.js
//fetch the parameters from the file and save them as constant "login"
const login_data = require('../fixtures/login_data.json')
//Now you can fetch the parameters using "login_data"
describe('smoke test', () => {
it('loop through login list', () => {
//we call each entry "param" and loop through the lines of the json file
cy.get(login_data).each((param) => {
cy.visit(param.url)
cy.get('#id_of_username_field').type(param.user)
cy.get('#id_of_pw_field').type(param.pwd)
//The next line is only if you have a login button
cy.get('#id_of_login_button').click()
cy.get(param.elementID).should('be.visible')
cy.get('#id_of_logout_button)
})
})
})

systematic failure when trying to execute a system command with Cypress

I'm new to Cypress and Javascript
I'm trying to send system commands through Cypress. I've been through several examples but even the simplest does not work.
it always fails with the following message
Information about the failure:
Code: 127
Stderr:
/c/Program: Files\Git\usr\bin\bash.exe: No such file or directory`
I'm trying cy.exec('pwd') or 'ls' to see where it is launched from but it does not work.
Is there a particular include I am missing ? some particular configuration ?
EDIT :
indeed, I'm not clear about the context I'm trying to use the command in. However, I don't set any path explicitely.
I send requests on a linux server but I also would like to send system commands.
My cypress project is in /c/Cypress/test_integration/cypress
I work with a .feature file located in /c/Cypress/test_integration/cypress/features/System and my scenario calls a function in a file system.js located in /c/Cypress/test_integration/cypress/step_definitions/generic.
System_operations.features:
Scenario: [0004] - Restore HBox configuration
Given I am logging with "Administrator" account from API
And I store the actual configuration
...
Then I my .js file, I want to send a system command
system.js:
Given('I store the actual configuration', () => {
let nb_elem = 0
cy.exec('ls -l')
...
})
I did no particular path configuration in VS Code for the use of bash command (I just configured the terminal in bash instead of powershell)
Finally, with some help, I managed to call system functions by using tasks.
In my function I call :
cy.task('send_system_cmd', 'pwd').then((output) => {
console.log("output = ", output)
})
with a task created as follows:
on('task', {
send_system_cmd(cmd) {
console.log("task test command system")
const execSync = require('child_process').execSync;
const output = execSync(cmd, { encoding: 'utf-8' });
return output
}
})
this works at least for simple commands, I haven't tried much further for the moment.
UPDATE for LINUX system commands as the previous method works for WINDOWS
(sorry, I can't remember where I found this method, it's not my credit. though it fulfills my needs)
This case requires node-ssh
Still using tasks, the function call is done like this
cy.task('send_system_cmd', {cmd:"<my_command>", endpoint:<address>,user:<ssh_login>, pwd:<ssh_password>}).then((output) => {
<process output.stdout or output.stderr>
})
with the task being build like this:
// send system command - remote
on('task', {
send_system_cmd({cmd, endpoint, user, pwd}) {
return new Promise((resolve, reject) => {
const { NodeSSH } = require('node-ssh')
const ssh = new NodeSSH()
let ssh_output = {}
ssh.connect({
host: endpoint,
username: user,
password: pwd
})
.then(() => {
if(!ssh.isConnected())
reject("ssh connection not set")
//console.log("ssh connection OK, send command")
ssh.execCommand(cmd).then(function (result) {
ssh_output["stderr"] = result.stderr
ssh_output["stdout"] = result.stdout
resolve(ssh_output)
});
})
.catch((err)=>{
console.log(err)
reject(err)
})
})
}
})

Directory path is incorrect when running from cypress test runner

When I login from normal browser the login is successful with the URL : http://neelesh.zapto.org:8084/EnrolMe/indHome.html
But when I run the script from Cypress the directory location is not appended and the new URL after login is formed as : http://neelesh.zapto.org:8084/__/indHome.html
I have tried setting cypress.json with
{
"chromeWebSecurity": false,
"modifyObstructiveCode" : false
}
I have tried on chrome/electron(head and headless).
Below is my code snippet:
describe('My First Test Suite', function() {
it('My First test case', function() {
cy.visit("http://neelesh.zapto.org:8084/EnrolMe")
cy.get("#login").click()
cy.get("input[value='Individual']").click()
cy.get("#username").type('1234567890')
cy.get("#pwd").type('0646')
Cypress.Cookies.debug(true)
cy.clearCookies()
cy.get("#login").click()
cy.wait(6000)
})
})
When I run the script from Cypress the directory location is not appended and the new URL after login is formed as : http://neelesh.zapto.org:8084/__/indHome.html
It should be redirected as : http://neelesh.zapto.org:8084/EnrolMe/indHome.html
Can anyone help me on this?
This sounds like an issue with "Frame Busting". There's a related discussion for Cypress GitHub Issue #992 which may lend some help.
Your application code may contain problematic frame busting code like the following:
if (window.top !== window.self) {
window.top.location.href = window.self.location.href;
}
You can get around this by changing your application code's reference to window.self from the Application Window to the Cypress Test Runner window (window.top).
Cypress emits a series of events as it runs in your browser. You can use the emitted window:before:load application event to ensure it's done before you attempt to login.
// cypress/support/index.js
Cypress.on('window:before:load', (win) => {
Object.defineProperty(win, 'self', {
get: () => {
return window.top
}
})
})

Change to desiredCapabilities in beforeEach not reflecting

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.

Resources