I want to retrieve the first element from a ElementArrayFinder matching a condition. The following code provides me with the element that I'm expecting but it goes through all elements which takes time.
Is there any way to this?
return content.all(by.css('.class')).filter(function(label){
return label.getText().then(function(text){
return text === searchName;
});
}).first();
CONCLUSION:
Answer provided by Sudharsan Selvaraj worked as a charm
var ele = content.all(by.xpath(".//*[contains(#class,'class')][normalize-space(text())='some-value']")).first()
Reduced drastically time searching the element
The answer provided by Florent B. also solves the problem and looks like a much simpler approach.
return content.element(by.cssContainingText('.class', searchName));
You can use xpath to find the element with specific text.Look at below sample xpath.
var ele = content.all(by.xpath(".//*[contains(#class,'class')][normalize-space(text())='some-value']")).first()
You should use the locator by.cssContainingText to find an element by CSS and text:
return content.element(by.cssContainingText('.class', searchName));
Why don't you directly access the first element of the label?
return content.all(by.css('.class label')).first().getText().then(function (text) {
return text === searchName;
});
P.S. I didn't test the code but it should probably work
Related
I have some Protractor tests that are running on an Angular application that uses ui-grid. I have some working smoke tests for the application, but I am just starting to implement tests using https://github.com/angular-ui/ui-grid/blob/master/test/e2e/gridTestUtils.spec.js to test the ui-grid components. The problem I'm having is that I need the actual id of the grid element in order to use the getGrid function.
I'm able to successfully locate the element using element(by.css("[id$='-grid-container']")), but for some reasons my attempts to get the full id out of the element have failed. Here is what I am trying:
var grid = element(by.css("[id$='-grid-container']"));
grid.getAttribute('id').then(function(result) {
console.log(result);
var myGrid = gridTestUtils.getGrid(result.toString());
gridTestUtils.expectCellValueMatch(myGrid, 0, 0, 'Cox');
});
The console.log(result); is not logging anything. It doesn't SEEM necessarily related to ui-grid, it's just Selenium isn't finding the id for some reason. As far as I can tell I'm using getAttribute correctly; it works with this syntax in other tests, but maybe I'm missing something. Any ideas why this isn't working?
Edit because my comment is unreadable:
Thanks for the suggestions. However, I'm still just as confused because
var grid = element(by.css("[id$='-grid-container']"));
console.log(grid.toString());
grid.getAttribute('id').then(function(result) {
console.log('======'+result);
var myGrid = gridTestUtils.getGrid(result.toString());
gridTestUtils.expectCellValueMatch(myGrid, 0, 0, 'Cox');
});
gives a console output of
[object Object]
======
so it seems like the element is being found, which I had already checked, and the console.log inside the promise is being executed.
It's like it can't find the 'id', which according to the API documentation means there is no id on the element. But that is definitely not true.
Not sure on the semantics, but you could try this, just to make sure that you are getting the first element, if multiple:
element.all(by.css('[id$="-grid-container"]')).first().getAttribute('id').then(function(result) {
console.log(result);
var myGrid = gridTestUtils.getGrid(result.toString());
gridTestUtils.expectCellValueMatch(myGrid, 0, 0, 'Cox');
});
Your code looks correct.
However, if your console.log(result) doesn't log anything, this means you either didn't find the element or the moment you execute the getAttribute() the element is no longer present.
See in the API description, that getAttribute() always returns a value, if the element is present.
Maybe try to extend console.log('======='+result); to figure out, if that line of code gets executed (I'm pretty sure it's not executed). Also try console.log(grid.toString());, which should output [object Object], if the element is really found.
As for the ElementFinder, I'm used to use the ' and " just the other way around, so element(by.css('[id$="-grid-container"]')); or shorter $('[id$="-grid-container"]').
Let me know, if this helped and you could further determine the cause.
Round 2
Let's exclude a few things
change getAttribute('id') to getAttribute('outerHTML') to see,
if there is anything logged.
change (result) to (resultattr) to exclude, that result is else used by a plugin, who put result as a global variable.
change grid.getAttribute() to be element(by.css("[id$='-grid-container']")).getAttribute
What are the results of those actions?
I am fairly new to protractor and angularJS so please help me with this. When the dayReport element is selected, the class='active' attribute is set but when the element is not selected, the attribute is completely removed.
I want to make sure that when another element is selected, dayReport doesn't have the class='active' attribute although the element itself is still present.
I tried this: expect(dayReport.getAttribute('class').isPresent()).toBe(false); and some other few ideas but it I don't seem to make it work. Any ideas?
For whoever is reading this and needs a clear answer, the response from #TomNijs was very helpful but the hasClass function should be created in order for that to work. So the whole piece of code after defining the dayReport element is now looking like this:
var hasClass = function (element, cls)
{
return element.getAttribute('class').then(function (classes)
{
return classes.split(' ').indexOf(cls) !== -1;
});
};
expect(hasClass(dayReport, 'active')).toBe(false);
I had the same issue, try the following code :
hasClass will return a promise which will immediatly be resolved by the expectstatement and return true or false wether your element has the class="active" attribute.
//hasClass will check if the first parameter (the element) has the following the second parameter(the class attribute)
expect(hasClass(dayReport, 'active')).toBe(true);
Here’s what I’m trying to do while testing an Angular app with Protractor. I would like to get a certain element, which is somewhat like this:
<div class="someClass">
<p>{{textFromBoundModel}}</p>
</div>
then get its html, and check whether it contains the text that I expect it to have.
I tried to get this element first by the cssContainingText method, but it didn't quite work (not sure why; maybe because the text within the paragraph is produced dynamically). So now I’m getting this element using just the by.css locator. Next, I'm checking whether it contains the text I’m testing for:
// this is Cucumber.js
this.Then(/^Doing my step"$/, function(callback){
var el = element(by.css('.someClass'));
expect(el).to.contain("some interesting string");
callback();
});
});
but this doesn't work. Problem is, el is some kind of a locator object, and I can’t figure out how to get html of the element it found in order to test against this html. Tried .getText(), with no success.
Any suggestions?
Does:
expect(el.getText()).to.eventually.contain("some interesting string");
work?
I believe you need the .eventually to wait for a promise to resolve, and you need the .getText() to get at the content of the div.
See the chai-as-promised stuff at the head of the cucumber sample.
Try the below solution worked for me
Solution 1 :
expect(page.getTitleText()).toContain('my app is running!');
Solution 2 :
expect<any>(page.getTitleText()).toEqual('my app is running!');
In my code there a list of elements (tr) selected with "protractor.By.repeater".
This list is looped using "forEach".
Within this loop, the element is clicked, and this click should trigger the inclusion of a new "tr" just after the clicked element.
I want to select that new line.
I used :
var nextRow = tr.$(protractor.By.xpath('following-sibling::tr'));
but then with :
nextRow.isDisplayed(function(row){
console.log('row', row);
});
it generates errors such as : " UnknownError: java.util.HashMap cannot be cast to java.lang.String"
Is there another way to achieve what I want, i.e to select the next sibling of the current element ?
Or did I wrote something incorrect there ?
Thanks for any help!
Looks like you are missing a .then there and misinterpreted what isDisplayed does.
Code should be more like:
nextRow.isDisplayed().then(function(visible) {
console.log('is displayed? ', visible);
});
Also your ElementFinder nextRow doesn't look quite alright, what is variable tr below? and Protractor $ is an alias for element(by.css which takes a string argument, not a webdriver.Locator like you interpreted below, in your code:
var nextRow = tr.$(protractor.By.xpath('following-sibling::tr'));
So instead maybe you meant:
var tr = $('table tr.first'); // just guessing here since you didn't provide that code
var nextRow = tr.element(By.xpath('following-sibling::tr'));
Using Xpath selectors is not a better choice as it slows down the element finding mechanism.
I have designed a plugin to address this specific issues: protractor-css-booster
The plugin provides some handly locators to find out siblings in a better way and most importantly with CSS selector.
using this plugin, you can directly use:
var nextRow = element(by.css('table tr.first')).element(By.followingSibling('tr'));
Hope, it will help you...
I have a ExtJS page that is outputting the following DOM.
I want to select a specific element so that I can respond to a click on it.
However, the following code never selected the elements that are built with the extJS library. JQuery can't seem to select them either.
ExtJS can't even find an element that is defined in the <body> element in the HTML file itself. However, JQuery can indeed select an element defined in the <body> element.
I have been reading this guide which seems to indicate it should be no problem to just use Ext.get() and Ext.select() to get elements, however, as the following code shows, the elements are never selected.
How do I select an element in ExtJS?
var members = Ext.select('x-panel');
for (var i = members.length - 1; i >= 0; i--){
element = members[i];
element.on('click', function() { alert('test');})
};
Try Ext.select('.x-panel') with a period in the selector, which is required for selecting by class name.
bmoeskau is right, you can use Ext.select('.x-panel') which returns a collection of divs with class x-panel.
Note that Ext.get() just returns a single element, so if you want to get multiple matches you should use Ext.select() or Ext.query().
And what's more, Ext.select() returns Ext.CompositeElement, though the document does not list but it supports all the methods of Ext.Element so your example can be simply written as:
Ext.select('.x-panel').on('click', function(){ alert('test') });
Code above will add event handler for click operation to each x-panel.
Use:
Ext.get(el);
if you need to get the flyweight element, use:
Ext.fly(el);
See the API documentation for the Static Ext object for details