How to scroll to the bottom inside of an element with selenium? - javascript

I'm writing in C# with selenium. However, the best way I've found to scroll a page was to use:
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
js.ExecuteScript("window.scrollBy(0,900);");
However, in my current case, the window I need to scroll is not the full page but a part of it. And this command doesn't do anything. I imagined that I need to select the element first so I tried something like this:
js.ExecuteScript("document.getElementsByClassName('scroller')[0].scrollBy(0,500)")
This didn't work either and I'm not sure if its because its wrong as I'm not particularly familiar with JS or if I'm doing something else wrong, like selecting the wrong element to try and scroll.
To sum up my questions are, is there a better way to scroll a window in c# selenium? Is my js code to try and scroll the element wrong? And is there a way to figure out which is the correct element i should try to scroll?

You can use the scrollIntoView(true); to do that, it will brings up the passed element view.
Suppose that you want to scroll until the below element
WebElement element = driver.getElementByClassName('scroller');
then you can do like this :
js.ExecuteScript("arguments[0].scrollIntoView(true);", element);
For multiple elements, you can try the below by passing a matching index number :
js.ExecuteScript("arguments[0].scrollIntoView(true);", driver.getElementsByClassName('scroller')[pass the index number here]);

Related

How toiterate though the website search results using selenium?

I am trying to iterate though pages of search results on this website. Here is a snippet of the HTML code they have for the paging section:
Paging HTML:
Link that I want to use to go to the next page:
Next >>
I was trying to do:
next_page_link = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, "//a[#href='/Catalogue/search?Query=face%20mask&QueryType=All&HideMaskedProducts=False&WasCorrected=False&Page=2&PageSize=10&TotalRecordCount=932&SortDescending=False&CoreListRequest=BrowseAll'")))
next_page_link.click()
but it doesn't seem to work. When I print out next_page_link, it does return an element, so I think the code itself if alright. Is it something wrong with the link? Can I use it the way I am trying to or is there any other way I can iterate thought the result pages?
Thank you!
Your XPATH is probably causing the issue here, so the click is not going to the correct element.
Try something like this
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, '//a/text()[contains(.,"Next")]/parent::*'))).click()
If you want to assign it to the variable and the call the click you can also do it:
next_page_link = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, '//a/text()[contains(.,"Next")]/parent::*')))
next_page_link.click()

toggle divs so only one is open at a time, but be able to close them all as well javascript

I have these divs that I can toggle onclick to scale larger one at a time. It works perfectly except that once one is enlarged, one is always enlarged. I am using toggleOpen for this. I am looking to be able to make it so that it can do what it already does, but then onclick of the enlarged div have it go back to its original size without having to toggle with another div. In other words, I need a way to make the page go back to a state where all the divs are in original size. I have tried else statements to no avail as well as adding another function to remove class. I only want a js solution - no jquery or anything else please. Here is the JS portion of it.
const event = document.querySelectorAll('.eventsBorder')
function toggleOpen() {
let opened = document.getElementsByClassName('large')[0];
if(opened!=undefined)
opened.classList.toggle('large');
this.classList.toggle('large');
}
event.forEach(eventsBorder => eventsBorder.addEventListener('click', toggleOpen));
Here is my codepen
Thanks in advance for any help!
The opened variable gives you back a list of all the HTML elements which have the large class, and when you click again on an already enlarged div that automatically satisfied this criteria. So, what happens is that if you click on the same item twice, your toggleOpen function first removes the large class from that item and then adds it again because of the following line in your code-
this.classList.toggle('large');
The best way to achieve what you want would be to make sure that in addition to opened not being undefined, you should also make sure opened is not the same item as the one you clicked on. You can accomplish that using-
if(opened != undefined && opened != this)
Here is a link to the updated codepen to see it in action.
So it looks like you are using querySelectorAll to select all elements with the class "large", then you're toggling the class. If you toggle the class, it will no longer be a part of that query selection, as it no longer has that class applied, so it will not be able to remove it.
const event = document.querySelectorAll('.eventsBorder')
event.forEach(eventsBorder =>
eventsBorder.onclick = () =>
eventsBorder.classList.toggle('large'));
This seems to accomplish what you'd like.

div scrolling inside an element but with java and selenium

I need to scroll an inner window (i.e. div). I found this web site
How to scroll to an element inside a div?
but this shows how to do Javascript. I am calling the executor but I don't think I can pass values back to java (height, etc). This is my code section. Basically there is a div window with a bunch of elements. Some are hidden on the bottom and do not actually appear in the html unless scrolled to. Once they are scrolled to I believe the will remain there. So I figured I could just scroll a large number and it would not give an error if it were too much, it would just scroll as much as possible.
I scroll to the top and then done, like this:
String sid = rolesScroller.getAttribute("id");
js.executeScript("document.getElementById('" + sid + "').scrollTop -= 1000");
js.executeScript("document.getElementById('" + sid + "').scrollTop += 1000");
waitForXPathVisibility("Scroll", ROLES_SCROLLER_X);
will this be ok or do I need to somehow figure the exact amount to scroll and scroll just by that amount?
I see there is an element.scrollHeight. Does the possible values for scrollTop go from 0 to scrollHeight? Are the units both in pixels?
The elements in the divs are themselves nodes (list values) which can also be expanded creating more elements underneath. Every time I search for a value I have to do the above to make sure everything is in view. The way I have it now works to an extent. But sometimes after scrolling when I try to access a node I get a StaleElementException. However if I do a waitForStaleElement() it sometimes gives an error saying the element did not go stale. Is there a way after executing the javascript that you can make sure all actions have completed so that a stale element won't happen?
To Summarize
When using the javascript executor from Java/Selenium is there a way to pass the javascript variables back to java so they can be used in later jasascript executor commands? (if that example above of -1000 +1000 is OK then this does not matter).
How can you ensure that the javascript command has completed before continuing so when you try to access an element in the scrolled div you will not get a stale element (I tried examining one element in the div, and the div itself).
It seems that the container is dynamically constructed upon scrolling. Try to scroll the last element at the top with scrollIntoView and then wait for a different element at the end:
WebDriverWait wait = new WebDriverWait(driver, 5);
JavascriptExecutor jse = (JavascriptExecutor)driver;
// get the last element
By lastChild = By.cssSelector("#list > div:last-of-type");
WebDriver elem = driver.findElement(lastChild);
// scroll the last element at the top
jse.executeScript("arguments[0].scrollIntoView(true);", elem);
// wait for a new element at the end
wait.until((WebDriver drv) -> !elem.equals(drv.findElement(lastChild)))

JS know the current distance to the top of an object

I want to know, how can I get the distance that a div is from window top, by it's id attribute.
I've already tried
var pubID = "#pub_<?php echo $_GET['pub']; ?>";
alert($(pubID).scrollTop());, and this alert return me "NULL".
I want to use this, when I'am on a determinate page and click on a notification, it redirects the user to another page, and should scroll the new page to the position of the div mentioned on the notification.
Help please,
Gonçalo Ribeiro
Your best bet would be to use jQuery, because offsetTop / offsetLeft don't work consistently in all browsers.
So, assuming you've included jQuery on the page, you could use:
$('#element').offset().top
Also, if you're so inclined, have a read here on the subject here and here.
Edit
Thinking about your problem, would linking to an anchor name (i.e. Adding a hash to the URL) not be easier than trying to work out the position like this?
One link to rule them all

check if jquery ui accordion exists?

is there an easy way to tell if a jquery accordion exists on the page...i am trying to dynamically build accordion based on selection that runs through $ajax, reads values from xml, and depending on the xml file selected builds strings the make up the accordion, and finally appends it.
I think that if the accordion already exists on the page, and the user selects another file, I am having trouble destroying the accordion, clearing the html, append the new string, then creating a new accordion...
like
$("#accordion").accordion('destory').html('').append(string).accordion();
seems like if there is not already an accordion this idea breaks....thinking maybe i can just check?? thanks for any help to beginner!
I suspect that you could try checking .data().
var isAccordion = !!$("#accordion").data("ui-accordion");
Or, by checking the ui-accordion classname using .hasClass() which is added upon initialization.
var isAccordion = $("#accordion").hasClass("ui-accordion");
You could try with .length
Count the element using .length
Or something like this
if($('#accordion').length > 0) {
// do something
}

Categories