Protractor test script is not getting object data from function - protractor

Need help on getting object data that populated in a function to test script, please. Here are the details:
candidate Data = function() {
"firstName": "firstname",
"lastName": "lastname",
"mobilePhone": "phone",
"primaryEmail": "email"
};
module.exports = new candidateData();
test script is as As below:
var testData = require('candidateData');
var myFunction = require('getData');
testCandiate = {};
testCandidate = testData;
it('Get Candidate Data', function(){
myFunction.getCandidateData(testCandidate);
console.log(`FirstName is -: ${testCandidate.firstName}:-`);
console.log(`LastName is -: ${testCandidate.firstName}:-`);
console.log(`Phone is: ${testCandidate.mobilePhone}:-`);
console.log(`Primary Email is -: ${testCandidate.primaryEmail}:-`);
});
the function is defined in separate js file as:
// As I am capturing data from edit fields of a page, so using get Attribute value to get value
var getData = function() {
this.getCandidateData = function(testObj){
page.firstname.getAttribute("value").then(function(fname){
testObj.firstName = fname;
});
page.lastname.getAttribute("value").then(function(lname){
testObj.lastName = lname;
});
page.phone.getAttribute("value").then(function(phone){
testObj.mobilePhone = phone;
});
page.email.getAttribute("value").then(function(email){
testObj.primaryEmail = email;
});
};
};
module.exports = new getData();
After Running Script I am getting console log results AS below instead of Populated data on the fields:
First Name is -: firstName :-
Last Name is -: lastName :-
Mobile Phone is -: mobilePhone :-
Primary Email is -: primaryEmail :-
please need help.

This is not a protractor issue but a basic misunderstanding you have of promises, as you are running into a race condition. You call myfunction.getCandidateData() which calls 4 separate functions that return promises. While those functions are getting the attributes you wanted javascript continues on in your code. This means that the console.log statements fire immediately without waiting for the four getAttribute promises to resolve.
To fix this you will have to convert getCandidateData into a function that returns a promise. As a proof of concept try this to see that firstName will be populated:
var testData = require('candidateData');
var myFunction = require('getData');
testCandiate = {};
testCandidate = testData;
it('Get Candidate Data', function(){
myFunction.getCandidateData(testCandidate).then(() => {
console.log(`FirstName is -: ${testCandidate.firstName}:-`);
});
// console.log(`LastName is -: ${testCandidate.firstName}:-`);
// console.log(`Phone is: ${testCandidate.mobilePhone}:-`);
// console.log(`Primary Email is -: ${testCandidate.primaryEmail}:-`);
});
And
var getData = function() {
this.getCandidateData = function(testObj){
return page.firstname.getAttribute("value").then(function(fname){
testObj.firstName = fname;
});
/*
page.lastname.getAttribute("value").then(function(lname){
testObj.lastName = lname;
});
page.phone.getAttribute("value").then(function(phone){
testObj.mobilePhone = phone;
});
page.email.getAttribute("value").then(function(email){
testObj.primaryEmail = email;
});
*/
};
};
module.exports = new getData();

Related

Use Protractor browser.driver as a variable

I'm using page object model and I'm stuck at how to put the browser.driver elements as a variable.
Here is an example of using it with Protractor's element:
var Messages = function() {};
var messagesLink = element(by.css('a[href*="/Messages"]'));
Messages.prototype.visitPage = function() {
messagesLink.click();
};
exports.Messages = new Messages();
Then I can use Messages.visitPage(); throughout my test. The problem is when I try to do the same thing with browser.driver:
var Login = function() {};
var usernameField = browser.driver.findElement(by.id('UserName'));
var passwordField = browser.driver.findElement(by.id('Password'));
var signOnButton = browser.driver.findElement(by.css('input[value="Sign On"]'));
var registeredUserName = 'user';
var registeredUserPass = 'pass';
Login.prototype.loginAsRegisteredUser = function() {
loginAs(registeredUserName, registeredUserPass);
};
var loginAs = function(userName, pass) {
usernameField.sendKeys(userName);
passwordField.sendKeys(pass);
signOnButton.click();
};
exports.Login = new Login();
The test instantly fails before even starting, throwing this error NoSuchElementError: Unable to locate element: *[id="UserName"]. The reason why I'm using browser.driver is because I'm accessing elements on a non-angular page. I want to try and keep angular and non-angular references separate from each other.
I'm not sure how Protractor handles this but in Selenium I can use the variable like so, static By cancelButton = By.id("cphMain_btnCancel");.
So, is there anyway that this can be done using Protractor?
Spec File:
var home = require('../../pages/home/Home.js').Home;
var headerHome = require('../../pages/home/HeaderHome.js').HeaderHome;
var login = require('../../pages/Login.js').Login;
describe('Registered User | DEV_Smoke |--- Home page: ', function() {
it('Navigates to the Home page', function() {
home.visitPage();
});
it('Prints the current URL (see build.log)', function() {
home.verifyHomeUrl();
});
it('Clicks Sign On link and signs in as a registered user', function() {
headerHome.clickSignOnLink();
login.loginAsRegisteredUser();
});
});
Easiest way would be to just wrap the findElement in functions and call them as needed
var Login = function() {};
var usernameField = function() {
return browser.driver.findElement(by.id('UserName')); //returns promise
}
var passwordField = function() {
return browser.driver.findElement(by.id('Password'));
}
var signOnButton = function() {
return browser.driver.findElement(by.css('input[value="Sign On"]'));
}
var registeredUserName = 'user';
var registeredUserPass = 'pass';
Login.prototype.loginAsRegisteredUser = function() {
loginAs(registeredUserName, registeredUserPass);
};
var loginAs = function(userName, pass) {
usernameField().sendKeys(userName);
passwordField().sendKeys(pass);
signOnButton().click();
};
exports.Login = new Login();
browser.driver is of type Webdriver and when calling findElement, selenium-webdriver will try to evaluate wherever it is stated in your code. So prior to your login method and possibly navigation to the login page, you are automatically looking for the WebElements for UserName, Password, and input[value="SignOn"].
In your code snippet, it looks like you should use element. When using element, at runtime, the findElement will be evaluated. This allows for more reusable code.
For non-angular pages, you might have to provide your own syncing or some arbitrary sleep. This usually occurs with animations, long load screens, etc.
Also make sure you return your promises so the jasmine wrapper evaluates your function properly.
var usernameField = element(by.id('UserName'));
var passwordField = element(by.id('Password'));
var signOnButton = element(by.css('input[value="Sign On"]'));
// make sure you return your promises so the jasmine wrapper
// evaluates your function properly.
var loginAs = function(userName, pass) {
return usernameField.sendKeys(userName).then(() => {
return passwordField.sendKeys(pass).then(() => {
return signOnButton.click();
});
});
};

ProxyConnectionError when connecting as Anonymous

I have developed an operator to retrieve information from Orion Context Broker.
It works perfectly when I'm loggin but if I try to enter as anonymous (with the embedded URL) in a incognito window, the operator raises the next error:
(link to the image): http://i.stack.imgur.com/jxMkr.png
This is the code:
var doInitialSubscription = function doInitialSubscription() {
this.subscriptionId = null;
this.ngsi_server = MashupPlatform.prefs.get('ngsi_server');
this.ngsi_proxy = MashupPlatform.prefs.get('ngsi_proxy');
this.connection = new NGSI.Connection(this.ngsi_server, {
ngsi_proxy_url: this.ngsi_proxy
});
console.log("Send initial subscription");
var types = ['SMARTMETER'];
var entityIdList = [];
var entityId;
entityId = {
id: '.*',
type: 'SMARTMETER',
isPattern: true
};
entityIdList.push(entityId);
var attributeList = null;
var duration = 'PT3H';
var throttling = null;
var notifyConditions = [{
'type': 'ONCHANGE',
'condValues': condValues
}];
var options = {
flat: true,
onNotify: handlerReceiveEntity.bind(this),
onSuccess: function (data) {
console.log("Subscription success ID: "+data.subscriptionId);
this.subscriptionId = data.subscriptionId;
this.refresh_interval = setInterval(refreshNGSISubscription.bind(this), 1000 * 60 * 60 * 2); // each 2 hours
window.addEventListener("beforeunload", function () {
this.connection.cancelSubscription(this.subscriptionId);
}.bind(this));
}.bind(this),
onFailure: function(data) {
console.log(data);
}
};
console.log("Now creating subscription...");
this.connection.createSubscription(entityIdList, attributeList, duration, throttling, notifyConditions, options);
};
Any idea of what is wrong?
According to user comments on the question, updating to Orion 0.19.0 (following the DB upgrade procedure detailed here) solves the problem.

BookshelfJs failing to bring in nested relationship on create

Let's say we have a Join table vehicle_inspections and another join table inspection_actions, as well as basic tables for actions, vehicles, andinspections`.
Lets say I desire the following DB entries:
vehicles
----------------------------
id make
----------------------------
1 Toyota
actions
-------------------------------
id description
-------------------------------
2 Check Tire Pressue
inspections
-------------------------------
id location date
-------------------------------
3 New York tomorrow
vehicle_inspections
--------------------------------
vehicle_id inspection_id
--------------------------------
1 3
inspection_actions
--------------------------------
inspection_id action_id
--------------------------------
3 2
and the following bookshelf classes
inspection_actions.js
(function () {
'use strict';
var Repository = require('../repository');
module.exports = Repository.Model.extend({
tableName: 'inspection_actions',
});
})();
vehicle_inspections.js
(function () {
'use strict';
var Repository = require('../repository');
module.exports = Repository.Model.extend({
tableName = 'vehicle_inspections',
inspection: function () {
return this.belongsTo(require('inspection'));
},
fetchOrCreate: function(vehicleId, inspectionId, options) {
var self = this;
return self.query(function (qb) {
qb.where({
vehicle_id: vehicleId,
inspection_id: inspectionId
});
)}.fetch(options || {}).then(function (model) {
if (!model) {
model.save({
vehicle_id: vehicleId,
inspection_id: inspectionId
});
return model;
};
}
};
});
inspection.js
...
module.exports = Repository.Model.extend(_.extend({
tableName: 'inspections',
actions: function () {
return this.hasMany(require('./inspection-action'));
}
}));
And a route:
new VehicleInspection().fetchOrCreate(req.params.vehicle_id, req.params.inspection_id, {withRelated: ['inspection.actions']})
.then(function (vehicleInspection) {
var inspection = vehicleInspection.related('inspection');
console.log( inspection);
console.log(inspection.related(actions);
})
The inspection console log prints out the correct inspection, however, irrelevantly of what is in the database the second console.log prints out an empty result
{ length: 0,
models: [],
_byId: {},
...
targetIdAttribute: 'id',
foreignKey: undefined,
parentId: undefined,
parentTableName: 'tasks',
parentIdAttribute: 'id',
parentFk: undefined } }
This "bad" behaviour only occurs the first time a projectTasks entry is being created. What appears to be happening is that the inspection_action table is not being populated through the nested withRelated. How could I get this working nested create working?
I'm not completely clear what you are trying to achieve, but here is how I would generally set things up. First I'd create a base model (assuming its saved as base.js), I think you are going to have some problems with circular dependencies, so using the Bookshelf registry plugin would be good:
var config = {
client: // whatever client you are using,
connection: // url to your database
};
var db = require('knex')(config);
var Bookshelf = require('bookshelf')(db);
var Base = Bookshelf.Model.extend({
// Put anything here that will be helpful for your use case
});
Bookshelf.plugin('registry');
Base.model = Bookshelf.model.bind(Bookshelf);
module.exports = Base;
Next create your Vehicle model:
require('inspection');
require('action');
var Base = require('base');
var Vehicle = Base.Model.extend({
tableName = 'vehicles',
inspections: function () {
return this.belongsToMany('Inspection',
'inspections_vehicles', 'vehicle_id', 'inspection_id');
},
actions: function() {
return this.belongsToMany('Action',
'actions_vehicles', 'vehicle_id', 'action_id');
}
};
module.exports = Base.model('Vehicle', Vehicle);
Then an inspection model:
require('vehicle');
var Base = require('base');
var Inspection = Base.Model.extend({
tableName = 'inspection',
vehicles: function () {
return this.belongsToMany('Vehicle',
'inspections_vehicles', 'inspection_id', 'vehicle_id');
}
};
module.exports = Base.model('Inspection', Inspection);
Finally an action model:
var Base = require('base');
var Action = Base.Model.extend({
tableName = 'actions',
};
module.exports = Base.model('Action', Action);
Now assuming that the database isn't already filled in with the data you supplied, we can populate it:
var Inspection = require('inspection');
var Vehicle = require('vehicle');
var Action = require('action');
var toyota;
var newYorkInspection
Vehicle.forge().save({name: 'Toyota'})
.then(function(vehicle) {
toyota = vehicle;
return Inspection.forge().save({location: 'New York', date: 'Tomorrow'});
}).then(function(inspection){
newYorkInspection = inspection;
return toyota.inspections().attach(newYorkInspection);
}).then(function() {
return Action.forge().save({description: 'Check Tire Pressure'});
}).then(function(tirePressureAction) {
return toyota.actions().attach(tirePressureAction);
});
Now I can fetch the toyota vehicle with the related actions and inspections:
var Vehicle = require('vehicle');
return Vehicle.forge({'name': 'Toyota'}).fetch({
withRelated: ['inspections', 'actions']
}).then(function(toyota){
var toyotaInspections = toyota.related('inspections');
var toyotaActions = toyota.related('actions');
});

Mootools Class - Calling a function within a function

I'm learning Mootools classes at the moment and there's something that I can't seem to get my head around or find a decent example.
Basically, I need to be able to call a function within a different function of the same class; example below:
var Bob = new Class({
initialize: function () {
this.message = 'Hello';
},
someOther: function() {
this.message2 = 'Bob';
},
getMessage: function() {
return this.someOther();
},
});
window.addEvent('domready', function() {
var map = new Bob;
alert(map.getMessage());
});
From this code, I would have thought that the alert would produce 'Bob' which has been set in the function 'someOther' but it's outputting a undefined message.
Can anyone help or point out where I'm going wrong?
Thanks in advance,
er not quite.
someOther has no return value in itself, it's a setter. you invoke it and it will set this.message2 into the class but it returns nothing. methods should return this (the instance, so making it chainable) or a value, when a getter.
anyway, you can make it set the property and return it like so:
var Bob = new Class({
initialize: function() {
this.message = 'Hello';
},
someOther: function() {
return this.message2 = 'Bob'; //bad
},
getMessage: function() {
return this.someOther(); // why
},
});
window.addEvent('domready', function() {
var map = new Bob;
alert(map.getMessage());
alert(map.message2); // bob
});
though, semantically, you want to have 1 getter. .getMessage should just return this.message - you can write a different method that calls someOther and returns it.
have a look at this pattern for a getter/setter in a class context I wrote the other day:
http://fragged.org/using-overloadsetter-overloadgetter-to-make-flexible-functions-in-mootools_1451.html
etc etc. for more help, look at the keetology blogs or davidwalsh.name - or the mootorial - plenty of examples of class use and structure.
most key ones are listed here: https://stackoverflow.com/tags/mootools/info

Is there a nodejs module or example of how to make GridFS files accessible with WebDAV?

I have an existing node.js app where users have a library of files that are stored with GridFS. Each user has their own library. I would like to make the library mountable with WebDAV so that a user could manage their library from their desktop.
I have seen jsDAV used to access the filesystem but it is not clear how to extend it for use with a virtual file system. I found gitDav but it is not clear how to use it.
Is this even possible without starting from scratch?
I was looking to use jsDAV to make some resources available through WebDAV. Failing to find a working example, I studied the comments in the source and wrote one myself. jsDAV is a port from a PHP library. The Sabre manual is useful guide in general. One thing to remember is that since we're in an asynchronous environment, functions that return the results in PHP might have to invoke a callback function instead. This usually happens when the operation in question involves reading from the disk. The first parameter to the callback will always be an error object, which should be null when all goes well.
'use strict';
var crypto = require('crypto');
var jsDAV = require("jsDAV/lib/jsdav");
var jsDAVLocksBackendFS = require("jsDAV/lib/DAV/plugins/locks/fs");
var jsDAVFile = require("jsDAV/lib/DAV/file");
var jsDAVCollection = require("jsDAV/lib/DAV/collection");
var jsExceptions = require("jsDAV/lib/shared/exceptions");
var VirtualFile = jsDAVFile.extend(
{
initialize: function(name, buffer) {
this.name = name;
this.buffer = buffer;
},
getName: function() {
return this.name;
},
get: function(callback) {
callback(null, this.buffer);
},
put: function(data, type, callback) {
callback(new jsExceptions.Forbidden("Permission denied to change data"));
},
getSize: function(callback) {
callback(null, this.buffer.length);
},
getETag: function(callback) {
var shasum = crypto.createHash('sha1');
shasum.update(this.buffer);
var etag = '"' + shasum.digest('hex') + '"';
callback(null, etag);
},
getContentType: function(callback) {
callback(null, 'text/plain');
}
});
var VirtualDirectory = jsDAVCollection.extend(
{
initialize: function(name, children) {
this.name = name;
this.children = children;
},
getChildren: function(callback) {
var list = [];
for (var name in this.children) {
list.push(this.children[name]);
}
callback(null, list);
},
getChild: function(name, callback) {
var child = this.children[name];
if (child) {
callback(null, child);
} else {
callback(new jsExceptions.NotFound("File not found"));
}
},
childExists: function(name, callback) {
var exists = (this.children[name] !== undefined);
callback(null, exists);
},
getName: function() {
return this.name;
}
});
var children = {};
for (var i = 1; i <= 10; i++) {
var name = 'file' + i + '.txt';
var text = 'Hello world, #' + i;
children[name] = VirtualFile.new(name, new Buffer(text, 'utf8'));
}
var grandchildren = {};
for (var i = 66; i <= 99; i++) {
var name = 'beer' + i + '.txt';
var text = i + ' bottles of beer';
grandchildren[name] = VirtualFile.new(name, new Buffer(text, 'utf8'));
}
children['folder'] = VirtualDirectory.new('folder', grandchildren);
var root = VirtualDirectory.new(null, children);
var options = {
node: root,
locksBackend: jsDAVLocksBackendFS.new(__dirname + "/data")
};
var port = 8000;
jsDAV.createServer(options, port);
It looks like jsDAV is the only option. It is a port of a PHP library and it is not setup in such a way that you can use it like a normal node.js module. I found a few examples of server types that others have created to connect it with dropbox and couchdb.
I am now working on a server type that will work more like you would expect a node.js module to work. The next step will be making it play nice with npm. You can see my fork here.