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!');
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 simplified the code i need to test to this:
<html ng-app="home" ng-strict-di=""><head>....
And i am running some protractor tests, i want to access the value of ng-app so i can compare and see which app is running in each page.
I have tried
var appName = element(by.xpath('/html/#ng-app'))
but it is not returning a usable promise or text i can compare with
appName.getText().then(function(name) {
expect(name).toBe('home')
});
But protractor complains:
InvalidSelectorError: invalid selector: The result of the xpath expression "/html/#ng-app" is: [object Attr]. It should be an element.
So i'm a bit baffled as how can i access my angular app name from protractor to test for app running independently of localization of labels.
Any insight into this enigma?
And it seems like magically, when you order your thoughts to formulate the question, the answer comes to you.
the trick is to get the html as element
var appNameHtml = element(by.xpath('/html'))
and then, in the test, get the ng-app attribute and use it:
appNameHtml.getAttribute('ng-app').then(function(value) {
expect(value).toBe('home');
});
And bingo, you can extract the app name.
Maybe this is a very basic question, but it was driving me insane :)
your answer will suffice I guess in this case. But just wanted to highlight a more generic approach in case ng-app may reside not only on html element.
var elementWithNgApp = element(by.css('*[ng-app]'))
And then wanted to add one more thing. You need not resolve the promise of getAttribute to do an expect on its value. Jasmine resolves the promise for you. You can have something like this
expect(elementWithNgApp.getAttribute('ng-app')).toBe('home');
After a lot of research, and tinkering, I can't seem to actually get my Protractor test to do anything else other than have an Angular related error, even though I am using browser to avoid Angular being detected at all.
The test involves an Angular app, opening a dropdown in it, and clicking on the link for the console; the console opens a non-Angular admin page in a separate window.
So based on the many informative SO posts I found, I first used this...
browser.driver.getAllWindowHandles().then(function(handles) {
browser.driver.switchTo().window(handles[1]).then(function() {
//expect for new window here
});
});
Which appeared to work, as I could get to the window through repl pretty easily.
The issue is when either of the following were added...
browser.driver.getAllWindowHandles().then(function(handles) {
browser.driver.switchTo().window(handles[1]).then(function() {
expect(browser.getLocationAbsUrl()).toContain('/console/login.jsp');
expect(browser.driver.findElement(By.css('th.login')).getText()).toEqual('Login');
});
});
One expect check the URL and the other checks for the header element on the page, which is a table header. When I run this, I get the following:
Error while waiting for Protractor to sync with the page: "angular could not be found on the window"
When I decide to use browser.ignoreSynchronization = true, both in the function, or in a beforeEach, with or without a following afterEach setting it to false, I get the following:
JavascriptError: angular is not defined
I can't seem to get any "useful" errors to help me debug it, and trying it in repl does not help, as I get the same issue.
To be comprehensive, trying my URL expect without getting the second window will give me the root, and the other will fail.
Just doing one or the other will cause the same problem.
Changing to regular syntax (element(by.css...)) does not change things.
So much for my first question...
It appears that my use of browser.getLocationAbsUrl() is meant to be used for an Angular page, and was causing my issue...
Essentially, even though I believed I was using pure Webdriver calls, that call still required Angular on the page to work...
As stated in another post, the use of browser.driver.getCurrentUrl() is a non-Angular call using Webdriver, and fixed the problem. Thus, the final code is the following...
browser.sleep(1000); //to wait for the page to load
browser.driver.getAllWindowHandles().then(function(handles) {
browser.driver.switchTo().window(handles[1]).then(function() {
expect(browser.driver.getCurrentUrl()).toContain('/console/login.jsp');
expect(browser.driver.findElement(By.css('th.login')).getText()).toEqual('Login');
});
});
This works without setting ignoreSynchronization, BTW.
I realized it would probably be something relatively simple to fix it, just didn't expect I'd get it that quickly (I intended on submitting the question last night, but posted it this morning instead).
In any case, I hope this will at least be a good reference for anyone else facing the same issue.
Seems like getLocationAbsUrl is angular abs url.
Try using the native driver getCurrentUrl instead.
-- expect(browser.getLocationAbsUrl()).toContain('/console/login.jsp');
++ expect(browser.driver.getCurrentUrl() ...
I have a few tests that are running fine in chrome, but if I switch to phantomjs, I have the following error:
Unable to find element with css selector '.selected-recipients a'
My test is simply this:
it('should navigate when clicking edit', function() {
var editLink = element(by.css('.selected-recipients a')).element(by.css('.edit-preview'));
editLink.click();
expect(browser.getCurrentUrl()).toContain('#/recipients');
});
This works fine on chrome. The problem is phantomjs. I found a post that suggests that the problem might have to do with window size, but that didn't solve the problem for me:
https://github.com/angular/protractor/issues/585
I also tried to use by.id instead of by.css and I have the same problem. All other tests in this file work fine and some do use by.css, so it doesn't look like a problem with phantomjs understanding this locator. It seems like the element is not in the page at all.
Any ideas? Thanks
When phantomjs is acting in a strange way I dump a screen shot.
Probably not what you are looking for, but it is an idea. :)
page.open("http://www.stackoverflow.com", function()
{
page.render('script_ending.png');
}
Another idea is to try dumping the html to a file, to see if the element is there.
Or try changing the DOM, inserting an element, then see if you can find it.
Or try searching by just the class name, to see at what point it fails... maybe there is no child element of tag a.
I'm trying to test my angularjs app with protractorjs. I have set up selenium and got the server and runner working. My issue is that when I run my test I get the ElementNotVisibleError. I know that the element I am trying to select is hidden until certain fields have been filled in and this is how I would like this to be kept.
My question is, are there any workarounds to the issue via a call to wait or sleep. I have tried many variations of wait and sleep but with no luck.
My test code is
it('navigates the user to the login page', function(){
ptor = protractor.getInstance();
ptor.get('http://localhost:2222/#/page');
ptor.findElement(protractor.By.input('input.type1')).sendKeys('one');
ptor.findElement(protractor.By.input('input.type2')).sendKeys('two');
ptor.findElement(protractor.By.input('input.type3')).sendKeys('three');
ptor.findElement(protractor.By.input('input.type4')).sendKeys('four');
ptor.findElement(protractor.By.input('input.type5')).sendKeys('five');
ptor.findElement(protractor.By.input('input.type6')).sendKeys('six');
ptor.sleep(5000);
ptor.findElement(protractor.By.id('clickableBtn')).click();//not visible until above fields populated
}, 1000000);
Message from protractor is
Message:
ElementNotVisibleError: element not visible
If the element is not visible until you have input in all of the fields, it is because of Javascript. You may have to kick off that Javascript by typing Tab or Enter after typing that last field:
ptor.findElement(protractor.By.input('input.type6')).sendKeys(Keys.Tab);
Using javascript I was able to click
var linkToClick = ptor.driver.findElement(protractor.By.id('clickableBtn'));
ptor.executeScript("arguments[0].click();", linkToClick );
yes, WebDriver allows you to execute javascript on elements directly so simply do a javascript .click. You would need to convert to your own language but here is how I did it using C#
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
js.ExecuteScript("arguments[0].click()", element);
Browser.WaitForPageLoad(driver);
I actually created an extender method so that I simply type element.InvisibleClick(driver) and it clicks on it for me. More on that can be found documented HERE.
You can always give it opacity:0
-moz-opacity: 0.00; opacity:.00; filter: alpha(opacity=00);
This should work for all browsers.