I am using Protractor with pageObject concept to do e2e testing.
However, I have difficulties to understand why creating new objects is needed for each pageObject?
Show you my question by code
Currently, I define the pageObject in pageObj.js as
var PageObj = function () {
this.method1 = function() { //whatever content };
}
module.exports = PageObj;
and invoking it in test spec file as
var PageObj = require('./pageObject/pageObj.js');
var pageObj = new PageObj();
//use pageObj's method here;
pageObj.method1();
However, I think this way below is simpler, why shouldn't I use this?
Define the same method in pageObj.js
```
module.exports = {
method1: function() {
//whatever content;
},
Invoke it as
var pageObj = require('./pageObject/pageObj.js');
//use pageObj's method here;
pageObj.method1();
Sometimes you might have multiple tests using the same page object and you might want to store there data representing current or changing state of page during one test or suite of tests. Using it as a class/constructor function allows you to have a clear state between every test.
If your take works for you for now and the future and doesn't limit you it's completely fine, just for these more complex cases you might need to have to use instanced page objects to achieve what you need.
At our company we prefer to stick to one pattern to not have to adjust to use page object as an object here and as constructor function there. So to keep it more uniform across our tests we just follow the recommended style + this pattern has already settled and it's easier to switch between projects if they follow the same guidelines.
As #Tom mentions, using an object literal is fine, but can be limiting. I use them if I don't have to extend other pages (eg. a basePage). I also feel like instantiating page objects in the spec is a bit clunky, so I opt for a solution somewhere in between..
var PageObj = function() {
this.method1 = function() { //whatever content };
};
module.exports = new PageObj();
And then your spec...
var pageObj = require('./pageObject/pageObja ');
//use pageObj's method here;
pageObj.method1();
Related
Given that I'm extending an existing module and it uses the module.exports in the way shown below, can I even call the start methods from (mocha) tests?
I suspect that there's no decent way to tap into it - and that's ok. I'd just rather test these if I am able to and would love to know how to do it if possible.
const NodeHelper = require("node_helper");
module.exports = NodeHelper.create({
start: function() {
//do stuff
};
});
Edit: NodeHelper returns a function that appears to be "extended":
NodeHelper.create = function(moduleDefinition) {
return NodeHelper.extend(moduleDefinition);
};
Looking closer at the linked code, it uses Resig's class.js so you probably need to create an instance to call the prototype methods, ie
const YourNodeHelper = require('path/to/your/module')
const yourNodeHelper = new YourNodeHelper() // create instance here
yourNodeHelper.start()
I am trying to find best way how to create multiple instances and configure my module according Module pattern.
Currently I have
var Logger = (function () {
// Private members
var _settings = {
json: JSON,
output: console
};
// Private methods
var _log = function (info) {
_settings.output.log(info);
};
var _dump = function (info) {
_log(_settings.json.stringify(info));
};
// Change default settings
var changeSettings = function (settingsArgs) {
if (settingsArgs !== undefined) {
if (settingsArgs.json !== undefined) {
_settings.json = settingsArgs.json;
}
if (settingsArgs.output !== undefined) {
_settings.output = settingsArgs.output;
}
}
};
return {
init: changeSettings,
log: _log,
dump: _dump
};
})();
I have several questions about this pattern.
What is the best way to provide configuration to the module, I simply created setter for private settings fields, but I feel this is not the best way it can be implemented. Please suggest right approach.
How to create multiple instances of my module. As I understood, module commonly used to encapsulate global objects and logic (like singletons), so most of time only one instances of module exists, but I need to have multiple instances. In my case this can be useful for example, I can create one logger ConsoleLogger another one will be AlertLogger the difference is output, but now I can only have one instance.
Please suggest the right way to follow, I have already read a lot of articles but haven't found answers to my questions. Thanks
What you have there is Module used as an Immediately-Invoked-Function-Expressions (IIFE), because of () at the end. Therefor, you are creating instance at class definition time and you can only have a single instance. You could clone one instance and have multiple of them, but that is not a good thing to do.
If you want to have multiple instances, you should remove IIFE expression at the end. Also, you can pass settings as constructor param:
var Logger = function (settingsArgs) {};
Now, you can create multiple instances:
var consoleLogger = new Logger({output: console});
var alertLogger = new Logger({output: alert}); // change this line probably, for this to work _settings.output.log(info);
Thus far I've worked only with relatively small projects (and mostly alone), but this time I have to collaborate with other programmers... basically because of that I must plan the structure of the website very carefully for the avoidance of spending hours debugging the code.
At this point I suppose doing that in the following manner. I divide my code in modules and store each module in a separate file inside an object (or a function) with a made-up name (lzheA, lzheB, lzheC etc.) to avoid conflicts whether an object with the same name was used in an another piece of code. When the document is loaded, I declare a variable (an object) that I use as a main namespace of the application. Properties of the object are the modules I defined before.
// file BI.lib.js
var lzheA = {
foo: function() {
},
bar: function() {
},
}
// file BI.init.js
function lzheK() {
BI.loadPage();
}
// file BI.loadPage.js
function lzheC() {
var result = document.getElementById('result');
result.innerHTML = "that worked";
}
// and so on
var lzheA,lzheB,lzheD,lzheE,lzheF,lzheG,lzheH,lzheI,lzheJ;
// doing the following when the document is loaded
var BI = {
lib: lzheA,
menu: lzheB,
loadPage: lzheC,
customScripts: lzheD,
_index: lzheE,
_briefs: lzheF,
_shop: lzheG,
_cases: lzheH,
_blog: lzheI,
_contacts: lzheJ,
init: lzheK,
}
BI.init();
https://jsfiddle.net/vwc2og57/2/
The question... is this way of structuring worth living or did I miss something because of lack of experience? Would the made-up names of the modules confuse you regardless of the fact that each one used only twice - while declaring the variable and assigning it to a property?
I consider the namespaces a good option when you want to modularize applications in Javascript. But I declare them in a different way
var myModule = myModule || {}; // This will allow to use the module in other places, declaring more than one specificComponent in other js file for example
myModule.specificComponent = (function(){
// Private things
var myVar = {};
var init = function() {
// Code
};
return {
init: init // Public Stuff
};
})();
If you want to call the init method, you would call it like this
myModule.specificComponent.init();
With this approach, i guarantee that the module will not be overwritten by another declaration in another place, and also I can declare internal components into my namespaces.
Also, the trick of just exposing what you want inside the return block, will make your component safer and you will be encapsulating your code in a pretty way.
Hope it helps
Quite a large portion of my work day to day involves working with Dynamics CRM and writing JS to extend the functionality on the forms.
Most clientside interaction in Dynamics involves using an object provided for you when the form loads, which is just Xrm. So you might have something like:
function OnLoad() {
Xrm.Page.getAttribute('name').setValue('Stackoverflow!');
var x = Xrm.Page.getAttribute('name').getValue();
}
I tend to write a wrapper for the Xrm object, mainly because it is a lot easier than remembering some of the chaining and end up with something like:
function WrappedXrm(realXrm) {
var xrm = realXrm;
this.getValue(name) {
return xrm.getAttribute(name).getValue();
}
}
//and then use it as so
var myXrm = new FakeXrm(Xrm);
var myXrmValue = myXrm.getValue('Name');
I am trying out QUnit and wondering how would I go about unit testing in this scenario?
Obviously the example above is a single line, it might not be worth testing it. But assume there was some business logic there that I wanted to test.
The only way I can see is doing some set up before each test along the lines of
var fakeXrm = {};
fakeXrm.Page = {};
fakeXrm.Page.getAttribute = function(name) {
var tempAttr = {};
tempAttr.getValue = function() {
return 'A fake value';
}
}
And then testing on 'A fake value' being returned, but this doesn't 'feel' right to me at all.
Where am I going wrong?
Using Mocks
So in this case, you want to create an instance of WrappedXrm, and pass it an object that mocks the Xrm from your lib ; you need a mock of Xrm.
A first alternative is to write it like you did (which is perfectly valid, if you know what the interface of Xrm is.)
Some libraries like sinon.js or "spies" in the jasmine framework can help you write code like ;
create a 'mock' Xrm, to configure what it should return
create an instance of WrappedXrm with this mock
call the getValue method of WrappedXrm
check that some method was called on the mock
But in the case of javascript, simply created a object that has just the right properties might be okay.
Note that your tests would break if the structure of the "real" Xrm object changes ; that might be what bother's you, but that's always the risk with mocks...
Using the real implementation
If you don't want to test against a mock (which might make sense in case of a wrapper), then maybe you can write the mimimal code that would create an actual Xrm object in your qunit html page (Maybe hardcoding markup ? I don't know the library, so...)
Hoping this helps.
I'm trying to write 'better' javascript.
Below is one pattern I've found, and am trying to adopt. However, I'm slightly confused about its use.
Say, for example, I've got a page called "Jobs". Any JS functionality on that page would be encapsulated in something like:
window.jobs = (function(jobs, $, undefined){
return {
addNew: function(){
// job-adding code
}
}
})(window.jobs|| {}, jQuery);
$(function(){
$('.add_job').on('click', function(event){
event.preventDefault();
window.jobs.addNew();
});
});
As you can probably deduct, all I've done is replaced all the code that would have sat inside the anonymous event-handler function, with a call to a function in my global jobs object. I'm not sure why that's a good thing, other than it's reduced the possibility of variable collisions and made the whole thing a bit neater, but that's good enough for me.
The - probably fairly obvious - question is: all my event-binding init-type stuff is still sitting outside my shiny new jobs object: where should it be? Inside the jobs object? Inside the return object inside the jobs object? Inside an init() function?
I'm just trying to get a sense of a stable, basic framework for putting simple functionality in. I'm not building JS apps, I'd just like to write code that's a little more robust and maintainable than it is currently. Any and all suggestions are warmly welcomed :)
You can break down your application in whatever number of modules / objects you like too.
For instance, you can have another object / module which caches and defines all your DOM nodes and another one, which just handles any event. So for instance:
(function ( win, doc, $, undef ) {
win.myApp = win.myApp || { };
var eventHandler = {
onJobClick: function( event ) {
event.preventDefault();
myApp.addNew();
}
};
var nodes = (function() {
var rootNode = $( '.myRootNode' ),
addJob = rootNode.find( '.add_job' );
return {
rootNode: rootNode,
addJob: addJob
};
}());
$(function() {
myApp.nodes.addJob.on( 'click', myApp.handler.onJobClick );
});
myApp.nodes = nodes;
myApp.handler = eventHandler;
}( this, this.document, jQuery ));
It doesn't really matter how you create singletons in this (module) pattern, either as literal, constructor, Object.create() or whatnot. It needs to fit your requirements.
But you should try to create as many specific modules/objects as necesarry. Of course, if makes even more sense to separate those singletons / modules / objects into multiple javascript files and load them on demand and before you can say knife, you're in the world of modular programming patterns, dealing with requireJS and AMD or CommonJS modules.
Encapsulation-wise, you're fine: you could even just declare addNew in the jQuery closure and you'd still avoid the global scope. I think what you're getting at is more of implementing something close to an MVC architecture.
Something I like to do is create an object that you instantiate with a DOM element and that takes care of its own bindings/provides methods to access its controls etc.
Example:
// (pretend we're inside a closure already)
var myObj = function(args){
this.el = args.el; // just a selector, e.g. #myId
this.html = args.html;
this.bindings = args.bindings || {};
}
myObj.prototype.appendTo = function(elem){
elem.innerHTML += this.html;
this.bindControls();
};
myObj.prototype.remove = function(){
$(this.el).remove(); // using jQuery
};
myObj.prototype.bindControls = function(){
for(var i in this.bindings){ // event#selector : function
var boundFunc = function(e){ return this.bindings[i].call(this,e); };
$(this.el).on(i,boundFunc);
}
};
The way you are doing it right now is exactly how I do it also, I typically create the window objects inside the anonymous function itself and then declare inside that (in this case: jClass = window.jClass).
(function (jClass, $, undefined) {
/// <param name="$" type="jQuery" />
var VERSION = '1.31';
UPDATED_DATE = '7/20/2012';
// Private Namespace Variables
var _self = jClass; // internal self-reference
jClass = window.jClass; // (fix for intellisense)
$ = jQuery; // save rights to jQuery (also fixes vsdoc Intellisense)
// I init my namespace from inside itself
$(function () {
jClass.init('branchName');
});
jClass.init = function(branch) {
this._branch = branch;
this._globalFunctionality({ globalDatePicker: true });
this._jQueryValidateAdditions();
//put GLOBAL IMAGES to preload in the array
this._preloadImages( [''] );
this._log('*******************************************************');
this._log('jClass Loaded Successfully :: v' + VERSION + ' :: Last Updated: ' + UPDATED_DATE);
this._log('*******************************************************\n');
};
jClass._log = function() {
//NOTE: Global Log (cross browser Console.log - for Testing purposes)
//ENDNOTE
try { console.log.apply(console, arguments); }
catch (e) {
try { opera.postError.apply(opera, arguments); }
catch (e) { /* IE Currently shut OFF : alert(Array.prototype.join.call(arguments, ' '));*/ }
}
};
}(window.jClass= window.jClass|| {}, jQuery));
The reason I leave them completely anonymous like this, is that let's say in another file I want to add much more functionality to this jClass. I simply create another:
(function jClass, $, undefined) {
jClass.newFunction = function (params) {
// new stuff here
};
}(window.jClass = window.jClass || {}, jQuery))
As you can see I prefer the object.object notation, but you can use object literals object : object, it's up to you!
Either way by leaving all of this separate, and encapsulated without actual page logic makes it easier to have this within a globalJS file and every page on your site able to use it. Such as the example below.
jClass._log('log this text for me');
You don't want to intertwine model logic with your business logic, so your on the right path separating the two, and allowing for your global namespace/class/etc to be more flexible!
You can find here a comprehensive study on module pattern here: http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html It covers all the aspects of block-scoped module approach. However in practice you gonna have quite a number files encapsulating you code, so the question is how to combine them property. AMD... multiple HTTP requests produced by every module loading will rather harm your page response time. So you can go with CommonJS compiled to a single JavaScript file suitable for in-browser use. Take a look how easy it is http://dsheiko.github.io/cjsc/