Find out if class name contains certain text

2020-03-26 08:46发布

问题:

As part of my test, the system is supposed to find out if the device being used to open the website is a mobile device or a normal desktop.

I keep getting the error:

"InvalidSelectorError: Unable to locate an element with the xpath expression //*[contains(@class, is-mobile..."

Property from firebug:

<body class="login-page is-desktop">

My test:

public class isMobile {

public static boolean isMobile = false;

public static boolean checkIfMobile(WebDriver driver) throws Exception {

    List<WebElement> list = driver.findElements(By
            .xpath("//body[contains(@class, 'is-mobile'"));
    if (list == null) {
        return false;
    } else {
        return true;
    }
}
}

Can somebody please tell me how the correct XPath should be?

回答1:

You seem to be missing the closing round and square brackets:

Change this:

//body[contains(@class, 'is-mobile'

Into this:

//body[contains(@class, 'is-mobile')]

As a side note, take into account that this code has another slightly hidden issue and it is that you will match things that you do not want to match such as this class attribute: login-page not-is-mobile.

There is no way to simply match that as you would using the CSS3 selector [class~="is-mobile"]. However, you can come around this by doing this:

//body[contains(concat(' ', @class, ' '), ' is-mobile ')]

All those spaces are there to make sure you will match only something between spaces and that it also matches even if it is at the beginning or end of the class attribute.

It is ugly indeed but that is the XPath way of doing this.



回答2:

This is a great example of using the wrong tool. One of the things that the HTML designers got wrong was using a single class string attribute to encode multiple values. Unfortunately, the XPath designers, who at least had an array construct available to them, failed to remedy this error. So don't use XPath for this, even though, as Mosty Mostacho says, you can make it owork.

The CSS designers did a better job. Although they didn't do something array-like, they at least elevated the class above a simple string. Use By.cssSelector('body.is-mobile') - it's a proper use of CSS locators.