aurelius
aurelius

Reputation: 4076

How to check if element contains specific class attribute

How can I check if a selenium web element contains a specific css class.

I have this html li element

<li class="list-group-item ng-scope active" ng-repeat="report in lineageController.reports" ng-click="lineageController.activate(report)" ng-class="{active : lineageController.active == report}">

As you can see inside class attribute there is an active class.

My problem is that I have this element and I want to do a check based on if the class attribute has that "active" value among the others, being more elegant solution then using xpath.

How can I do this?

Upvotes: 42

Views: 90107

Answers (8)

drkthng
drkthng

Reputation: 6909

Given you already found your element and you want to check for a certain class inside the class-attribute:

public boolean hasClass(WebElement element) {
    String classes = element.getAttribute("class");
    for (String c : classes.split(" ")) {
        if (c.equals(theClassYouAreSearching)) {
            return true;
        }
    }
    
    return false;
}

#EDIT As @aurelius rightly pointed out, there is an even simpler way (that doesn't work very well):

public boolean elementHasClass(WebElement element, String active) {
    return element.getAttribute("class").contains(active);
}

This approach looks simpler but has one big caveat:

As pointed out by @JuanMendes you will run into problems if the class-name you're searching for is a substring of other class-names:

for example class="test-a test-b", searching for class.contains("test") will return true but it should be false

#EDIT 2 Try combining the two code snippets:

public boolean elementHasClass(WebElement element, String active) {
    return Arrays.asList(element.getAttribute("class").split(" ")).contains(active);
}

That should fix your caveat.

Upvotes: 47

Nick Kuznia
Nick Kuznia

Reputation: 1768

For anyone looking for a C# implementation:

public static class WebElementExtensions
{
    private static Regex _classNameValidatorRegex = new Regex(@"^[a-z][a-z0-9\-_]*$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
    private static Regex _whiteSpaceRegex = new Regex(@"\s+");

    public static bool HasClass(this IWebElement element, params string[] htmlClasses)
    {
        if (!htmlClasses.Any())
            throw new ArgumentException("No html classes to match.");

        if (!htmlClasses.All(c => _classNameValidatorRegex.IsMatch(c)))
            throw new ArgumentException("Invalid CSS class(es) detected.");

        var classAttribute = element.GetAttribute("class");
        if (string.IsNullOrWhiteSpace(classAttribute))
            return false;

        var elementClasses = _whiteSpaceRegex.Split(classAttribute.Trim()).ToHashSet();

        return htmlClasses.All(c => elementClasses.Contains(c));
    }

    public static bool HasAnyClass(this IWebElement element, params string[] htmlClasses)
    {
        if (!htmlClasses.Any())
            throw new ArgumentException("No html classes to match.");

        if (!htmlClasses.All(c => _classNameValidatorRegex.IsMatch(c)))
            throw new ArgumentException("Invalid CSS class(es) detected.");

        var classAttribute = element.GetAttribute("class");
        if (string.IsNullOrWhiteSpace(classAttribute))
            return false;

        var elementClasses = _whiteSpaceRegex.Split(classAttribute.Trim()).ToHashSet();

        return htmlClasses.Any(c => elementClasses.Contains(c));
    }
}

Upvotes: 1

Mike Godin
Mike Godin

Reputation: 3937

Based on a common pre-classList javascript technique:

public boolean hasClass(WebElement element, String theClass) {
    return (" " + element.getAttribute("class") + " ").contains(" " + theClass + " ");
}

Upvotes: 3

John Collins
John Collins

Reputation: 89

Improving on @uesports135 answer, "classess" should be a String array.

 public boolean hasClass(WebElement element, String htmlClass) {
        String[] classes = element.getAttribute("class").split("\\s+");
        if (classes != null) {
            for (String classAttr: classes) {
                if (classAttr.equals(htmlClass)) {
                    return true;
                }
            }
        }
        return false;
    }

Upvotes: 2

JohnP2
JohnP2

Reputation: 2167

Use javascript: classList.contains

 WebElement element = By.id("id");
 String className = "hidden";
 JavascriptExecutor js = (JavascriptExecutor) driver;
 Boolean containsClass = js.executeScript("return arguments[0].classList.contains(arguments[1])", element, className);

Upvotes: 4

Krystian
Krystian

Reputation: 2290

Simmilar to previous one, but with java 8 capabilities:

String classes= getDriver().findElement(someSelector).getAttribute("class");
Optional<String> classFindResult = Arrays.stream(elementClasses.split(" ")).filter(el -> el.equals("myClass")).findFirst();
if(openClassFindResult.isPresent()){
    return true;
}
return false;

Upvotes: 2

Ranet Cientouno
Ranet Cientouno

Reputation: 17

Try using contains();

String classes = divPubli.getAttribute("class");
assertTrue("The element does not contain .maClass class .publi",classes.contains("maClass"));

Upvotes: 0

uesports135
uesports135

Reputation: 1123

The answer provided by @drkthng works but you might have a case where the class name is a subset of another class name. For example:

<li class="list-group-item ng-scope active">text</li>

If you wanted to find the class "item" then the provided answer would give a false positive. You might want to try something like this:

public boolean hasClass(WebElement element, String htmlClass) {
    String classes = element.getAttribute("class").split("\\s+");
    if (classes != null) {
        for (String classAttr: classes) {
            if (classAttr.equals(htmlClass)) {
                return true;
            }
        }
    }
    return false;
}

Upvotes: 10

Related Questions