0
votes

I have a dropdown list in my menu and I'm trying to select one of two options available after clicking the dropdown. I can't get the options to show though and therefore I'm unable to click either one. This is the source code of the dropdown list on the page:

<span class="ribbondropdown combined importantribbonbutton">
<div class="button_ribbon hasimage ">
<div id="ribbon_nav_dashboard_dropper" class="button_ribbon_dropper ">
<div class="inner"></div>

<div class="button_ribbon_dropdownsection" style="left: 1520px; top: 40px; display: block;">
<table class="dropdownlist" width="100%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="icon"></td>
<td class="value">Option 1</td>
</tr>
<tr>
<td class="icon"></td>
<td class="value">Option 2</td>
</tr>
</tbody>
</table>
</div>
</div>
</span>

The first four lines are the area I want to click. the rest of the code is for the section that becomes visible after clicking and here I'd like to click 'Option 2'.

I'm currenlty using the following:

driver.findElement(By.id("ribbon_nav_dashboard_dropper")).click();
driver.findElement(By.xpath("//div[@class='value' and text()='Option 2']")).click();

this however results in a failure:

org.openqa.selenium.ElementNotVisibleException: Element is not currently visible and so may not be interacted with

If I comment out the second line, only clicking on the dropdown to show the options and make the test show the options it does not show. If I do this manually I do get the two options. I've looked at another question with the same exception but the proposed solution did not work for me: Java webdriver: Element not visible exception

3
I just noticed that when I look at the code in Firebug the section containing <div class="button_ribbon_dropdownsection" is greyed out when the options are not showing, if I then click on the icon for the dropdown menu or the arrow to its right the code 'comes to life' and display changes from none to block. If it has not been clicked at all the entire section containing style="left: 1520px; top: 40px; display: block is not present - Hugo
Are are getting exception on the first line? driver.findElement(By.id("ribbon_nav_dashboard_dropper")).click(); - Sighil
What about an implicit wait for the second element? - SiKing
@Striker, I'm getting the exception at the second line, the first line passes without a problem - Hugo
@SiKing, I tried implicitly waiting with the following code but that didn't work (driver.manage().timeouts().implicitlyWait(4, TimeUnit.SECONDS);). Also tried waiting for the element to be visible but that too did not work (new WebDriverWait(driver, 30).until(ExpectedConditions.visibilityOfElementLocated(By.xpath) - Hugo

3 Answers

0
votes

Have you tried scrolling the element to the visible range before firing the action on to it. If the element is out of the visible area selenium cannot fire actions upon it.

WebElement webelement = driver.findElement(By.xpath("//div[@class='value' and text()='Option 2']"))
JavascriptExecutor jsExecutor = (JavascriptExecutor) driver;
jsExecutor.executeScript("arguments[0].scrollIntoView(false);", webElement);
webElement.click();
0
votes

It turned out the option I was trying to click in the dropdown menu was in a section of code that was not available. I am unsure why an automated click did not change the style of a given element but this is required for the options to show. I automatically changed the style of the element with the following:

JavascriptExecutor js = (JavascriptExecutor) driver;
WebElement element = driver.findElement(By.xpath("//div[@class='dropdownsection']"));
js.executeScript("arguments[0].setAttribute('style', 'left: 1520px; top: 40px; display: block;')",element);

Now that the Style is changed the section of code containing the options available is active showing my options and I can now click my prefered option:

driver.findElement(By.xpath("//*[@class='value' and text()='Option 2']")).click();
0
votes

I will start by telling you that I am learning html formatting and syntax so you may find that I'm taking the long-way around a problem. I tried creating a basic webpage locally based on your sample and I was not able to create the drop-down for any validation of this proposal.

That being said...

"If I comment out the second line, only clicking on the dropdown to show the options and make the test show the options it does not show."

Focus on this first. If you can't get the element to show, then you will never be able to click on it.

Based on the described behavior, I think your combo id lookup is perhaps the wrong element in the structure.

By.id("ribbon_nav_dashboard_dropper")

The Junit class below is basically how I would go about testing if I've got the right element for the drop down. Fill in the String arrays in the buildLookups method and the test cases should tell you which of the options you've entered will allow the 'option[2]' to be clicked.

I also took a crack at implementing how the performValidation method would work in this case, but I'd recommend double checking that just to be sure I've understood the problem correctly.

package stackoverflow.proof.selenium;

import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * Parameterized test which can be used to validate lookups for a single well-defined desired interaction in Selenium.
 * 
 */
@RunWith(Parameterized.class)
public class SeleniumLookupValidationUtil {
    /** Test URL where the element should be validated.*/
    private static final String TEST_URL = "myURL";
    /** Function which converts a String into a {@link By#id(String)} reference.*/
    private static final Function<String, By> AS_ID_LOOKUP = new Function<String, By>() {
        @Override
        public By apply(String arg0) {
            System.out.println("Id Lookup: " + arg0);
            return By.id(arg0);
        }
    };
    /** Function which converts a String into a {@link By#xpath(String)} reference.*/
    private static final Function<String, By> AS_XPATH_LOOKUP = new Function<String, By>() {
        @Override
        public By apply(String arg0) {
            System.out.println("xpath Lookup: " + arg0);
            return By.xpath(arg0);
        }
    };
    /** Function which converts a String into a {@link By#cssSelector(String)} reference.*/
    private static final Function<String, By> AS_CSS_SELECTOR_LOOKUP = new Function<String, By>() {
        @Override
        public By apply(String arg0) {
            System.out.println("css Lookup: " + arg0);
            return By.cssSelector(arg0);
        }
    };
    /** Function which converts a String into a {@link By#className(String)} reference.*/
    private static final Function<String, By> AS_CLASS_NAME_LOOKUP = new Function<String, By>() {
        @Override
        public By apply(String arg0) {
            System.out.println("className Lookup: " + arg0);
            return By.className(arg0);
        }
    };
    /** Function which converts a String into a {@link By#linkText(String)} reference.*/
    private static final Function<String, By> AS_LINK_TEXT_LOOKUP = new Function<String, By>() {
        @Override
        public By apply(String arg0) {
            System.out.println("LinkText Lookup: " + arg0);
            return By.linkText(arg0);
        }
    };

    /**
     * Creates the data for running the test instance.
     * @return Collection of Object arrays.  Each array in the collection represents a different test execution.
     */
    @Parameters(name="{0}")
    public static Collection<Object[]> buildLookups() {
        //TODO:  Fill in add as many possible lookups for the drop-down element as you can find.
        String[] ids = new String[]{"id1", "id2"};
        String[] xpaths = new String[]{};
        String[] cssSelectors = new String[]{};
        String[] classNames = new String[]{"A", "B"};
        String[] linkTexts = new String[]{};

        //I use the map so I can loop through the dataset later.
        Map<Function<String, By>, String[]> associations = Maps.newHashMap();
        associations.put(AS_ID_LOOKUP, ids);
        associations.put(AS_XPATH_LOOKUP,xpaths);
        associations.put(AS_CSS_SELECTOR_LOOKUP, cssSelectors);
        associations.put(AS_CLASS_NAME_LOOKUP, classNames);
        associations.put(AS_LINK_TEXT_LOOKUP, linkTexts);

        List<Object[]> parameters = Lists.newArrayList();
        for (Function<String, By> converter: associations.keySet()) {
            String[] lookupStrings = associations.get(converter);
            for (String lookup : lookupStrings) {
                By by = converter.apply(lookup);
                parameters.add(new Object[]{by});
            }
        }

        return parameters;
    }

    /** The By lookup to use for the current test validation.*/
    private final By target;
    /** WebDriver for testing.*/
    private WebDriver driver;

    /**
     * Test constructor.
     * @param lookup By to be used for this validation.
     */
    public SeleniumLookupValidationUtil(By lookup) {
        this.target = lookup;
    }

    /**
     * Creates the webdriver and establishes our validation state.
     */
    @Before
    public void initWebDriver() {
        driver = new FirefoxDriver();
        driver.get(TEST_URL);
        //TODO:  Any other setup to make the test case valid.
    }

    /**
     * Performs the thing we actually want to know about.
     */
    @Test
    public void performValidation() {
        WebDriverWait wait = new WebDriverWait(driver, 30);
        wait.until(ExpectedConditions.elementToBeClickable(target));
        WebElement option2 = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//div[@class='value' and text()='Option 2']")));
        option2.click();
    }

    /**
     * Closes all test browser windows and destroys the driver reference.
     */
    @After
    public void destroyWebDriver() {
        for (String window : driver.getWindowHandles()) {
            driver.switchTo().window(window);
            driver.close();
        }
    }
}

I use the google.guava api quite a bit, you will need that library to run this code. Here is the maven pom dependency I use for that reference:

 <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>LATEST</version>
      <scope>compile</scope>
    </dependency>

Best of Luck.