0

I am trying to find the field name "User Settings Updated Successfully" from the following code:

<div id="btn-usersettings" class="tab-content clearfix">
<h4>Set your User Settings in This Section</h4>
<div class="notice success">
<i class="icon-ok icon-large"/>
User Settings Updated Successfully
<a href="#close" class="icon-remove"/>
</div>
<fieldset>
<input type="submit" name="submit" value="Save Changes"/>
</div>

The code that I am using in C# is

var title = Driver.Instance.FindElements(By.ClassName("notice success"))[0];
if (title != null)
    return title.Text;
return " ";

Basically I am trying to clarify, if the user update has been successful or not, so if it is successful I want to code to return me with the text "User Settings Updated Successfully". But the problem that I am facing is even if the update is successful, it is failing to return me the value and it is throwing exception.

  • 1
    Possible duplicate of [Compound class names are not supported. Consider searching for one class name and filtering the results](http://stackoverflow.com/questions/20361643/compound-class-names-are-not-supported-consider-searching-for-one-class-name-an) – JeffC Jul 13 '16 at 18:33
  • You want `driver.FindElement(By.CssSelector("div.tab-content.clearfix"));` or better yet you have an ID, use that `driver.FindElement(By.Id("btn-usersettings"));` – JeffC Jul 13 '16 at 18:35
  • Also, please edit your question and add any error/exception messages you got. – JeffC Jul 13 '16 at 18:36
  • Hey Jeff, thank you for your answer, but I am very new to this, so I really need to ask what is CssSelector("div.tab-content.clearfix") doing? –  Jul 13 '16 at 18:38
  • And I need the field name "User Settings Updated Successfully", the id "btn-usersettings" is for "Set your User Settings in This Section", right? –  Jul 13 '16 at 18:40

2 Answers2

0

That div you're trying to match actually has two classes on it: "notice" and "success".

You'd be better off trying to match it using CSS. Try

var title = Driver.Instance.FindElements(By.CssSelector("div.notice.success"))[0];

This will select a div that has both the "notice" class and the "success" class. The other way to handle this would be to change the class on that div to be "notice-success", which could be matched by the By.ClassName.

Jason Howell
  • 466
  • 1
  • 4
  • 3
0

Since you were asking questions, I thought I would post my comment here so I can explain more. I'll start off with my recommendation (including some changes based on my recommendations) and then explain a couple other methods you could use.

My recommendations

Here's the code I would use

IReadOnlyCollection<IWebElement> title = Driver.FindElements(By.Id("btn-usersettings"));
if (title.Any())
{
    return title.ElementAt(0).Text;
}
return " ";

This code looks for the element by ID and grabs a collection, checks to see if the collection contains any elements (.Any()) and then returns the text f it exists or an empty string if it doesn't.

If you use .FindElement() and it's not there, it will throw an ElementNotFoundException. The recommended way to get around that is to pull a collection and see if the collection is empty. If it's not empty, you grab the first element from the collection and that's the one you want.

Basic rules for finding an element: If the element is always there, use .FindElement(). If there's some uncertainty whether it will be there, use .FindElements() and check to see if there are elements contained using .Any().

My suggestions for your code

Your first line grabs the first element of a collection. There are a few issues. First, always define the correct Type. var will work but there are many reasons not to use it. IWebElement is the C# Type for a web element. IReadOnlyCollection<IWebElement> is the C# Type for a collection of web elements. In your code you use .FindElements() but then only use the first element. If you just want the first element found, you can use .FindElement() instead.

The rest of your code is fine, I just provided an alternative that I use instead of checking for null.

To answer your question

You have the code

Driver.Instance.FindElements(By.ClassName("notice success"))[0];

By.ClassName() only accepts a single class name. Since the element you want

<div id="btn-usersettings" class="tab-content clearfix">

has two class names, tab-content and clearfix, you will get an error like

Compound class names not permitted

There are a few ways around this.

  1. Stay with By.ClassName() - if you want to do this, you will have to pick only one of the class names to use. You'll have to determine whether a single class name will be unique enough since you have access to all the HTML. It may work but I would recommend another method.

    Driver.Instance.FindElement(By.ClassName("success"));
    
  2. Switch to By.CssSelector() - CSS Selectors are very powerful. I'll give you the code you would need to find this one element but also leave some links that you can review. If you are going to be doing Selenium, you will want to learn CSS Selectors. The code would be

    Driver.Instance.FindElement(By.CssSelector("div.tab-content.clearfix"));
    

    This is looking for a DIV tag that has a class (.) name of tab-content and another class name of clearfix.

    CSS Selector Reference

    CSS Selector Tips

  3. Switch to ID - Recommended. Since your element has an ID, btn-usersettings, I would use that. An ID is, generally, the best way to find an element. By HTML standards, it should be unique on the page so it's the safest, most reliable way to locate an element.

    Driver.FindElement(By.Id("btn-usersettings"));
    
JeffC
  • 22,180
  • 5
  • 32
  • 55