Is protractor.findElement() meant to scroll to that element? - javascript

My current unit test (protractor + angularJS project) is failing with the error UnknownError: unknown error: Element is not clickable at point (525, 1103). I used debugger to stop it just before failure, and the only reason I can think that it would fail is because the button is not in the view port (you would have to scroll down).
The failing lines are
homeLink = ptor.findElement(protractor.By.linkText('Home'));
homeLink.click();
expect(ptor.getCurrentUrl()).toBe(homeUrl);
From https://github.com/angular/protractor/issues/319, he says '...when i use findElement() it will scroll them to the "top" of the page'. And the comments agree.
In my test homeLink = ptor.findElement(protractor.By.linkText('Home')); is not causing the the page to scroll.
Am I wrong in thinking it should?
What should I be doing?

You need to scroll down (or maximize browser if this allows you to see the button you would like to click on) first so that the button is visible on the page:
var scrollIntoView = function () {
arguments[0].scrollIntoView();
}
browser.executeScript(scrollIntoView, yourwebelement);

don't forget to get the webElement browser.driver.executeScript("arguments[0].scrollIntoView(true);", ed.getWebElement());

Related

How to test 'HOVER' using Cypress(.trigger('mouseover') doesn't work)

I wonder if it's possible to test coverable dropdown menu bar using Cypress.
For example, when you go to Ebay(https://www.ebay.com), you'll see the alert icon at the top-right corner of the page and if you hover on that element, sign-in notification box will show up.
Here is my code and I followed what Cypress told me to do but I got an error like...
AssertionError
Timed out retrying: Expected to find element: #ghn-err, but never found it.
it('ebay hover test', () => {
cy.visit('https://www.ebay.com')
// 1. alert icon hover test.
cy.get('#gh-Alerts-i').trigger('mouseover')
cy.get('#ghn-err').should('be.visible')
// 2. This is my another test.
// cy.get('#gh-eb-My > .gh-menu > .gh-eb-li-a > .gh-sprRetina').trigger('mouseover')
//cy.get('#gh-eb-My-o > .gh-eb-oa thrd').should('be.visible')
})
For me mouseover works. It's a known Cypress bug pending to be solved.
However, try these:
cy.get('#gh-Alerts-i').trigger('onmouseover')
cy.get('#gh-Alerts-i').trigger('mouseenter')
cy.get('#gh-Alerts-i').invoke('trigger', 'contextmenu')
cy.get('#gh-Alerts-i').rightclick();
I had the same problem, I finally found this plugin that does exactly what I was looking for: do real events instead of simulated ones (simulated == launched with javascript).
https://github.com/dmtrKovalenko/cypress-real-events#cyrealhover
Just install it, add a line to cypress/support/index.js file (do not forget! See 'install' paragraph at the top of the page) and use cy.get(<element>).realHover().
If .trigger() does not work for you, it could also be that your display logic is controlled via CSS instead (for example with .class:hover). You could then rework the display logic to toggle a class with mouseenter and mouseleave events instead.

Scroll up and down to get Element into View with Selenium Python

I need to be able to scroll up and after that down to find some element with Selenium.
I already saw many questions and answers, the main idea I found is self.web_driver.execute_script("return arguments[0].scrollIntoView(true);", element) and this is what I currently have in my code. But this is not good enough since this code is scrolling down only so this fails to find the element in case it is located in the upper part of the rollable view.
So I need a script that first scrolls up (page Up?) and after that begins scrolling down.
I tried something like this
self.web_driver.execute_script("return arguments[0].scrollIntoView(true);", element)
self.web_driver.execute_script("window.scrollTo(0, -document.body.scrollHeight);")
self.web_driver.execute_script("return arguments[0].scrollIntoView(true);", element)
but this doesn't scroll up :(
You can try below code to scroll page up:
from selenium.webdriver.common.keys import Keys
self.web_driver.find_element_by_tag_name('body').send_keys(Keys.HOME)
Another way (preferred) you can scroll up to required element:
element = self.web_driver.find_element_by_xpath('SOME_XPATH') # you can use ANY way to locate element
coordinates = element.location_once_scrolled_into_view # returns dict of X, Y coordinates
self.web_driver.execute_script('window.scrollTo({}, {});'.format(coordinates['x'], coordinates['y']))
I have discovered a handy tricky hacky stuff over the years (I've been using Selenium for 150 years).
Whenever you're unable to scroll up a form, just send keys into an input on the top of the page. The driver will find it and will automagically scroll up the page to perform the action.
Whenever I think about this trick, I realize being an old man isn't that bad.
Good luck you fresh sailor, see you on the shores of Selenia.
Try this, it works good:
view_port_height = "var viewPortHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);"
element_top = "var elementTop = arguments[0].getBoundingClientRect().top;"
js_function = "window.scrollBy(0, elementTop-(viewPortHeight/2));"
scroll_into_middle = view_port_height + element_top + js_function
driver.execute_script(scroll_into_middle, element)
This was very useful for me:
WebElement scrolling = new WebDriverWait(driver, 10)
.until(ExpectedConditions.visibilityOfElementLocated(By.className("classSomething")));
//SCroll Down
((JavascriptExecutor) driver).executeScript("arguments[0].scrollTo(0, arguments[0].scrollHeight)", scrolling);
//Scroll Up
((JavascriptExecutor) driver).executeScript("arguments[0].scrollTo(0, arguments[0].scrollUp)", scrolling);
You can do it with also getBoundingClientRect() and scrollTo()
self.web_driver.execute_script("coordinates = arguments[0].getBoundingClientRect();scrollTo(coordinates.x,coordinates.y);", element)
I tested and it goes up and down.
If you defined driver as webdriver.Chrome() or webdriver.Firefox(),you can use this code for scrolling up:
from selenium.webdriver.common.keys import Keys
driver.find_element_by_tag_name('body').send_keys(Keys.HOME)
Also, for scrolling down, you can try this code:
driver.execute_script("arguments[0].scrollTop = arguments[0].scrollHeight", scr1)
scr1 is your box xpath which you want to scroll it.
You can scroll to middle of the page by this code, too:
driver.execute_script("arguments[0].scrollTop = arguments[0].scrollWidth", scr1)
For java I use next expression:
WebElement element = drv.findElement(By.xpath("//div"));
(drv as JavascriptExecutor).executeScript("arguments[0].scrollIntoView();", element);
The snippet scroll down to an element in Selenium until it is visible

Can a scrollIntoView function save its position?

I am having a problem with JS scrollIntoView getting reset after a selenium webElement.click() was performed. When I have used it on a custom scrollbox, it performs action correctly and then scrolls back to top after hitting .click().
element = driver.findElement(By.xpath("//div[#id='iLegenda']/ul/li[4]/i"));
((JavascriptExecutor)driver).executeScript("arguments[0].scrollIntoView(true);", element);
Thread.sleep(500);
driver.findElement(By.xpath("//div[#id='iLegenda']/ul/li[4]/i")).click(); //this line resets the position of the affected scrollbar
An alternate solution would be force-clicking the element even though it's not displayed on screen, but I haven't found any info on that front yet...
That's not something you can control. It's something to do with whatever the click is doing. If it were me, I would put the .scrollIntoView() code into a function so that it's easier to call, e.g.
public void scrollIntoView(WebElement e)
{
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", e);
}
and call it like
element = driver.findElement(By.xpath("//div[#id='iLegenda']/ul/li[4]/i"));
scrollIntoView(element);
Also, Thread.Sleep() is a bad practice. (You can google to learn the reasons why). You shouldn't need a wait here anyway but in case you do, it should be something like
WebDriverWait wait = new WebDriverWait(driver, 2);
WebElement element = driver.findElement(locator);
wait.until(ExpectedConditions.elementToBeClickable(element)).click();
I use Java and Selenium all the time and I've never had to scroll before clicking an element. Have you tried something simple like
driver.findElement(By.xpath("//div[#id='iLegenda']/ul/li[4]/i")).click();
with no scroll and no wait? It should just work.
Also, if you are going to click the same element repeatedly, you should do something like
By locator = By.xpath("//div[#id='iLegenda']/ul/li[4]/i");
driver.findElement(locator).click();
// do something
driver.findElement(locator).click();
// ... and so on...

Scroll to specific place on the page does not work browser Edge

I can't understand why this function doesn't work properly on Edge.
function contactos(thi)
{
var contactos = document.getElementById('contactos');
window.scrollTo(0, contactos.offsetTop - 160 );
}
And this is the html
Contatos
I just tested window.scrollTo() on Edge and it works as expected.
The only thing that comes to mind is, maybe contactos doesn't exist or it doesn't have an offsetTop property. To debug it:
Go to Edge
Open developer tools (press F12)
In the Console tab, write document.getElementById('contactos')
If it prints something other that undefined, it exists.
Write document.getElementById('contactos').offsetTop
If it prints something other that undefined, it exists.
If you successfully reach the last point, it's because there is an problem somewhere else in the code. You might have to debug further.
Edit: You don't have an element with an id "contactos". You can do one of three things:
Since you're passing this to your function (function contactos(element)), you can just window.scrollTo(0, element.offsetTop - 160 );
Or, you first set var contactos = element, and keep the rest.
Or, better, set an id in the html element, like so: Contatos
Here's a snippet. Try making it a button.
function contactos(element)
{
window.scrollTo(0, element.offsetTop + 160);
}
<button onclick="contactos(this)">Contactos</button>
<!-- gibberish -->
<br/><br/><br/><br/><br/><br/><br/>
<br/><br/><br/><br/><br/><br/><br/>
<p>Text added just to see movement</p>

Chrome ignoring hashes in URL

I've spent quite a while trying to find answers for this issue, but haven't had any success. Basically I need to scroll the user to the contact portion of the website when they go to healthdollars.com/#contact. This works just fine in Safari, but in Chrome I haven't had any luck. I've tried using jQuery/Javascript to force the browser to scroll down, but I haven't been able to.
Does anyone have any ideas? It's driving me crazy - especially since it's such a simple thing to do.
Not a full answer but in Chrome if you disable Javascript I believe you get the desired behavior. This makes me believe that something in your JavaScript is preventing default browser behavior.
It looks to me like the target element doesn't exist when when page first loads. I don't have any problem if I navigate to the page and then add the hash.
if (window.location.hash.length && $(location.hash)) {
window.scrollTo(0, $(location.hash).offset().top)
}
check for a hash, find the element's page offset, and scroll there (x, y).
edit: I noticed that, in fact, the page starts at #contact, then scrolls back to the top. I agree with the other answerer that there's something on your page that's scrolling you to the top. I'd search for that before adding a hack.
You can do this with JS, for example` if you have JQuery.
$(function(){
// get the selector to scroll (#contact)
var $to = $(window.location.hash);
// jquery animate
$('html'/* or body */).animate({ scrollTop: $to.offset().top });
});
The name attribute doesn't exists in HTML 5 so chrome looks to have made the name attribute obsolete when you use the DOCTYPE html.
The other browsers have yet to catch up.
Change
<a name="contact"></a>
to
<a id="contact"></a>
Maybe this workaround with vanilla javascript can be useful:
// Get the HTMLElement that you want to scroll to.
var element = document.querySelector('#contact');
// Stories the height of element in the page.
var elementHeight = element.scrollHeight;
// Get the HTMLElement that will fire the scroll on{event}.
var trigger = document.querySelector('[href="#contact"]');
trigger.addEventListener('click', function (event) {
// Hide the hash from URL.
event.preventDefault();
// Call the scrollTo(width, height) method of window, for example.
window.scrollTo(0, elementHeight);
})

Categories