Get URL after sending form with webdriverio - javascript

I need to automate a sign in process test. I'm using webdriver.io in order to do that.
Here is my problem.
I have this bizarre sign in process:
I have to fulfil a form in a regular webpage
After sending the form, I'll be redirected to an URL that does not exist, but it contains an access code in one of its query params
Then I take this access code and send it to another location to obtain an access token.
What I need is a way of programmatically complete step 2, since 1 and 3 I have already figured out.
I'm trying like this:
var webdriverio = require('webdriverio');
var options = {
desiredCapabilities: {
browserName: 'chrome'
}
};
webdriverio
.remote(options)
.init()
.url(myUrl)
.title(function(err, res) {
console.log('Title was: ' + res.value);
})
.setValue('#usuario', user)
.setValue('#password', password)
.submitForm('form', function(){
this.url(function(err, res){
console.log(res.value);
});
this.pause(5000, function(){
this.end();
});
});
However, it seems like the callback for submitForm is called before the page gets loaded. This way, my log shows the very same URL I passed before.
If I try like this:
.submitForm('form', function(){
this.pause(5000, function(){
this.url(function(err, res){
console.log(res.value);
this.end();
});
});
});
I get this strange output:
data:text/html,chromewebdata
I know that a pause is not flawless in this context, but I could not find an asynchronous way of doing this.
Can anyone help?

You are probably not waiting for specific state after your form is submitted. What is the expected result after the form is submitted?
For example, you are expecting browser to redirect to a page with a header
<h1 class="success">Your form is submitted successfully</h1>
Then you should do something like this:
webdriverio
.remote(options)
.init()
.url(myUrl)
.waitForExist('form')
.setValue('#usuario', user)
.setValue('#password', password)
.submitForm('form')
.waitForExist('h1.success', 5000)
.getText('h1', function (err, res) {
expect(res).to.contain('submitted successfully'); //chai.js
})
.call(done);

Related

Verifying a navigated to URL using Webdriverio and Chai

I'm using webdriverio v4 and chai to enter values into a login form, click the login button and verify the navigated to URL:
describe('login form', function () {
it('should allow access with correct credentials', function () {
LoginPage.open();
LoginPage.username.setValue('name');
LoginPage.companyCode.setValue('100');
LoginPage.password.setValue('password');
LoginPage.loginButton.click();
expect(browser.getUrl()).to.equal('URL path');
});
});
the values are entered successfully and the expected URL is navigated to. However, browser.getURL() is returning the base URL rather than the new URL?
What am I doing wrong?
The URL may be retrieved too quickly. You may have to wait until the page has loaded the new page before getting the URL.
Could use something like with waitUntil and check the URL within the callback. Like so:
browser.waitUtil(function() {
return browser.getUrl() === urlToCheck;
}, 5000);
See: http://webdriver.io/api/utility/waitUntil.html

'or' query with different data types in sails.js

Given routes
GET /user/42
GET /user/dude
where 42 is user id and dude is username.
So, I want to have method in my controller that return user for both cases. Here it is:
// api/controllers/UserController.js
findOne: function(req, res) {
User.findOne({
or: [
{id: req.params.id},
{username: req.params.id}
]
}).exec(function(err, user) {
if (err) {
return console.log(err);
}
res.json(user);
});
},
When I try to GET /user/42 everything is fine.
When I try to GET /user/dude I get error:
Error (E_UNKNOWN) :: Encountered an unexpected error
error: invalid input syntax for integer: "dude"
It seems like sails refuses to process {id: 'dude'} because of type mismatch.
I am using sails 0.10.5 with sails-postgresql 0.10.9. So what am I doing wrong?
UPD: I do know how to solve problem. Of course I can put if statement to my controller and check what type of parameter it got. Actually, I just created two routes with regexp parameters that point to single method.
My actual problem is why I can not do this with or. Does sails provide such way?
By default, sails get method only supports id numbers. You will need
to define custom routes and implement the relevant api method to
support a get request using a string instead of a number.
Technical Details:
To solve your exact problem, you need to define the following route in your routes.js
module.exports.routes = {
...
'/user/get/:param': 'UserController.findByIDorName',
...
}
This will pass anything after the /user/get/ as the parameter named 'param' to the findByIDorName controller method.
Next you need to check the type of the param and decide if you want to fetch the user info based on the id or the name, so add this function in your userController.js
findByIDorName : function (req, res) {
if (isNaN(req.param)){
//find the user by his username after any validation you need
}
else {
//find the user by his id and return
}
}

How create a simple get form that will create a dynamic route, depending on the value of the search field (MONGODB and Node.js)

i want search throw the database for a value that the user puts in a get form.
The backend is very simple, i know how to search throw the database and render the result..
app.get('search/:id', function(req, res) {
var id = req.param("id");
mongoose.model('Something').find({
// the field that i want find. For example:
_id: id // This will search for the id field in the database, them will return a object if finds a match.
}, function(error, object){
if (error) {
res.send(error);
}
else {
res.send(object);
}
}
);
});
This script will work.
Now i'm having problems with the HTML.
I need a get form that will send a user to /search/SOMETHING THAT THE USER WANTS SEARCH, but i don't know exactly how to change the url dinamically..
Any help is very very welcome.
If you don't know how to achieve desired behaviour in the HTML, you could still do it in the backend - by setting a redirect. Your incoming request after form submission would be something like ?inputName=user search string.
You could then take the value of the query and perform an internal redirect to your route
app.get('search', function(req, res) {
res.redirect('/search/' + req.query["inputName"]);
});
to get a form to pass GET params in a nice express-like way, you need to hook on the onSubmit of the form and then trigger an XHR/ajax request instead of the form-post.
Or you can read the querystring via req.query.inputFieldName if you are okay having the url look like /search/?inputFieldName=AwesomeSearchString
I'd take the XHR/ajax way as it also prevents the page from reloading and thus improving user-experience.

Calling the app config method inside ajax response - AngularJS

I am developing an app using angularjs and this is my first hands on using angular. Although, I have started understanding it and have developed some part of the app but I am stuck at one particular point.
I am trying to implement login functionality, so as the page loads, I am authenticating user and redirecting him to login page. On successful login, I am storing some values of user in one of the config provider.
Now I am using an API which has their own method of authentication and they have expose the ajax method which I can use to authenticate a user.
I have provided a snippet below. What I am primarily doing is using the external API, authenticating the user and once authenticated, I am getting roles associated to that user using another ajax method of the API, called "GetUserDetails".
And inside the response of the "GetUserDetails", I am injecting a provider and setting some values, so I can use this across my app.
The problem here is the app.config method is never called/executded. I mean the ajax request is returning response, and the alert is displayed on my page, but app.config is never executed.
But the same app.config if I call inside the done() of GetUser method, the app.config gets executed and stores values in my provider. But I want the GetuserDetails values also to be stored before I do anything in my app as I want to execute certain functionality based on user.
Below is my function in main.js file
function(angular,angularRoute,app,routes,configService){
var $html = angular.element(document.getElementsByTagName('html')[0]);
angular.element().ready(function() {
$.c.authentication.getUser()
.done(function(response){
if(response.userName!="anonymous"){
$.c.ajax({
method: "GetUserDetails",
parameters: {
User: response.user
}
})
.done(function(res) {
alert("I have reached the destination").
app.config(['configServiceProvider', function(configServiceProvider){
configServiceProvider.setLoginStatus(true);
configServiceProvider.setUserName(response.userName);
configServiceProvider.setUserObject(response);
configServiceProvider.setUserRoleDetails(res);
}]);
})
.fail(function(res) {
alert("Error while getting user roles ."+res);
});
angular.resumeBootstrap([app['name']]);
}
else
{
app.config(['configServiceProvider', function(configServiceProvider){
configServiceProvider.setLoginStatus(false);
configServiceProvider.setUserName(response.userName);
}]);
//Show Login Screen
var url = window.location.href.split("#")[0];
window.location.href = url + "#/Login";
angular.resumeBootstrap([app['name']]);
}
})
.fail(function(response){
$rootScope.isLoggedIn=false;
});
});
Here is my configServiceProvider
define(['../app'],function(app){
return app.provider('configService', function(){
var options={};
this.setLoginStatus = function(status){
//$rootScope.isLoggedIn = status;
options.isLoggedIn=status;
};
this.setPreLoginInfo=function(info){
options.preLoginInfo=info;
};
this.setUserName=function(name){
options.username=name;
}
this.setUserObject = function(userObject) {
options.userObject = userObject;
}
this.setUserRoleDetails = function(userRoleDetails) {
options.userRoleDetails = userRoleDetails;
}
this.$get=[function(){
if(!options){
}
return options;
}];
});
})
Can anyone please explain me what's going wrong here or what I am missing ?
Also, is there any alternative to achieve the same functionality ?
No luck in figuring out why the above scenario was not working. Since I had already spent lot of time behind this, I have found a workaround to achieve the same with the use of services.

Node.js, MongoDB Login form

I have a node.js application with a connection to a remote mongoDB server. The database contains some custom codes that have been pre-created and distributed to certain users. The idea is that only those who enter one of such codes into a form on the index page can be allowed to view the rest of the site. That is, I want to cross-reference the code entered with the master list stored in my database.
This is an example of what I'm trying to do(note this is in routes/index.js):
collection.findOne({ "Code": "fooCode" }, function(err, doc){
if you cannot find fooCode
show an error message, clear the input area and tell the user to re-enter a correct code
if you find fooCode
redirect to a new page;
});
The above code is within a
router.post('/', function(req, res){...})
function.
My question is, how do I clear the text input area(without refreshing the page) and ask the user to re-enter a new code when a wrong code is entered?
Secondly how do I redirect the user to a new page on valid entry of a code? Thanks.
For that kind of behavior you would need to submit the form via XHR, parse the (JSON) response, and then clear the form on error and display error information. On the server side you can simply do something like res.json({ status: 'success' }); or res.json({ status: 'error', error: 'Bad token' });
On success, you could do the redirect in the browser via window.location.replace("http://example.org/foo"); or if you want the current page in the session history (e.g. reachable with the browser's back button) you can use window.location.href = "http://example.org/foo".
To clear the input: I would handle this on the front-end, so that everytime the button is clicked (to send the form) it clears the input with:
<input id="userInput" type="text">
<button id="submitBtn">Send</button>
Then in your script:
// Cache DOM
const myInput = document.getElementById('userInput');
const myBtn = document.getElementById('submitBtn');
// Event Bind
myBtn.on('click', clearInput);
// Functions
function clearInput() {
myInput.value = '';
}
2. To redirect the user to a new page
res.redirect('/<path>');
You can do the following in your routes to redirect user to the home route.
collection.findOne({ "Code": "fooCode" }, function(err, doc){
if err throw err
else {
res.redirect('/');
}
})

Categories