Using elements within API functions in Nightwatch JS - javascript

I have a page object and am creating a command for use in my test file. When I use a WebDriver API command like .elements(), the elements that I created are not passed through and cannot be used in the callback function.
Example code:
var commands = {
command1: function () {
var element1 = "div.some-class"; //I end up doing this
this.api
.elements("css selector", "#element1", function (result) {
return this
.click("#element2");
})
}
}
module.exports = {
url: function() {
return this.launchUrl;
},
elements: {
element1: "div.some-class",
element2: "h2[id=some-id]"
},
commands: [commands]
}
I have noticed that calling .api makes it so you cannot use elements, but is there any way around this? I have been making variables for each of my commands, but I feel like that defeats the purpose of having elements.

to make it more generic inside a custom function u can use:
var objectSelector = this.page.pageobject.elements[elementName]
it should return element1 css: div.some-class
if i gona think about better solution will post it here in a comment

Related

access callback response data from Ajax using Javascript Revealing Prototype Pattern

I am trying to structurise JS code using Revealing Prototype Pattern.
My basic usecase is: Create different types of entities like Person, Technology. Each entity has its own tags. In order to get these tags i make an ajax call which returns an object of tags. I want to access this object in my implementation. But i am not sure how to do it in right way.
My attempt is as follows:
var Entity= function (url) {
this.url = url; /*variable that can be shared by all instances*/
var entityTags;
};
Entity.prototype = function () {
var create = function (type, values) {
//code for creating
}
var update = function (type, values) {}
var tags = function () {
AjaxCall(' ', this.url, {data:data}, 'callbackAfterGetTags', '');
callbackAfterGetTags=function(responseFromAjax)
{
entityTags=responseFromAjax.tagsReturned; //how to access this entityTags in my implementation
}
};
return {
createEntity: create,
getTagsEntity: tags
};
My Implementation
var myEntity = new Entity(url);
myEntity.getTagsEntity();
Ajax call returns object successfully but i am not sure how to access the object inside tags functions in a right way. Any suggestions? This is my first trial to use OO style in JS. Let me also know if i am right track or not.

Best way to perform JavaScript code on specific pages/body class?

I know there are libraries made for this, such as require.js, but I don't want anything complicated. I just want to run JS code that runs when there is a specific class on the body.
My try at this was to create functions for each page code, and a function to check if the body has the class name to execute code, then run it.
var body = $('body');
initPageOnClass('.home', initFrontPage());
function initPageOnClass(className, func) {
if (body.hasClass(className)) {
return func;
}
}
function initFrontPage(){
// some code for the frontpage
}
Which works, but I fear this may be bad practice. Is it? I know the more pages there is, there will be more functions:
initPageOnClass('.home', initAboutPage());
initPageOnClass('.subscriptions', initSubscriptionPage());
initPageOnClass('.team', initTeamPage());
But I'm not sure if this would be a big no, or what. I want to do this properly.
What is the correct or best way to perform this task?
Id rather use some attribute in this case and map of functions. Your markup will have role attribute defined:
<body role=home>...</body>
And the script may look like:
var initMap = {
'home':initAboutPage,
'subscriptions': initSubscriptionPage,
'team': initTeamPage };
// getting initializer function by content of 'role' attribute
var initializer = initMap[ $('body').attr('role') ] || initAboutPage;
initializer();
And yet check my spapp - it's quite simple (60 LOC)
I think you're on the right path, but not quite executing properly and if you're going to have a bunch of different classes/functions that you check for, then I'd suggest a table driven approach, so you can maintain it by just adding/removing/modifying items in the table rather than writing new code:
var bodyClassList = {
"home": initFrontPage,
"subscriptions": initSubscriptionPage,
"team": initTeamPage
};
function runBodyInit() {
var body = $(document.body);
$.each(bodyClassList, function(cls, fn) {
if (body.hasClass(cls) {
// if class found, execute corresponding function
fn();
}
});
}
runBodyInit();
Or, if you're doing this on document.ready, then you might do this:
$(document).ready(function() {
var bodyClassList = {
"home": initFrontPage,
"subscriptions": initSubscriptionPage,
"team": initTeamPage
};
var body = $(document.body);
$.each(bodyClassList, function(cls, fn) {
if (body.hasClass(cls) {
// if class found, execute corresponding function
fn();
}
});
});

Structure application by using jQuery

I am going to build an application as it is not too much rich otherwise I can use angularjs for that purpose. I wanted to organize my JS code into proper modular programming approach.
E.g
var SignUpModule = {
elem: $('#id'), // unable to access jquery object here
init: function (jQuery) {
alert(jQuery('.row').html());
}
};
var application = {
modules: [],
addModule: function (module) {
this.modules.push(module);
},
run: function (jQuery) {
_.each(this.modules, function (module) {
//Iterate each module and run init function
module.init(jQuery);
});
}
}
jQuery(document).ready(function () {
application.addModule(SignUpModule);//add module to execute in application
application.run(jQuery);//Bootstrap application
});
Please now look at it I have updated my question with actual code
The biggest mistake you've done is using anonymous first parameter of an anonymous function taken by $.each method. The first argument is just index, and the second argument is an element you were looking for. Below you can find working code.
And no, you don't need to pass jQuery object everywhere. It's global. It already is everywhere. You can see it in the code below.
var SignUpModule = {
elem: $('.row'), //jQuery works fine here
init: function () {
alert(this.elem.html());
}
};
var application = {
modules: [],
addModule: function (module) {
this.modules.push(module);
},
run: function () {
$.each(this.modules, function (index, module) { //this function takes 2 parameters
//Iterate each module and run init function
module.init();
});
}
}
//document.ready
$(function () {
application.addModule(SignUpModule);//add module to execute in application
application.run();//Bootstrap application
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row">alert <b>me!</b></div>

Async, Callbacks, and OOP JavaScript: how do I organize this?

I'm building a plugin that fetches info for a bunch of images in JSON, then displays them in some dialog for selection. Unfortunately, my first intuition pretty clearly results in a race condition:
var ImageDialog = function () {};
ImageDialog.prototype.items = [];
ImageDialog.prototype.fetch_images() {
var parse_images = function(data) {
// Magically parse these suckers.
data = awesome_function(data);
this.items = data;
};
magicalxhrclass.xhr.send({"url": 'someurl', "success": parse_images, "success_scope": this});
}
ImageDialog.prototype.render = function () {
this.fetch_images();
// XHR may or may not have finished yet...
this.display_images();
this.do_other_stuff();
};
var monkey = new ImageDialog();
monkey.render();
Off of the top of my head, I think I could fix this by changing the parse_images callback to include the rest of the render steps. However, that doesn't look quite right. Why would the fetch_images method be calling a bunch of things about displaying images?
So: what should I do here?
I am pretty certain deferreds would help, but alas: I need to write this without any external libraries. :(
Comments on other code smells would be nice, too!
In general, the basic idea you can use is that when a regular program would use a return statement (meaning, "My function is done now do your job!") an asynchronous continuation-passing program would instead use a ballcabk function that gets explicitly called
function fetch_images(callback){
magicalXHR({
success: function(data){
parse_images(data);
callback(whatever);
}
}
}
or, if parse_images is itself an async function:
parse_images(data, callback)
Now when you call fetch_images the code after it goes into a callback instead of assuming that fetch_images will be done when it returns
fetch_images(function(
display_images()
})
By using callbacks you can emulate pretty well what a traditional program could do (in fact its a fairly mechanical translation between one form of the other). The only problem you will now encounter is that error handling gets tricky, language features like loops don't play well with async callbacks and calbacks tend to nest into callback hell. If the callbacks start getting too complex, I would investigate using one of those Javascript dialects that compiles down to continuation-passing-style Javascrit (some of them work without needing extra libraries at runtime).
How about this?
var ImageDialog = function () {
this.items = []; // just in case you need it before the images are fetched
};
ImageDialog.prototype.fetch_images(callback) {
var that = this;
function parse_images (data) {
// Magically parse these suckers.
data = awesome_function(data);
that.items = data;
callback.apply(that);
};
magicalxhrclass.xhr.send({"url": 'someurl', "success": parse_images, "success_scope": this});
}
ImageDialog.prototype.render = function () {
this.fetch_images(function(){
this.display_images();
this.do_other_stuff();
});
};
var monkey = new ImageDialog();
monkey.render();
Here's a thought about what to do.
ImageDialog.prototype.fetch_images() {
var parse_images = function(data) {
// Magically parse these suckers.
data = awesome_function(data);
this.items = data;
fetch_images.caller() // Unfortunately, this is nonstandard/not in the spec. :(
};
magicalxhrclass.xhr.send({"url": 'someurl', "success": parse_images, "success_scope": this});
}
ImageDialog.prototype.render = function () {
if (this.items === []) {
this.fetch_images()
return;
} else {
this.display_images();
this.do_other_stuff();
};
};
This way I'm not passing some implementation detail to fetch_images, and I get caching, to boot. Am I still trying too hard to escape CPS, or is this sensible?

Passing collection.fetch as a named function to collection.bind does not work

I have two Backbone collections. I want to bind to the reset event one one. When that event is fired, I want to call fetch on the second collection, like so:
App.collections.movies.bind("reset", App.collections.theaters.fetch);
The second fetch never fires though. However, if I pass an anonymous function that calls theaters.fetch, it works no problem:
App.collections.movies.bind("reset", function () { App.collections.theaters.fetch(); });
Any idea why this might be the case?
Heres my full code. I'm not showing any of the models or collections, because it's a lot of code, but let me know if you think that might be the source of the problem:
var App = {
init: function () {
App.collections.theaters = new App.Theaters();
App.collections.movies = new App.Movies();
App.events.bind();
App.events.fetch();
},
events: {
bind: function () {
App.collections.theaters.bind("reset", App.theaterManager.assign);
App.collections.movies.bind("reset", function () { App.collections.theaters.fetch(); });
},
fetch: function () {
App.collections.movies.fetch();
}
},
collections: {},
views: {},
theaterManager: {
// Provide each model that requires theaters with the right data
assign: function () {
// Get all theaters associated with each theater
App.theaterManager.addToCollection("theaters");
// Get all theaters associated with each movie
App.theaterManager.addToCollection("movies");
},
// Add theaters to a collection
addToCollection: function (collection) {
App.collections[collection].each(function (item) {
item.theaters = App.theaterManager.getTheaters(item.get(("theaters")));
});
},
// Returns a collection of Theaters models based on a list of ids
getTheaters: function () {
var args;
if (!arguments) {
return [];
}
if (_.isArray(arguments[0])) {
args = arguments[0];
} else {
args = Array.prototype.slice.call(arguments);
}
return new App.Theaters(_.map(args, function (id) {
return App.collections.theaters.get(id);
}));
}
}
};
$(function () {
App.init();
});
This all has to do with function context. It is a common confusion with the way functions are called in Javascript.
In your first way, you are handing a function to be called, but there is no context defined. This means that whoever calls it will become "this". It is likely that the equivalent will be of calling App.collections.movies.fetch() which is not what you want. At least, I am guessing that is what the context will be. It is difficult to know for sure... it might be jQuery, it might be Backbone.sync. The only way to tell is by putting a breakpoint in the Backbone.collections.fetch function and print out the this variable. Whatever the case, it won't be what you want it to be.
In the second case, you hand it a function again but internally, you specify the context in which the function is called. In this case, fetch gets called with App.collections.theaters as the context.
... was that clear?

Categories

Resources