How to handle modal-dialog box in Protractor? - angularjs

I am trying to use sendKeys() on a modal-dialog box on this website. This dialog box appears after clicking Sign In button. I cannot seem to find any way to switch focus on the box. See the gist
I tried using browser.driver.switchTo().activeElement(); in
InvalidLogInUnSuccess: {
get: function () {
this.loginButton.click();
browser.driver.switchTo().activeElement();
this.email.sendKeys("Test");
}
}
with no luck and throws ElementNotVisibleError
Message:
ElementNotVisibleError: element not visible
(Session info: chrome=41.0.2272.101)
(Driver info: chromedriver=2.14.313457 (3d645c400edf2e2c500566c9aa096063e707c9cf),platform=Windows NT 6.3 x86_64)
Stacktrace:
ElementNotVisibleError: element not visible

I've experienced a similar issue while testing an internal application when a popup was being opened with an animation effect (I think it is a culprit here) which had me think about waiting for an element inside the popup to become visible.
visibilityOf expected condition works for me in this case:
var email = element(by.css('.container.login.ng-scope #email'));
browser.wait(EC.visibilityOf(email), 5000);
email.sendKeys('test');
where EC is something I usually define globally in the onPrepare():
onPrepare: function () {
...
global.EC = protractor.ExpectedConditions;
},
Just a side note, I think the locator could be improved here:
ng-scope is not something I would rely on
there is a model defined on the email field, how about:
element(by.model('email'));
FYI, the complete spec I've executed:
"use strict";
describe("gifteng test", function () {
var scope = {};
beforeEach(function () {
browser.get("http://www.gifteng.com/?login");
browser.waitForAngular();
});
describe("Logging in", function () {
it("should send keys to email", function () {
var email = element(by.css('.container.login.ng-scope #email'));
browser.wait(EC.visibilityOf(email), 5000);
email.sendKeys('test');
});
});
});

Protractor works with promises you should write :
InvalidLogInUnSuccess: {
get: async() => {
await this.loginButton.click();
await browser.driver.switchTo().activeElement();
await this.email.sendKeys("Test");
just apply Promises before protractor code. I removed function and write async. so i applied async/await.
reference: Link

Related

Protractor - if element is displayed, click on it doesn't work with by.buttonText

I have switched from finding an element by id to by.buttonText due to the fact I now use a single button with variable text. My test have started to fail.
This is my button
<button type="button" class="btn btn-primary" ng-click="vm.watchUnwatchDriver()">{{vm.model.isWatched ? 'Un-' : ''}}Watch Driver</button>
This evaluates to either 'Watch Driver' or 'Un-Watch Driver' based on vm.model.isWatched.
Initially I set my button to be Watch Driver so that I test if the Un-Watch button isDisplayed and potentially click on it if it is.
I have started to see this message
Failed: No element found using locator: by.buttonText("Un-Watch Driver")✗
My test looks like so
describe('Watch/Un-Watch Driver Test', function() {
var watchBtn = element(by.buttonText('Watch Driver'));
var unwatchBtn = element(by.buttonText('Un-Watch Driver'));
it('should set Driver watch status to default: un-watched', function() {
unwatchBtn.isDisplayed().then(function(visible) {
if (visible) {
unwatchBtn.click();
}
});
expect(unwatchBtn.isDisplayed()).toBe(false);
});
it('should watch a driver', function() {
watchBtn.click();
expect(unwatchBtn.isDisplayed()).toBe(true);
});
it('should un-watch a driver', function() {
unwatchBtn.click();
expect(unwatchBtn.isDisplayed()).toBe(false);
});
});
Try to print your button text and observe for example:
var unwatchBtn = element(by.css('.btn.btn-primary'));
unwatchBtn.getText().then(function(text){
console.log(text);
})
then use that text in by.buttonText
You can try element(by.partialButtonText('Watch Driver')) and it will work in both cases.
isPresent() seems to work okay for me. It successfully detects if button with such name is present.
it('should set Driver watch status to default: un-watched', function() {
unwatchBtn.isPresent().then(function(visible) {
if (visible) {
unwatchBtn.click();
expect(unwatchBtn.isPresent()).toBe(false);
} else {
expect(unwatchBtn.isPresent()).toBe(false);
}
});
});

Use protractor on an non angular page

in my recent test I need to first login and take some actions on an non angular page (https://www.qa.dealertrack.com/default1.aspx)
then switch to an angular page and finish the test.
In conf I have
global.driver = browser.driver;
My page object looks like:
var LogInPage = function() {
this.loginUrl = 'https://www.qa.dealertrack.com/default1.aspx';
this.id = browser.driver.findElement(by.name('username'));
this.password = browser.driver.findElement(by.name('password'));
this.loginButton = browser.driver.findElement(by.name('login'));
this.logIn = function(id, password) {
// maximize window
driver.manage().window().maximize();
// log in
driver.get('https://www.qa.dealertrack.com/default1.aspx');
this.id.sendKeys(id);
this.password.sendKeys(password);
this.loginButton.click();
}
};
My test looks like:
describe('Sample Test - Log In', function() {
var loginPage = require('../pages/LogInPage.js');
/**
* Disable waiting for AngularJS for none Angular page
*/
beforeEach(function() {
isAngularSite(false);
});
it('logging in', function() {
loginPage.logIn('xxx', 'xxx');
})
})
However, even before getting to the site, protractor throws error NoSuchElementError: no such element: Unable to locate element:{'method':'name','selector':'username'}
But when I commented out all the element variables and related lines, only left
driver.get(this/loginUrl);
It worked. Why would browser.driver.get works but browser.driver.findElement does not?
This is my first question on Stackoverflow. Thank everyone!!
Before login you need to set
browser.driver.ignoreSynchronization=true;
So it shold be like
browser.driver.ignoreSynchronization=true;
login();
browser.driver.ignoreSynchronization=false;
I tried to removed all the elements I declared outside my functions in page object. Instead of that, I just hard code the elements in the function. And it worked.

Element not clickable at point - works locally but not in production

So I'm receiving this error while testing on Circle, but not while in production. I've npm installed, bower installed, npm updated, bower updated, and npm run update-webdriver.
[chrome #1a] UnknownError: unknown error: Element is not clickable at point (1652, 61). Other element would receive the click: <div class="md-toolbar-tools">...</div>
[chrome #1a] (Session info: chrome=43.0.2357.130)
[chrome #1a] (Driver info: chromedriver=2.14.313457 (3d645c400edf2e2c500566c9aa096063e707c9cf),platform=Linux 3.13.0-76-generic x86_64
I'm not sure why the element wouldn't be clickable while in production but it would be fine for local. I tried adding in some waits but I don't think that's the issue. I've looked at other questions surrounding element not clickable at point but they all seem to be cases where it isn't working at all, not working only in select circumstances.
My page object looks like this:
'use strict';
var myObject = function () {
this.thing1 = element(by.css('md-list'))
this.thing2 = this.thing1.element(by.css('md-list-item'))
this.thing3 = this.thing2.element(by.css('button div div h4'))
this.thing4 = this.thing2.element(by.css('button div md-menu button'))
};
module.exports = new myObject();
and my spec looks like this, and the error is coming on the click line.
describe('Object directive', function () {
var myObject;
browser.driver.manage().window().setSize(1920, 1080);
browser.get('/#/login');
browser.waitForAngular();
myObject = require('./myobject.po.js');
it('should rename', function () {
myObject.thing4.click();
element(by.css('[aria-label=\'Rename Button\']')).click();
element(by.css('input')).clear();
element(by.css('input')).sendKeys('Test Name');
element(by.css('[ng-click="saveName()"]')).click();
expect(myObject.thing3.getText()).toBe('Test Name');
});
it('should delete', function () {
myObject.thing4.click();
element(by.css('[aria-label=\'Delete Button\']')).click();
expect(element(by.css('md-dialog-content div p')).getText()).toBe('Do you want to permanently delete?');
element(by.css('[ng-click="dialog.abort()"]')).click();
});
});
It looks like selenium thinks some element overlaps the desired one, it happens.
There are multiple things you can try:
make the click via JS click() (see the difference: WebDriver click() vs JavaScript click()):
browser.executeScript("arguments[0].click()", elm.getWebElement());
use browser actions: move to element and then make the click:
browser.actions().mouseMove(elm).click().perform();

protractor get url after click()

i'm new with protractor.. i need you'r help..
my code go like this..
describe('Protractor Demo Charts', function () {
var url = 'https://angularjs.org/';
it('should get the value of attribute d', function () {
browser.get(url);
element(by.css('.btn-warning')).click().then(function(text){
expect(browser.getCurrentUrl()).toContain('0BxgtL8yFJbacQmpCc1NMV3d5dnM');
}
);
});
});
my problem is that browser.getCurrentUrl() still return me the base url (the page that i came from 'https://angularjs.org/' )
how can i get the new Url (the URL AFTER the click )?
May you should wait until the page has been loaded.
Try this way :
describe('Protractor Demo Charts', function () {
var url = 'https://angularjs.org/';
it('should get the value of attribute d', function () {
browser.get(url);
browser.sleep(2000);
$('.btn-warning').click();
expect(browser.getCurrentUrl()).toContain('0BxgtL8yFJbacQmpCc1NMV3d5dnM');
});
});
From the doc:
Protractor will ensure that commands will automatically run in sync. For example, in the following code, element(by.model(...)).click() will run before browser2.$('.css').click():
browser.get('http://www.angularjs.org');
browser2.get('http://localhost:1234');
browser.sleep(5000);
element(by.model(...)).click();
browser2.$('.css').click();

Simple protractor test for isElementPresent failing with unsupported locator strategy

My test:
it('should allow login', function() {
browser.get('index.html');
$('#username').sendKeys('administrator');
$('#password').sendKeys('password');
$('#login').click();
var logout = $('#logout');
expect($p.isElementPresent(logout)).to.eventually.be.true;
});
But this errors out with:
Error: Unsupported locator strategy: click
at Error (<anonymous>)
at Function.webdriver.Locator.createFromObj (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/webdriver/locators.js:97:9)
at Function.webdriver.Locator.checkLocator (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/webdriver/locators.js:111:33)
at webdriver.WebDriver.findElements (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/webdriver/webdriver.js:805:31)
at webdriver.WebDriver.isElementPresent (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/webdriver/webdriver.js:787:29)
at Protractor.isElementPresent (/usr/local/lib/node_modules/protractor/lib/protractor.js:476:22)
at /Users/pschuegr/wt/client/e2e/login_test.js:26:15
Strangely, it points to the isElementPresent line, rather than the line with the click. I'm pretty new to webdriver, so apologies if I missed something obvious. I'm running using the mocha framework (which means the canary version of protractor), fwiw.
Any ideas appreciated.
Using the latest Protractor build, you can shorten the above answer to the following:
expect(element(by.css('#logout')).isPresent()).toBeTruthy();
This way you do not have to perform the browser.wait and you reduce the number of calls to isElementPresent.
$('#logout') is a WebElement. isElementPresent takes a locator, like by.css
$('#username').sendKeys('administrator');
$('#password').sendKeys('password');
$('#login').click();
var logout = by.css('#logout');
browser.wait(function() { return $p.isElementPresent(logout); }, 8000);
expect($p.isElementPresent(logout)).toBeTruthy();
The safest approach I would take is depicted in the following code snippet:
it('should return true when element is present', function () {
var logout;
logout = $('#logout');
browser.driver.isElementPresent(logout).then(function (isPresent) {
isPresent = (isPresent) ? true : browser.wait(function () {
return browser.driver.isElementPresent(logout );
}, 15000); //timeout after 15s
expect(isPresent).toBeTruthy();
});
});
Above code starts of with a promise to check if an element exists, and if true then assign it true, otherwise wait and keep pooling for the next 15sec to see if element is present, and in both cases we expect it to be true.
This should work :
var logout = $('#logout');
expect(logout.isPresent()).to.eventually.be.true;

Resources