I trying to run standart example from Protractor's documentation ( http://angular.github.io/protractor/#/api?view=ProtractorBy.prototype.addLocator ). And have an Error: 'Cannot read property 'querySelectorAll of null'
by.addLocator('buttonTextSimple',
function(buttonText, opt_parentElement, opt_rootSelector ) {
var using = opt_parentElement,
buttons = using.querySelectorAll('button');
return Array.prototype.filter.call(buttons, function(button) {
return button.textContent === buttonText;
});
});
View the same:
<button ng-click="doAddition()">Go!</button>
What I should do to solve this problem?
You should declare a variable called using like this:
var using = opt_parentElement || document;
so if there is no optional parent element provided, then global document will be used to query for results.
Not sure if it is a typo in the documentation or Protractor was expected to auto-fill opt_parentElement variable with some defaults if it is not being set.
Related
Here is JS function. this function is an event handler for a checkbox. so the element is the checkbox.
function updateSelect(element) {
// this works
document.getElementById("file_update_" + 1).disabled = !element.checked;
// this does not works. the element.value is also 1
document.getElementById("file_update_" + element.value).disabled = !element.checked;
}
the console has the following error.
Uncaught TypeError: Cannot set property 'disabled' of null
at updateSelect (<anonymous>:21:75)
at HTMLInputElement.onchange (updateuser:1)
any idea....what is unique about the element.value?
After doing some trial and error this worked
function updateSelect(element) {
var v = parseInt(element.value, 10);
document.getElementById("file_update_" + v).disabled = !element.checked;
}
I do not know why I had to do this to make it work.
I would appreciate it if someone helps me to understand it.
In a protractor end to end test, I want to check if an element exist using element(by.css(...)), my code:
var myElement = element(by.css('.elementClass'));
expect(myElement).toBeUndefined;
This test fails, it says:
Expected { locator_ : { using : 'css selector', value : 'div[ng-switch-
when="resultNav"]' }, parentElementFinder_ : null, opt_actionResult_ :
undefined, opt_index_ : undefined, click : Function, sendKeys : Function,
getTagName : Function, getCssValue : Function, getAttribute : Function, getText
: Function, getSize : Function, getLocation : Function, isEnabled : Function,
isSelected : Function, submit : Function, clear : Function, isDisplayed :
Function, getOuterHtml : Function, getInnerHtml : Function, toWireValue :
Function } to be undefined.
After that I tried to use a promise:
element(by.css('.elementClass')).then( functtion(data) {
expect(data.getText()).toBeUndefined();
});
This results in an error:
Error: No element found using locator By.CssSelector(...)
Yes, I know that no element will be found, but how can I create a working test using element(by.css(...))?
Does anyone know how to achieve this? or is element(by.css()) not the method to use here?
You can test whether the element is present with isPresent. Here are the protractor docs for the isPresent function.
So, your code would be something like:
var myElement = element(by.css('.elementClass'));
expect(myElement.isPresent()).toBeFalsy();
You need to test if the element is not present:
expect(element(by.css('.elementClass')).isPresent()).toBe(false);
Truthy and falsie refer to values that are evaluated to true and false after being coerced to a boolean unless you want your function to return different types of values.
var myElement = element(by.css('.elementClass'));
myElement.isPresent().then(function (elm)
{
if (elm)
{
console.log("... Element was found")
expect(myElement.getText()).toBeUndefined();
} else {
console.log("... Element was not found")
}
});
same thing, but different syntax
let elem = $('.elementClass');
let elemIsPresent = await elem.isPresent();
expect(elemIsPresent).toBe(false);
I'm trying to test if an element is visible using protractor. Here's what the element looks like:
<i class="icon-spinner icon-spin ng-hide" ng-show="saving"></i>
When in the chrome console, I can use this jQuery selector to test if the element is visible:
$('[ng-show=saving].icon-spin')
[
<i class="icon-spinner icon-spin ng-hide" ng-show="saving"></i>
]
> $('[ng-show=saving].icon-spin:visible')
[]
However, when I try to do the same in protractor, I get this error at runtime:
InvalidElementStateError:
invalid element state: Failed to execute 'querySelectorAll' on 'Document':
'[ng-show=saving].icon-spin:visible' is not a valid selector.
Why is this not valid? How can I check for visibility using protractor?
This should do it:
expect($('[ng-show=saving].icon-spin').isDisplayed()).toBe(true);
Remember protractor's $ isn't jQuery and :visible is not yet a part of available CSS selectors + pseudo-selectors
More info at https://stackoverflow.com/a/13388700/511069
The correct way for checking the visibility of an element with Protractor is to call the isDisplayed method. You should be careful though since isDisplayed does not return a boolean, but rather a promise providing the evaluated visibility. I've seen lots of code examples that use this method wrongly and therefore don't evaluate its actual visibility.
Example for getting the visibility of an element:
element(by.className('your-class-name')).isDisplayed().then(function (isVisible) {
if (isVisible) {
// element is visible
} else {
// element is not visible
}
});
However, you don't need this if you are just checking the visibility of the element (as opposed to getting it) because protractor patches Jasmine expect() so it always waits for promises to be resolved. See github.com/angular/jasminewd
So you can just do:
expect(element(by.className('your-class-name')).isDisplayed()).toBeTruthy();
Since you're using AngularJS to control the visibility of that element, you could also check its class attribute for ng-hide like this:
var spinner = element.by.css('i.icon-spin');
expect(spinner.getAttribute('class')).not.toMatch('ng-hide'); // expect element to be visible
I had a similar issue, in that I only wanted return elements that were visible in a page object. I found that I'm able to use the css :not. In the case of this issue, this should do you...
expect($('i.icon-spinner:not(.ng-hide)').isDisplayed()).toBeTruthy();
In the context of a page object, you can get ONLY those elements that are visible in this way as well. Eg. given a page with multiple items, where only some are visible, you can use:
this.visibileIcons = $$('i.icon:not(.ng-hide)');
This will return you all visible i.icons
If there are multiple elements in DOM with same class name. But only one of element is visible.
element.all(by.css('.text-input-input')).filter(function(ele){
return ele.isDisplayed();
}).then(function(filteredElement){
filteredElement[0].click();
});
In this example filter takes a collection of elements and returns a single visible element using isDisplayed().
This answer will be robust enough to work for elements that aren't on the page, therefore failing gracefully (not throwing an exception) if the selector failed to find the element.
const nameSelector = '[data-automation="name-input"]';
const nameInputIsDisplayed = () => {
return $$(nameSelector).count()
.then(count => count !== 0)
}
it('should be displayed', () => {
nameInputIsDisplayed().then(isDisplayed => {
expect(isDisplayed).toBeTruthy()
})
})
To wait for visibility
const EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(element(by.css('.icon-spinner icon-spin ng-hide')))).then(function() {
//do stuff
})
Xpath trick to only find visible elements
element(by.xpath('//i[not(contains(#style,"display:none")) and #class="icon-spinner icon-spin ng-hide"]))
element(by.className('your-class-name'))
.isDisplayed()
.then(function (isVisible) {
if (isVisible) { // element is visible
} else { // element is not visible
}
})
.catch(function(err){
console.error("Element is not found! ", err);
})
Here are the few code snippet which can be used for framework which use Typescript, protractor, jasmine
browser.wait(until.visibilityOf(OversightAutomationOR.lblContentModal), 3000, "Modal text is present");
// Asserting a text
OversightAutomationOR.lblContentModal.getText().then(text => {
this.assertEquals(text.toString().trim(), AdminPanelData.lblContentModal);
});
// Asserting an element
expect(OnboardingFormsOR.masterFormActionCloneBtn.isDisplayed()).to.eventually.equal(true
);
OnboardingFormsOR.customFormActionViewBtn.isDisplayed().then((isDisplayed) => {
expect(isDisplayed).to.equal(true);
});
// Asserting a form
formInfoSection.getText().then((text) => {
const vendorInformationCount = text[0].split("\n");
let found = false;
for (let i = 0; i < vendorInformationCount.length; i++) {
if (vendorInformationCount[i] === customLabel) {
found = true;
};
};
expect(found).to.equal(true);
});
Something to consider
.isDisplayed() assumes the element is present (exists in the DOM)
so if you do
expect($('[ng-show=saving]').isDisplayed()).toBe(true);
but the element is not present, then instead of graceful failed expectation, $('[ng-show=saving]').isDisplayed() will throw an error causing the rest of it block not executed
Solution
If you assume, the element you're checking may not be present for any reason on the page, then go with a safe way below
/**
* element is Present and is Displayed
* #param {ElementFinder} $element Locator of element
* #return {boolean}
*/
let isDisplayed = function ($element) {
return (await $element.isPresent()) && (await $element.isDisplayed())
}
and use
expect(await isDisplayed( $('[ng-show=saving]') )).toBe(true);
waitTillElementIsPresent(locator: Locator): promise.Promise<boolean>
{
const EC = protractor.ExpectedConditions;
return browser.wait(EC.visibilityOf(element(by.id('xyz')), browser.params.explicitWaitTime, 'Element taking too long to appear in the DOM');
}
const isDisplayed = await $('div').isDisplayed().then(null, err => false)
I have two models (User and Task) which are instances of Backbone.RelationalModel.
The relation about these two models is the following:
// Task model
var Task = Backbone.RelationalModel.extend({
relations: [
{
type: 'HasOne',
key: 'user',
relatedModel: User
}
],
urlRoot: 'someUrl'
});
Then I have one collection which code looks like this:
var FollowerCollection = Backbone.Collection.extend({
initialize: function () {
_.bindAll(this);
}
model: User
});
var User = Backbone.RelationalModel.extend({
});
When I make a fetch on FollowerCollection I get the following error:
Uncaught TypeError: Cannot read property 'idAttribute' of undefined
on the line 1565 of backbone-relation.js of backbone-relation version 0.5.0
Here a piece of code of backbone-relation.js
if ( !( model instanceof Backbone.Model ) ) {
// Try to find 'model' in Backbone.store. If it already exists, set the new properties on it.
var existingModel = Backbone.Relational.store.find( this.model, model[ this.model.prototype.idAttribute ] );
The problem is related to _.bindAll(this) because if I comment it, it works properly.
Why? Any ideas?
Removing the _.bindAll does work.
It's a shame, because it's a really handy function. It must interact with some part of Backbone badly. I'm on v9.10
I use this method all the time, and issues only come up sometimes (like when you want to do a bulk add to a collection).
For me, The problem was in this Backbone.js method:
// Get a model from the set by id.
get: function(obj) {
if (obj == null) return void 0;
this._idAttr || (this._idAttr = this.model.prototype.idAttribute);
return this._byId[obj.id || obj.cid || obj[this._idAttr] || obj];
},
The code fails at this.model.prototype because prototype is undefined. What? Ya. For reals.
The problem is that when _.bindAll is called, it binds all properties of the collection, as #jakee says. This seems to include Collection.model, which is a bug I think.
The solution is to bind individual methods until this is fixed.
There's an existing, but closed issue on github: https://github.com/documentcloud/backbone/issues/2080
Seems like the current maintainers don't like the method, but I don't understand why.
Like my project is really big I had to create my custom bindAll. Here you have the code, it works with the lastest versions.
I bind all the properties of the instance "this" except the ones that has prototype with properties, like this.model in a Collection
https://gist.github.com/patrixd/8025952
//bindAll from underscore that allows 1 argument to bind all the functions from the prototype,
//or if there are more arguments they will be the only binded
_.originalBindAll = _.bindAll;
_.bindAll = function (that) {
var funcs = Array.prototype.slice.call(arguments, 1),
validKeys = [], fn;
if (funcs.length == 0) {
for (var i in that) {
fn = that[i];
if (fn && typeof fn == "function" && (!fn.prototype ||
_.keys(fn.prototype).length == 0))
validKeys.push(i);
}
_.originalBindAll.apply(_, [that].concat(validKeys));
}
else
_.originalBindAll.apply(_, arguments);
};
i'm using openlayers and geoExt.
what i have is this:
var options = {
hover : true,
box : true,
onSelect : saveToJ
};
var select = new OpenLayers.Control.SelectFeature(vecLayer, options);
map.addControl(select);
select.activate();
now in saveToJ function i want to get length of selected feature (let's say feature = lineString):
function saveToJ(feature) {
feature.getLength()
...
}
gives an error TypeError: Object #<Object> has no method 'getLength', but from this
i thought i can use it.
So: how can i get a length of selected feature?
getLength is a method of Geometry, not Feature.
So you should write feature.geometry.getLength(), see http://dev.openlayers.org/docs/files/OpenLayers/Geometry-js.html#OpenLayers.Geometry.getLength