Robot framework, how to check class - html

Is there a keyword in Robot Framework to ensure element has a certain class? Something like
Element should has class element className
Alternatively, I could check if element has a certain attribute with certain value. Former would be more suitable though, as element may contain multiple classes.

You could create a new keyword via XPath selectors:
Element should have class
[Arguments] ${element} ${className}
Wait until page contains element ${element}[contains(#class, '${className}')]
Or via CSS selectors:
Element should have class
[Arguments] ${element} ${className}
Wait until page contains element ${element}.${className}
Wait until page contains element could be replaced by any keyword of your liking to check if the element exists and is visible, such as Element should be visible.

Here's an alternative solution (though the accepted answer's CSS one is quite good), working for any kind of selector strategy:
Element should have class
[Arguments] ${locator} ${target value}
${class}= Get Element Attribute ${locator}#class
Should Contain ${class} ${target value}
It can be modified for any other attribute - just substitute the #class in Get Element Attribute with it (or even, make it an optional argument).

Some of the solutions on this page may suffer from sub-string matches. Checking that the class attribute (e.g. test-run) contains a class (e.g. test) may pass even though it should fail.
There are a few ways to deal with this, but in the end, I did the following:
Element Should Have Class
[Arguments] ${locator} ${class}
${escaped}= Regexp Escape ${class}
${classes}= Get Element Attribute ${locator} class
Should Match Regexp ${classes} \\b${escaped}\\b
Element Should Not Have Class
[Arguments] ${locator} ${class}
${escaped}= Regexp Escape ${class}
${classes}= Get Element Attribute ${locator} class
Should Not Match Regexp ${classes} \\b${escaped}\\b

Here below an example of both ways:
${temp}= get element attribute xpath=/elementpath class
should contain ${temp} ${ClassName}
OR
Wait until page contains element xpath=/elementpath[contains(#class, '${ClassName}')

Related

failed to use xpath

To crawl "https://www.reddit.com/r/CryptoCurrency/"
I used xpath to find li element has class named "first"
response.xpath('//li[#class="first"]')
but it returns None
I can't understand what's wrong
as I know '//' finds all elements in document. so I thought it will find all 'li' elements
and predicate [#class="top-matter"] means if element has class attribute named "top-matter", should select it.

attribute selector for class starts with and ends with

I have been reading up on attribute selectors, such as ~ ^ | etc, but I cant figure out the following:
How do I target an element with a class starting with lets say "abc" and also ends with "xyz".
The way I have it now is this:
div[class^="abc"][class$="xyz"]{}
But if my element looks like this, it wont work:
<div class="foo abcDExyz bar">
It only works if abcDExyz is the only class in the class attribute.
Basically, I want to target a class that starts with something... and ends with something. In between that, anything can go (such as 'DE' in my example)
Is my only option to use * instead?
thanks in advance!
You can only do this if you can guarantee that the substrings "abc" and "xyz" will never appear in any other class names within that element's class attribute, and they will never appear separately:
div[class*=" abc"][class*="xyz "]
And even this falls flat when that class name is the first, last, or only one in the class attribute (unless you include the respective ^= and $= attribute selectors, but it's all still very fragile).
Otherwise, you won't be able to do this reliably with just a selector, or even a list of selectors.
You'd have a much easier time if whatever "abc" and "xyz" are supposed to represent was its own class name, instead...

Can I have multiple values in one HTML "data-" element?

Can I have multiple values in one HTML "data-" element? Similar to how a class can have multiple class names.
If possible, I would like to create a CSS/JS library that makes use of one "data-" element to house all of the library styles. For example:
<div data-library-name="xs-hidden col-md-10 col-xl-8 big-hero"></div>
That way, any of the programmers custom style rules can go into the elements class. My reasoning for this is to make readability easier, so together it would look like:
<div class="custom-style another-style" data-library-name="xs-hidden col-md-10 col-xl-8 big-hero"></div>
Can I have multiple values in one HTML "data-" element?
You can have a string. The spec doesn't define any particular format for the data in the attribute, which is designed to be processed by site specific JavaScript.
Similar to how a class can have multiple class names.
The class attribute takes a space separated list of classes.
Your JavaScript can your_data_attribute_value.split(" "); if you like.
Handling this with CSS would use the ~= attribute selector.
[att~=val]
Represents an element with the att attribute whose value is a whitespace-separated list of words, one of which is exactly "val". If "val" contains whitespace, it will never represent anything (since the words are separated by spaces). Also if "val" is the empty string, it will never represent anything.
AFAIK, I don't think data- attributes can convert that to an array. Instead, I think it'll interpret it as one value, but it is allowed.
If you want to do that, you'll probably have to split() it later in JavaScript into an array of usable values.
See this example on JSFiddle.net.
CSS has the shortcut .class selector but it actually is parsing the attribute named "class" as a list for space separated values. This is supported in the non-shortcut form by the following attribute selector:
[att~=val]
Represents an element with the att attribute whose value is a white space-separated list of words, one of which is exactly "val". If "val" contains white space, it will never represent anything (since the words are separated by spaces). If "val" is the empty string, it will never represent anything either.
Ref: http://www.w3.org/TR/CSS2/selector.html#class-html
As your question is tagged CSS you're perhaps looking for that. The rules how the parsing of attribute values is done is given in that document as well, so in case the javascript library you're trying to use on this (if any) won't cover that, it should be easy to add:
var list = $("div").data("library-name").split(/\s+/);
^^^^^^^^^^^^
This split with the white-space regular expression parses the string attribute value into an array with javascript and the Jquery library (for accessing the DOM and the data attribute).

CSS substring matching attribute selectors: Contains multiple class names

A CSS "contains" selector is
td[class*="foo"]
I can select multiple classes with
td[class*="foo bar"]
This however will fail for <td class="foo baz bar" />
How can I do a CSS "contains" wildcard select?
BTW: I cannot use td.foo.bar
The selector you're looking for is as follows, see this question for more details.
td[class*="foo"][class*="bar"]
However, if you need to use selectors like that then it's often a sign that your class name logic is bad.
Honestly I don't know what you mean by "failing" td[class*="foo bar"] selector as it seems working to me in your particular case.
However, since the class names are separated by white spaces, you could use multiple [attr~=value] attribute selectors to select the elements having the classes as follows:
td[class~="foo"][class~="baz"] {
background-color: gold;
}
WORKING DEMO.
From the MDN:
[attr~=value] Represents an element with an attribute name of attr
whose value is a whitespace-separated list of words, one of which is
exactly "value".
Visit : CSS-Tricks (CSS Attribute Selectors)
From the above for finding a match of a given string to the string in the class specified according to your question , the only option I find working and correct is * and ~.
1. Demo for *
2. Demo for ~
Multiple attribute matches

How exactly is [att~=val] different from [att*=val] in CSS Attribute Selectors?

Maybe I am missing something, but they seem similar. If you use for example...
a[alt~="thumb"]
or...
a[alt*="thumb"]
What can I narrow my selection down to differently? I am at the understanding that ~ gives you a partial match in the quotes while the * gives you a partial match. I am going to fiddle with the code a little, but since I could not find a question on the subject here, thought it would make a good topic either way.
From the JQuery help (which supports the standard selectors):
a[alt~="thumb"]
Description: Selects elements that have the specified attribute with a
value containing a given word, delimited by spaces. This selector
matches the test string against each word in the attribute value,
where a "word" is defined as a string delimited by whitespace. The
selector matches if the test string is exactly equal to any of the
words.
a[alt*="thumb"]
Description: Selects elements that have the specified attribute with a
value containing the a given substring. This is the most generous of
the jQuery attribute selectors that match against a value. It will
select an element if the selector's string appears anywhere within the
element's attribute value. Compare this selector with the Attribute
Contains Word selector (e.g. [attr~="word"]), which is more
appropriate in many cases.
Basically the selector ~= only matches if the value is found surrounded by white space. The selector *= matches if the value is found anywhere.
<div alt='heading navigation'>
<div alt='head'>
div[alt~='head'] would match only the second div, but div[alt*='head'] would match both.
[att~=value] is a contains word selector.
So a [alt="foo"] selector will match <a alt="foo bar"> but will not match <a alt="foobar">.
[alt*="foo"] will match both though, because this doesn't discriminate on words or whatever. As long as it's in the value, it hits.