Protractor + chrome driver: Element is not clickable at point - angularjs

Hi I am having some trouble getting a basic protractor test to work.
My setup:
I use requirejs so I init angular using angular.bootstrap(), not the ng-app attr. According to protractor docs this is not supported out of the box, but seems to work fine for tests that don' involve clicking.
Protractor conf.json:
"use strict";
exports.config = {
specs: '../E2ETests/**/*.js',
chromeOnly: true,
getPageTimeout: 30000,
allScriptsTimeout: 30000
}
I use some third party jquery plugs which I wrap in directives, I suspect these might be part of the issue.
The test:
"use strict";
describe('When clicking should add stuff', function () {
var ptor;
beforeEach(function () {
browser.get('https://localhost/myApp');
ptor = protractor.getInstance();
});
it('add stuff', function () {
// If I comment this, the test pass.
element(by.id('add-stuff-button')).click();
// This does not matter fails on the line above..
expect(browser.getTitle()).toBeDefined();
});
});
The error:
UnknownError: unknown error: Element is not clickable at point (720, 881). Other element would receive the click: <div class="col-md-5 col-md-offset-5">...</div>
(Session info: chrome=37.0.2062.124)
(Driver info: chromedriver=2.10.267521,platform=Windows NT 6.1 SP1 x86_64)
Thoughts
The chromedriver do find the button, because if I change the id it complains that no element is found. So I think the problem is that the button moves from its initial position. As the element(***) function should wait for angular to be done, I suspect that its the third party plugins that might interfere as they might not use angular api's fetching data etc. So angular think its done but then the third party plug populates and moves stuff around.
Any ideas what to do?
If the third party plugs is the problem, can I somehow tell angular that third party stuff is going on and then later tell it when its done?
Thx
Br
Twd

You should set window size in your config file
onPrepare: function() {
browser.manage().window().setSize(1600, 1000);
}

Following worked fine for me:
browser.actions().mouseMove(element).click();
Edit: If above does not work try chaining perform() method too(I got this as an edit suggestion, I have not tested it but somebody could verify it and comment)
browser.actions().mouseMove(element).click().perform();

This happens if the chrome window is too small, try to add inside the beforeEach
browser.driver.manage().window().setSize(1280, 1024);

Or simply use the Actions class:
browser.actions().mouseMove(elem).click().perform();

Had the same issue but was not related to the window size but had to wait for ngAnimation to end.
So I had to wait until the element was clickable with.
const msg = 'Waiting for animation timeout after 1s';
const EC = new protractor.ProtractorExpectedConditions();
await browser.wait(EC.elementToBeClickable(model.elements.button.checkCompliance), 1000, `${msg} panel`);
await model.elements.button.checkCompliance.click();
#note - I am using async/await node 8 feature, you could just as well convert this to regular Promises.
Also using ProtractorExpectedConditions instead of ExpectedConditions see documentation

Maybe It is not applicable in your case, but I've encountered the same problem and based on Milena's answer I've been looking for another element obscuring my button (in my case, a dropdown menu in the top right of my screen).
It appears to be the Connected to Browser Sync notification message sent by browsersync, launched by Gulp. The message vanished after a short time, but after my onClick() call.
To remove the notification, in my gulpfile, I've added the notify: false param when initializing browsersync:
browserSync.init(files, {
server: {
baseDir: "dist",
index: "index.html"
},
notify: false
});

I fix this problem by using browser time sleep.
browser.driver.sleep(3000)
before giving click button

You can define the desired screen resolution through your protractor configuration file (e.g. protractor.conf.js or config.js) for consistent test behavior.
For example with Chrome browser:
exports.config = {
specs: [
// ...
],
capabilities: {
browserName: 'chrome',
chromeOptions: {
args: [
'--window-size=1600,900',
'--headless'
]
}
}
// ...
}
Explanations
window-size argument will launch Chrome with a 1600 by 900 window.
headless will launch headless Chrome, allowing you to have your tests run with the specified window size (1600 by 900) even if your screen resolution is lower than that.
You may want to have two configurations, one for developers (without headless mode) who always have a high resolution screen and one for build servers (headless mode) where screen resolution is sometimes a mystery and could be lower than what your application / test is designed for. Protractor configuration file are javascript and can be extended to avoid code duplication.

I had the same error and purely adjusting the screen size did not fix it for me.
Upon further inspection it looked as though another element was obscuring the button, hence the Selenium test failed because the button was not (and could not be) clicked. Perhaps that's why adjusting the screen size fixes it for some?
What fixed mine was removing the other element (and later adjusting the positioning of it).

This works better than specifying the window size, in case you test need to run on multiple displays.
browser.manage().window().maximize();

Other way, you can try this:
this.setScrollPage = function (element) {
function execScroll() {
return browser.executeScript('arguments[0].scrollIntoView()',
element.getWebElement())
}
browser.wait(execScroll, 5000);
element.click();
};

You could also try turning off any debug tools you might be using. I was using Laravel and debugbar and had to set APP_DEBUG to false.

From Gal Malgarit's answer,
You should set window size in your config file
onPrepare: function() {
browser.manage().window().setSize(1600, 800);
}
If it still doesn't work you should scroll to the element's location
browser.executeScript('window.scrollTo(720, 881);');
element(by.id('add-stuff-button')).click();

Note that this was sometime caused by a top navigation bar or bottom navigation bar / cookie warning bar covering the element. With angular 2, when clicking it scrolls until the element is only just on page. That means that when scrolling down to click something, if there is a bottom navigation, then this will obstruct the click. Similarly, when scrolling up it can be covered by the top navigation.
For now, to get around the scrolling up, I am using the following:
browser.refresh();
browser.driver.sleep(3000);
I made sure that I removed the bottom bar by clicking to close it before the test started.

That means the element is not within the visible area. There are several ways to handle this:
Force click the element regardless visibility
await browser.executeScript('arguments[0].click();', $element.getWebElement());
Scroll to the element and then click
await browser.executeScript(`arguments[0].scrollIntoView({block: "center"});`, $element.getWebElement());
await $element.click()
Maximize the working area of browser's window before tests
beforeAll(async () => await browser.driver
.manage()
.window()
.setSize(1920, 1080)
);

Related

Not all automation tests run the same in different browsers

I have automation tests that will need to be ran in chrome desktop edition and chrome mobile edition. One of my tests require the desktop edition to click on an element that only appears when hovering, however, the mobile edition does not require hover the elements are always visible. I am having troubles finding a way to tell the test running on ipad to ignore the hover step and just click the button. I could create a method just for ipad and separate spec file but I don't want to waste my time if there is an easy fix.
however, the mobile edition does not require hover the elements are always visible.
We may use that. Basically, if the element is visible, click on it, if not - hover and then click:
elm.isDisplayed().then(function (isDisplayed) {
if (!isDisplayed) {
// hover what you need to hover
}
elm.click();
});
There is also that getCapabilities() function that gives you access to the current capability object. You may have a helper function that would determine whether a hover is needed depending on the current browser the tests are executed in. Let's first write our isMobile sample function and define it on the browser object:
browser.isMobile = function(ver) {
var platformName, version;
return browser.getCapabilities().then(function(s) {
platformName = s.caps_.platformName;
version = s.caps_.version;
return /Android|iOS/.test(platformName);
});
};
Sample helper function:
function hoverClick(elm) {
return browser.isMobile().then(function (isMobile) {
if (!isMobile) {
browser.actions().mouseMove(elm).perform();
}
return elm.click();
});
}
See also: Protractor: accessing capabilities.
You may also extend the browser.actions() and add a custom hoverClick action, see:
Custom browser actions in Protractor

Failed: Timed out waiting for Protractor to synchronize with the page

I faced with very strange problem. During first test run I am almost always receive such error:
Failed: Timed out waiting for Protractor to synchronize with the page after 50 seconds. Please see https://github.com/angular/protractor/blob/master/docs/faq.md
It does not depend somehow on the test content and after couple of executions everything starting working just fine.
My spec:
Protractor 2.1.0 + Jasmine
It is only occurs for one of my projects, for others everything just fine.
browser.ignoreSynchronization=true; wont work in my case, because it is 100% angular app.
Any ideas on the reasons? It is really strange because it occurs mostly on the 1st run.
I also increased allScriptsTimeout: 50000, but looks like it does not help and it is not a solution
I use
rootElement: 'html'
param in my config as long as app is defined on html tag
I also faced the same issue but after increasing the time out it worked for me
allScriptsTimeout: 72000, and try to add the below lines
jasmineNodeOpts: {
isVerbose: true,
includeStackTrace: true,
showColors: true,
defaultTimeoutInterval: 72000
}
You can try: browser.manage().timeouts().implicitlyWait(2000); inside onPrepare()
I use it for my hybrid app, maybe your angular part of DOM is taking some time to load, and it might help you.
EDIT: F*** comments edits :)
I guess you could hack around it with beforeEach() function, or use it in first test if that happens only then, that would have something like this:
dvr = browser.driver;
browser.ignoreSynchronization = true;
dvr.wait(function() {
return browser.driver.isElementPresent(by.css('.ngscope')); }, 30000); //or any other angular element detection
browser.ignoreSynchronization = false;
Also I remember that sometimes webdriver lose focus of browser window on start (I haven't seen it in protractor, but it happened to me before with different frameworks), and changing resolution of browser helped browser.manage().window().setSize(1280, 1024); )

I can't move website created in famous on mobile device

I've created website completely in angular + famous.
In desktop it's working great. When I try to open it in safari / chrome on iPhone it's working great as well but there is one problem. Using my finger I can't move page at all, only touch event is recognized, nothing more.
This is happening also in official examples. For example examples/views/Scrollview/example.html. If I rotate my iPhone 6 Plus to landscape I can't even access the browser toolbar to close the page, I need to kill the browser and start it again.
What I am suppose to do to fix this? Why is this even happening?
The problem is that you are using Famous in appMode. Try setting the following and see if that works:
Engine.setOptions({appMode: false});
When Famous is in appMode, it will add the following snippet when the context is created:
function initialize() {
// prevent scrolling via browser
window.addEventListener('touchmove', function(event) {
event.preventDefault();
}, true);
addRootClasses();
}
This is what prevents the browser page from moving.
function initialize() {
// prevent scrolling via browser
window.addEventListener('touchmove', function(event) {
event.preventDefault();
}, true);
addRootClasses();
}

Make protractor test occupy the entire screen

I have seen a couple questions online related to this issue (How to set default browser window size in Protractor/WebdriverJS) but they don't address my issue.
I have the tests that I want to be able to run successfully on a laptop screen or desktop screen of ant size. I had tried all of these methods below but unsuccesfully.
The issue with this one is that I have to hardcode a width and height. I want to detect the screen size automatically
browser.driver.manage().window().setSize(width, height);
The issue with this one is that it only seems to maximize the height and not the width.
browser.driver.manage().window().maximize();
I want to be able to get the screen's height and width and plug those in for the .setSize() function. But when I try this
browser.driver.manage().window().setSize(screen.width, screen.height);
I get ReferenceError: screen is not defined
If I try console.log($(window)); then window is not defined either
So what the best way to do this?
In case of Chrome on Mac OS X, the following didn't make the browser maximized for me:
browser.driver.manage().window().maximize();
In this case, you need to either switch to Firefox, or start Chrome with --start-maximized:
capabilities: {
browserName: 'chrome',
chromeOptions: {
args: [
'--start-maximized'
]
}
}
We set browser size in onPrepare block in protractor.conf.js:
onPrepare: function() {
browser.driver.manage().window().maximize();
},
not sure if this helps you with your second issue ..?
Inexplicably, on OSX only '--start-fullscreen' worked for me.

can not click on none visible element

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.

Resources