Vasco
Vasco

Reputation: 802

Selenium CSS Selector

I am a newbie in selenium. I am trying to run a suite on Stack overflow website with the below code. The code generates NoSuchElement exception. I am using selenium java client and server (3.7.1) with Chrome Driver (2.33). Using Java 9. On windows 10.

I have validated the css selector using the find feature on Chrome developer tools.

What could be the problem?

public class Suite {

    private static final String home = "https://stackoverflow.com";
    private  WebDriver driver = null;

    public static void main(String[] args) {

        Suite suite = new Suite(true);

            suite.login()
                .clickByCSSSelector("a.my-profile");

    }
    public Suite(boolean isHeadLess) {

        ChromeOptions option = new ChromeOptions();
        if (isHeadLess) option.addArguments("--headless");
        System.setProperty("webdriver.chrome.driver", "D:\\work\\webscraping\\chromedriver\\chromedriver.exe");

        driver = new ChromeDriver(option);
    }
    public Suite login() {

        this.navigate(home)
            .setValue("email", "[email protected]")
            .setValue("password", "xxxxxx")
            .click("submit-button");
        return this;

    }
    public Suite navigate(String target) {
        driver.navigate().to(target);
        return this;
    }
    public Suite setValue(String elementId, String value) {
        driver.findElement(By.id(elementId)).sendKeys(value);
        return this;
    }
    public Suite clickByXpath(String xpath) {
        this.findByXpath(xpath).click();
        return this;
    }
    public Suite clickByCSSSelector(String selector) {
        this.findByCSSSelector(selector).click();
        return this;
    }   
    private WebElement findByCSSSelector(String selector) {
        return driver.findElement(By.cssSelector(selector));

    }
    public WebElement findByXpath(String xpath) {
        return this.find(By.xpath(xpath));
    }

    public WebElement find(By element) {
        return driver.findElement(element);
    }
    public Suite click(String elementId) {
        this.find(elementId).click();
        return this;
    }
    public WebElement find(String elementId) {
        return this.find(By.id(elementId));
    }

}

Exception:

Exception in thread "main" org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"a.my-profile"}
  (Session info: headless chrome=62.0.3202.94)
  (Driver info: chromedriver=2.33.506120 (e3e53437346286c0bc2d2dc9aa4915ba81d9023f),platform=Windows NT 10.0.14393 x86_64) (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 0 milliseconds
For documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html
Build info: version: '3.7.1', revision: '8a0099a', time: '2017-11-06T21:01:39.354Z'
System info: host: 'HMECL000593', ip: '10.0.75.1', os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '9'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Capabilities {acceptSslCerts: true, applicationCacheEnabled: false, browserConnectionEnabled: false, browserName: chrome, chrome: {chromedriverVersion: 2.33.506120 (e3e53437346286..., userDataDir: C:\Users\TOMS~1.VAR\AppData...}, cssSelectorsEnabled: true, databaseEnabled: false, handlesAlerts: true, hasTouchScreen: false, javascriptEnabled: true, locationContextEnabled: true, mobileEmulationEnabled: false, nativeEvents: true, networkConnectionEnabled: false, pageLoadStrategy: normal, platform: XP, platformName: XP, rotatable: false, setWindowRect: true, takesHeapSnapshot: true, takesScreenshot: true, unexpectedAlertBehaviour: , unhandledPromptBehavior: , version: 62.0.3202.94, webStorageEnabled: true}
Session ID: fa8665d6bf99e34431e27b91ec3a1458
*** Element info: {Using=css selector, value=a.my-profile}
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:488)
    at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:214)
    at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:166)
    at org.openqa.selenium.remote.http.JsonHttpResponseCodec.reconstructValue(JsonHttpResponseCodec.java:40)
    at org.openqa.selenium.remote.http.AbstractHttpResponseCodec.decode(AbstractHttpResponseCodec.java:80)
    at org.openqa.selenium.remote.http.AbstractHttpResponseCodec.decode(AbstractHttpResponseCodec.java:44)
    at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:164)
    at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:83)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:600)
    at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:370)
    at org.openqa.selenium.remote.RemoteWebDriver.findElementByCssSelector(RemoteWebDriver.java:464)
    at org.openqa.selenium.By$ByCssSelector.findElement(By.java:430)
    at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:362)
    at com.tv.webscraping.selenium.SeleniumClient.findByCSSSelector(SeleniumClient.java:81)
    at com.tv.webscraping.selenium.SeleniumClient.clickByCSSSelector(SeleniumClient.java:76)
    at com.tv.webscraping.selenium.Suite.main(Suite.java:19)

Chrome Develper tools:

enter image description here

Upvotes: 0

Views: 1434

Answers (2)

Parry
Parry

Reputation: 56

You can also add implicit wait after get(url) shown below. It works throughout script for all elements and waits for page to load. Its good practise to use implicit wait once at the start.

driver.get(url); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

Try this one instead of explicit wait suggested above. And even after using implicit wait, if you get ElementNotVisibleException then add explicit wait for that particular web element.

But using implicit wait will generally help you giving load time for all elements throughout your script.

Hope it helps.

Upvotes: 0

Danny
Danny

Reputation: 287

You may also need to include a wait prior to your click

WebDriverWait wait = new WebDriverWait(webDriver, timeoutInSeconds);

wait.until(ExpectedConditions.visibilityOfElementLocated(By.id<locator>));

See more information for Waits here: WebDriver - wait for element using Java

If this doesn't work, try the following xpath instead, in combination with the wait above .clickByXpath("//a[contains(@class, 'my-profile')]");

Some more information below to explain xpaths:

  • multiple matches: //div[@class='class' and contains(text(), 'text')]
  • partial match: //span[contains(class, 'class')]
  • starts-with: //input[starts-with(@name,'input') These are more beneficial when handling dynamic elements and will be robust.

See more information for xpaths here: https://sqa.stackexchange.com/questions/10342/how-to-find-element-using-contains-in-xpath

Please note: I'd only advise using xpaths when an element is either dynamic, or has no unique ID

Additionally, you could use classname rather then xpath, and example of how I do this in c# is driver.FindElement(By.ClassName("my-profile js-gps-track");

If all the above does not work, you may require the use of actions, something like the below:

Actions actions = new Actions(driver);
actions.moveToElement(driver.findElement(By.id(id)));
actions.click();
actions.build().perform();

Upvotes: 2

Related Questions