Reputation: 627
I try to extend ElementFinder library. I wondering how I can require different methods with the same names? I want to make something like:
// spec.js
var ef1 = require('./ef_extend1.js');
var ef2 = require('./ef_extend2.js');
expect(column_resizer.ef1.getWidth()).toEqual(18);
expect(column_resizer.ef2.getWidth()).toEqual(18);
Now I have an error:
TypeError: Cannot read property 'getWidth' of undefined
My required libraries:
// ef_extend1.js
var ElementFinder = $('').constructor;
ElementFinder.prototype.getWidth = function() {
return this.getSize().then(function(size) {
return size.width + 1;
});
};
And the second one:
// ef_extend2.js
var ElementFinder = $('').constructor;
ElementFinder.prototype.getWidth = function() {
return this.getSize().then(function(size) {
return size.width;
});
};
Upvotes: 4
Views: 636
Reputation: 13309
I guess you've used a solution from Protractor issue #1102, but now it can be accomplished a bit easier after PR#1633, because ElementFinder
is now exposed in protractor
global variable:
protractor.ElementFinder.prototype.getWidth = function () {
return this.getSize().then(function (size) {
return size.width;
});
};
expect($('body').getWidth()).toBe(100);
Update:
As I said in the comment, ElementFinder
can only be extended again and again. If you already had a method getWidth
, and you extend ElementFinder
with one more getWidth
implementation, then the first one will be overriden, there should not be any conflict. But you'll have to keep them in strict order depending on when do you want to use appropriate set of methods:
require('./ef_extend1.js');
expect(column_resizer.getWidth()).toEqual(18);
require('./ef_extend2.js');
expect(column_resizer.getWidth()).toEqual(18);
Actually I've came with some alternative approach, but I do not think it will be nice to use, but anyway. Here is a sample module with extension methods:
// ef_extend1.js
// shortcut
var EF = protractor.ElementFinder;
// holds methods you want to add to ElementFinder prototype
var extend = {
getWidth: function () {
return this.getSize().then(function (size) {
return size.width;
});
}
};
// will hold original ElementFinder methods, if they'll get overriden
// to be able to restore them back
var original = {};
// inject desired methods to prototype and also save original methods
function register() {
Object.keys(extend).forEach(function (name) {
original[name] = EF.prototype[name]; // save original method
EF.prototype[name] = extend[name]; // override
});
}
// remove injected methods and return back original ones
// to keep ElementFinder prototype clean after each execution
function unregister() {
Object.keys(original).forEach(function (name) {
if (typeof original[name] === 'undefined') {
// if there was not such a method in original object
// then get rid of meaningless property
delete EF.prototype[name];
} else {
// restore back original method
EF.prototype[name] = original[name];
}
});
original = {};
}
// pass a function, which will be executed with extended ElementFinder
function execute(callback) {
register();
callback();
unregister();
}
module.exports = execute;
And you will use them like that, being able to run protractor commands in "isolated" environments, where each of them has it's own set of methods for ElementFinder
:
var ef1 = require('./ef_extend1.js');
var ef2 = require('./ef_extend2.js');
ef1(function () {
expect(column_resizer.getWidth()).toEqual(18);
});
ef2(function () {
expect(column_resizer.getWidth()).toEqual(18);
});
I'm not quire sure about it, maybe I am over-engineering here and there are solutions much easier than that.
Upvotes: 5