I have multiple div like below
<div class="one">send Message</div>
<div class="one">send Message</div>
<div class="one">send Message</div>
I have a web page where there is send Message buttons like above, in which only one button is visible at a time.Other two buttons are hidden via some javascript codes.So for example if 2nd button is visible , I should be able to click only that element.But in my selenium code , its trying to click first hidden div and its failing
driver.findElements(by.className(".one")).then((els) => {
var element = els[index];
element.click();
});
So basically I wanna convert below javascript code to Selenium nodejs code,If some one guide me that will be helpful
var all = document.getElementsByTagName("*");
for (var i = 0, max = all.length; i < max; i++) {
if (isHidden(all[i]))
// hidden
else
// visible
}
function isHidden(el) {
var style = window.getComputedStyle(el);
return ((style.display === 'none') || (style.visibility === 'hidden'))
}
Do you want to click the button ( basically a div as far as code is concerned ) which is visible ?
If that is your main agenda, then the code you've written will fail to find desired element. As you are selecting the element by it's classname not its visibility.
Your code will find all the matched class element. As it's a basic element selector and all your buttons have the same class, so they are basically rendered on the page.
Approach 1
driver.findElements(by.className(".one")).then((els) => {
for(var key in els){
var element = els[key];
if(element.isDisplayed()){ //if visible element
element.click();
}
}
});
The Key here is to check if the element you are trying to click is visible on the page.
Approach 2
By giving a unique class to the target button. Some class for eg 'clickable' or 'active'. So it will be a more optimized solution to select the target element using the Css selector. The Key here is to give uniqueness to your target element to be more identifiable.
Usually many Java Scripts are run in the node Js without the convert.
Have you try it in the node Js without converting ???
** Remember to import selenium
Related
What do I have - I'm automating one website where there is a big list of elements but not loaded all at once. Say for example I have 200 elements in the list, but only 10 elements are loaded at the moment, and out of these 10 only 5 are visible on the screen.
What I want to do - Now I want to select all of these elements 1 by 1, by clicking on them, because clicking on element selects check box in front of each (Basically i want to tick checkbox). So i will 1st select 5 elements which are visible on page, then i will scroll down to select another visible group, like wise i want to select all 200 elements.
What Problem I'm facing - webdriver.findElements(..) method is returning list of 10 elements which are loaded. But it is not returning list in the order in which the elements are displayed on the page. I'm using for loop to iterate over the list and clicking on elements one by one.
As a result if 6th element is clicked which is not displayed in page, page scrolls till that element and click it, now after that if 2nd element got chance to be clicked, then page should scrolls up to click it, but this time since DOM has loaded again due to scrolling, I get StaleElementReferenceException. If I handle this exception within try catch and get element list again by finding elements, it is not guaranteed to be in the correct order and does not solve my problem.
Solution?? - Is there any way in selenium to get list of elements in order it is displayed on page? Or please let me know what should be the approach to achieve above scenario?
Any suggestions are much appreciated.
Note - JAVA is being used as a programming laungage.
If you also post the HTML that would be more helpful to explain the solution. I am trying to give you a solution by making some assumptions.
Taking a sample HTML code
<div id "checkbox_container>
<input type="checkbox " id="checkbox1 ">
<input type="checkbox " id="checkbox1 ">
<input type="checkbox " id="checkbox1 ">
<input type="checkbox " id="checkbox1 ">
.
.
.
<input type="checkbox " id="checkbox1 ">
</div>
Now write the locators that will give the count of the available checkbox elements and a locator that will select the specific checkbox.
public class SamplePageObjects {
//This locator will select all available checkboxes
public static By ALL_CHECK_BOX = By.xpath("//div[#id='checkbox_container']//input");
//This locator will select the particular element for the given index
public static getMeExpectedCheckBox(int index, int maxCount) {
if (index < 0 || index > maxCount) {
throw new IlleagalArgumentException(index+" is not a valid index");
}
return By.xpath("//div[#id='checkbox_container']//input[" + index + "];
}
}
Now, write your page class
public class SamplePage{
//Gives the count of available elements
public int getCountOfAvailableCheckBox(WebDriver driver){
return driver.findElements(SamplePageObjects.ALL_CHECK_BOX).size();
}
//Selects the specific element
public void selectWebElement(WebDriver driver,int index){
driver.findElement(SamplePageObjects.getMeExpectedCheckBox(index).click();
}
//Selects all available element one by one
public void click(){
int totalCount = getCountOfAvailableCheckBox();
for(int i=0; i< totalCount-1; i++){
try{
selectWebElement(i,totalCount);
} catch(StaleElementReferenceException e){
selectWebElement(i,totalCount);
}
}
}
So first get the list of all available checkboxes. After getting the count, just pass the index value to the locator and perform the action.
Hope it will help you.
I need some help in selecting a div form many div's that for every session number of div's are changing.
For example:
one time a have the div in that position(absolute path): /html/body/div[97]
other time in that position (absolute path):/html/body/div[160]
and so on...
At a moment only one div is active and the other div's are hidden.
I attached a picture to show the code.
I try the xpath below but doesn't work,I get the error "no such element: Unable to locate element ...
driver.findElement(By.xpath(".//*[#class=\'ui-selectmenu-menu ui-selectmenu-open\']/ul/li[1]")).click();
Picture with html code is here:
XPath is great if you expect the target element to be in the exact location every time the page is displayed. However, CSS is the way to go if the content is constantly changing.
In the example below I have found the DIV and the Element that you highlighted in your screen capture.
WebElement targetElementDiv = null;
WebElement targetElement = null;
targetElementDiv = driver.findElement(By.cssSelector("[class='ui-selectmenu-menu ui-selectmenu-open']"));
if (targetElementDiv != null) {
targetElement = targetElementDiv.findElement(By.cssSelector("[class='ui-menu-item ui-state-focus'])");
}
I need to select all the checkboxes from here one-by-one after every 3 second. I tried couple of xpaths with list,none of them have worked
Tried xpaths:
//div/div[#class='filters-list sdCheckbox ']
Using input and type. But none of them worked. Can you please help me out?
Reference website: https://www.snapdeal.com/products/storage-devices?sort=plrty
->Capacity at the left hand corner
By.xpath("//a[#class='filter-name']") this one listed out all the filters of page.
The xPath "//div[#data-name='Capacity_s']/div[#class='filters-list sdCheckbox ']/input" will fetch you the list of all input elements that you need to check.
There is a container DIV that holds all the filters of a certain type, e.g. Brand, Capacity, etc. The one for Brand is shown below.
<div class="filter-inner " data-name="Brand">
Under that container, all the LABEL tags are what you need to click to check the boxes. So, we can craft a CSS selector using the grouping as a filter to reach only the checkboxes we want.
"div[data-name='Brand'] label"
Since this is something I assume you will reuse, I would write this as a function.
public static void CheckFilters(String filterGroup)
{
WebDriverWait wait = new WebDriverWait(driver, 10);
List<WebElement> filters = driver.findElements(By.cssSelector("div[data-name='" + filterGroup + "'] label"));
// System.out.println(filters.size()); // for debugging
for (int i = 0; i < filters.size(); i++)
{
filters.get(i).click();
// wait for the two overlays to disappear
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("div.searcharea-overlay")));
wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("div.filterLoader.hidden")));
// reload the element list after the refresh so you don't get StaleElementExceptions
filters = driver.findElements(By.cssSelector("div[data-name='" + filterGroup + "'] label"));
}
}
and you would call it like
driver.get("https://www.snapdeal.com/products/storage-devices?sort=plrty");
CheckFilters("Brand");
We have two button named “Inschrijven” in Tab1 section and Tab2 section as shown in below image
Tab 1:
<span class="form-submit-wrapper"><input type="submit" id="edit-submit--3" name="op" value="Inschrijven" class="form-submit"></span>
Tab 2:
<span class="form-submit-wrapper"><input onclick="return validate_course_anywhere(this)" type="submit" id="edit-submit--22" name="op" value="Inschrijven" class="form-submit"></span>
When I click element with id "edit-submit--3" This behat code scenario is worked in Tab 1 section but not in tab 2 section ( When I click element with id "edit-submit--22")
/**
* #When /^I click element with id "([^"]*)"$/
*/
public function iClickElementWithId($class) {
$locator = "#$class";
$element = $this->getSession()->getPage()->find('css', $locator);
if (null === $element) {
throw new \InvalidArgumentException(sprintf('Could not evaluate CSS selector: "%s"', $locator));
}
$element->click();
$this->getSession()->wait(1000);
}
But error message is displaying in Tab 2 section:
Exception thrown by (//html/descendant-or-self::*[#id = 'edit-submit--22'])[1]
Element is not clickable at point (813.5, 16.666671752929688). Other element would receive the click:
It seems that the selector is ok, the issue here is that is not clickable and some other element is in the front of it and receives the click.
Some of the possible issues:
1. wait for the element to be visible
2. you have 2 elements with the same id and the first one is found but not clickable
3. wait for the page to be loaded if needed
To use the onClick attribute you can use a css selector like: [onclick*='some_value_from_attribute']
You should have a method to click by selector and not particular method for just one attribute.
Another thing to avoid is using blind waits, you should try to use conditional waits.
Is there any way to disable all input fields in an div container with dojo?
Something like:
dijit.byId('main').disable -> Input
That's how I do it:
dojo.query("input, button, textarea, select", container).attr("disabled", true);
This one-liner disables all form elements in the given container.
Sure there is. Open up this form test page for example, launch FireBug and execute in the console:
var container = dojo.query('div')[13];
console.log(container);
dojo.query('input', container).forEach(
function(inputElem){
console.log(inputElem);
inputElem.disabled = 'disabled';
}
)
Notes:
On that test page form elements are actually dijit form widgets, but in this sample I'm treating them as if they were normal input tags
The second dojo.query selects all input elements within the container element. If the container had some unique id, you could simplify the sample by having only one dojo.query: dojo.query('#containerId input').forEach( ...
forEach loops through all found input elements and applies the given function on them.
Update: There's also a shortcut for setting an attribute value using NodeList's attr function instead of forEach. attr takes first the attribute name and then the value or an object with name/value pairs:
var container = dojo.query('div')[13];
dojo.query('input', container).attr('disabled', 'disabled');
Something else to keep in mind is the difference between A Dijit and a regular DomNode. If you want all Dijit's within a DomNode, you can convert them from Nodes -> Dijit refs with query no problem:
// find all widget-dom-nodes in a div, convert them to dijit reference:
var widgets = dojo.query("[widgetId]", someDiv).map(dijit.byNode);
// now iterate over that array making each disabled in dijit-land:
dojo.forEach(widgets, function(w){ w.attr("disabled", "disabled"); }
It really just depends on if your inputs are regular Dom input tags or have been converted into the rich Dijit templates (which all do have a regular input within them, just controlled by the widget reference instead)
I would do it like this:
var widgets;
require(["dijit/registry", "dojo/dom"], function(registry, dom){
widgets = registry.findWidgets(dom.byId(domId));
});
require(["dojo/_base/array"], function(array){
array.forEach(widgets, function(widget, index) {
widget.set("disabled", true);
});
});
Method findWidgets is essential to get all widgets underneath a specific DOM.