Unable to get element based on text in css selectors [duplicate] - css

I am working on selenium python in firefox. I am trying to find element by css selector
element = "span:contains('Control panel')"
my_driver.find_element_by_css_selector(element)
I am getting below error
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.InvalidSelectorException: Message: Given css selector expression "span:contains('Control panel')" is invalid: InvalidSelectorError: 'span:contains('Control panel')' is not a valid selector: "span:contains('Control panel')"
In selenium IDE I am successfully able to find element by this field but in Python it is not working

The error says it all :
selenium.common.exceptions.InvalidSelectorException: Message: Given css selector expression "span:contains('Control panel')" is invalid: InvalidSelectorError: 'span:contains('Control panel')' is not a valid selector: "span:contains('Control panel')"
As per Issue#987 and Issue#1547:
The :contains pseudo-class isn't in the CSS Spec and is not supported by either Firefox or Chrome (even outside WebDriver).
The pseudo-class was specific to the Sizzle Selector Engine that Selenium 1.0 relied on. But, it was decided that WebDriver was not going to support the Sizzle style CSS selectors that Selenium 1.0 used.
Now, an interesting fact is the :contains pseudo-class will work for browsers that don't natively support CSS selectors (IE7, IE8, etc) which causes
inconsistencies between browsers and selectors.
Hence a better solution would have been to go with any other attribute of the <span> tag as follows :
element = "span[attribute_name=attribute_value]"
Alternate Solution
You can use either of the following xpaths as per the prevailing DOM Tree:
Using text():
element = my_driver.find_element_by_xpath("//span[text()='Control panel']")
Using contains():
element = my_driver.find_element_by_xpath("//span[contains(.,'Control panel')]")
Using normalize-space():
element = my_driver.find_element_by_xpath("//span[normalize-space()='Control panel']")
Using jQuery
You can also use jQuery as follows:
$('span:contains("Control panel")')
Trivia :
A valuable comment from #FlorentB.
CSS selector is not supported by the console either, but JQuery supports it. The $('...') from the console is a shorthand for document.querySelector which is generally overridden with JQuery when the page has it.

Using css_selector to locate element by text is not supported in Selenium (although it will work in the developer tools console). The only possibility is xpath
element = "//span[contains(text(), 'Control panel')]"
my_driver.find_element_by_xpath(element)
Edit: a comment by #FlorentB:
A css selector is not supported by the console either, but JQuery supports it. The $('...') from the console is a shorthand for document.querySelector which is generally overridden with JQuery when the page has it.

Related

CSS `:disable` vs `[disabled]` [duplicate]

I'm trying to style a disabled input. I can use:
.myInput[disabled] { }
or
.myInput:disabled { }
Is the attribute selector the modern CSS3 way and the way to go forward? I used to use the pseudo-class, but I can't find any info on whether they are the old way and won't be supported or whether they're both equal and you can use whatever you like best.
I have no need to support older browsers (it's an intranet application), so is it:
attribute is newer and better
pseudo-class is still the way to go
whichever you like best
there's a technical reason to use one over the other
Is the attribute selector the modern CSS3 way and the way to go forward?
attribute is newer and better
No; actually, attribute selectors have been around since CSS2, and the disabled attribute itself has existed since HTML 4. As far as I know, the :disabled pseudo-class was introduced in Selectors 3, which makes the pseudo-class newer.
there's a technical reason to use one over the other
Yes, to some extent.
With an attribute selector, you're relying on the knowledge that the document you're styling makes use of a disabled attribute to indicate disabled fields. Theoretically, if you were styling something that wasn't HTML, disabled fields might not be represented using a disabled attribute, e.g. it might be enabled="false" or something like that. Even future editions of HTML could introduce new elements that make use of different attributes to represent enabled/disabled state; those elements wouldn't match the [disabled] attribute selector.
The :disabled pseudo-class decouples the selector from the document you're working with. The spec simply states that it targets elements that are disabled, and that whether an element is enabled, disabled, or neither, is defined by the document language instead:
What constitutes an enabled state, a disabled state, and a user interface element is language-dependent. In a typical document most elements will be neither :enabled nor :disabled.
In other words, when you use the pseudo-class, the UA automatically figures out which elements to match based on the document you're styling, so you don't have to tell it how. Conversely, the attribute selector would match any element with a disabled attribute, regardless of whether that element actually supports being enabled or disabled, such as div. If you're using one of the many modern frameworks that rely on such non-standard behavior, you may be better served by using the attribute selector.
In terms of the DOM, I believe setting the disabled property on a DOM element also modifies the HTML element's disabled attribute, which means there's no difference between either selector with DOM manipulation. I'm not sure if this is browser-dependent, but here's a fiddle that demonstrates it in the latest versions of all major browsers:
// The following statement removes the disabled attribute from the first input
document.querySelector('input:first-child').disabled = false;
You're most likely going to be styling HTML, so none of this may make any difference to you, but if browser compatibility isn't an issue I would choose :enabled and :disabled over :not([disabled]) and [disabled] simply because the pseudo-classes carry semantics that the attribute selector does not. I'm a purist like that.
It turns out that Internet Explorer 10 and 11 fail to recognize the :disabled pseudoclass on some elements and only work fine with the attribute selector syntax.
#test1:disabled { color: graytext; }
#test2[disabled] { color: graytext; }
<form>
<fieldset id="test1" disabled>:disabled</fieldset>
<fieldset id="test2" disabled>[disabled]</fieldset>
</form>
The code snipped above renders in IE like this:
As long as you're only styling input elements, you should be fine either way. Still it's a good advice to test the final result in all browsers you wish to support.
Apparently, you can only select and style input elements with ":(pseudoclass)" / ":disabled" , but other elements, such as DIVs, must instead use [disabled].
I often run into this issue when writing SCSS / SASS and try to select a disabled element.
See
CSS selector for disabled elements

Should I use CSS :disabled pseudo-class or [disabled] attribute selector or is it a matter of opinion?

I'm trying to style a disabled input. I can use:
.myInput[disabled] { }
or
.myInput:disabled { }
Is the attribute selector the modern CSS3 way and the way to go forward? I used to use the pseudo-class, but I can't find any info on whether they are the old way and won't be supported or whether they're both equal and you can use whatever you like best.
I have no need to support older browsers (it's an intranet application), so is it:
attribute is newer and better
pseudo-class is still the way to go
whichever you like best
there's a technical reason to use one over the other
Is the attribute selector the modern CSS3 way and the way to go forward?
attribute is newer and better
No; actually, attribute selectors have been around since CSS2, and the disabled attribute itself has existed since HTML 4. As far as I know, the :disabled pseudo-class was introduced in Selectors 3, which makes the pseudo-class newer.
there's a technical reason to use one over the other
Yes, to some extent.
With an attribute selector, you're relying on the knowledge that the document you're styling makes use of a disabled attribute to indicate disabled fields. Theoretically, if you were styling something that wasn't HTML, disabled fields might not be represented using a disabled attribute, e.g. it might be enabled="false" or something like that. Even future editions of HTML could introduce new elements that make use of different attributes to represent enabled/disabled state; those elements wouldn't match the [disabled] attribute selector.
The :disabled pseudo-class decouples the selector from the document you're working with. The spec simply states that it targets elements that are disabled, and that whether an element is enabled, disabled, or neither, is defined by the document language instead:
What constitutes an enabled state, a disabled state, and a user interface element is language-dependent. In a typical document most elements will be neither :enabled nor :disabled.
In other words, when you use the pseudo-class, the UA automatically figures out which elements to match based on the document you're styling, so you don't have to tell it how. Conversely, the attribute selector would match any element with a disabled attribute, regardless of whether that element actually supports being enabled or disabled, such as div. If you're using one of the many modern frameworks that rely on such non-standard behavior, you may be better served by using the attribute selector.
In terms of the DOM, I believe setting the disabled property on a DOM element also modifies the HTML element's disabled attribute, which means there's no difference between either selector with DOM manipulation. I'm not sure if this is browser-dependent, but here's a fiddle that demonstrates it in the latest versions of all major browsers:
// The following statement removes the disabled attribute from the first input
document.querySelector('input:first-child').disabled = false;
You're most likely going to be styling HTML, so none of this may make any difference to you, but if browser compatibility isn't an issue I would choose :enabled and :disabled over :not([disabled]) and [disabled] simply because the pseudo-classes carry semantics that the attribute selector does not. I'm a purist like that.
It turns out that Internet Explorer 10 and 11 fail to recognize the :disabled pseudoclass on some elements and only work fine with the attribute selector syntax.
#test1:disabled { color: graytext; }
#test2[disabled] { color: graytext; }
<form>
<fieldset id="test1" disabled>:disabled</fieldset>
<fieldset id="test2" disabled>[disabled]</fieldset>
</form>
The code snipped above renders in IE like this:
As long as you're only styling input elements, you should be fine either way. Still it's a good advice to test the final result in all browsers you wish to support.
Apparently, you can only select and style input elements with ":(pseudoclass)" / ":disabled" , but other elements, such as DIVs, must instead use [disabled].
I often run into this issue when writing SCSS / SASS and try to select a disabled element.
See
CSS selector for disabled elements

Does selenium webdriver support css contains?

I've read that "the css2 contains function is not in css3, however selenium supports the superset of css 1,2 and 3."
Will contains be supported by Selenium Server using webDriver or it only supported when using the Selenium IDE?
I recently came across some more information that may be useful to you. To use contains in css selector. You will have to use :contains pseudo class however this is not properly supported in recent versions of CSS selector engines,upon which WebDriver relies for CSS selector, hence it is not a preferred way these days. To get the same effect of using a contains use
div[name*='part'] in CSS Selector and will match all div tags where id contains 'part'. This is equivalent to using //div[contains(#name,'part')] in XPath selector.
This question has similar discussions as your own.
Check this stackexchange answer for more information.

Identify if an element has rel="nofollow" attribute using CSS for selenium tests

I am using CSS selectors as the element locators for selenium test scripts.
Now, I want to check if an element has a rel="nofollow" attribute using CSS.
Does any one know how to check this?
The question isn't 100% clear on what you're trying to do, but I'll try to answer anyway.
If I'm reading you correctly, you're working within the Selenium script language, and you want to determine your the Selenium script that the page contains an <a> element that has rel='nofollow' attribute.
According to the Selenium reference page, this should be possible, as Selenium supports most CSS selectors (the exception except pseudo selectors, but they're not relevant for you here).
It also supports DOM references and XPath references, so one way or the other you should be able to check just about anything.
For CSS, the syntax is css=cssSelector, so in your case this would be css=a[rel=nofollow].
This selector will check the page for any <a> element with the rel=nofollow attribute. If you need to check if a specific element has this attribute, then modify the selector to include the ID or class of the element you want - eg a#myspecificelement[rel=nofollow]
This would be used with a Selenium command such as assertElementPresent() to check that the element is present, or a range of other possible Selenium commands.
Hope that helps.
a[rel="nofollow"]
Won't work in all browsers.
A better solution would be to use jquery who selectors are supported in all browsers
$('a[rel="nofollow"]')

Why doesn't the selector h3:nth-child(1):contains('a') work?

I check this selector:
h3:nth-child(1):contains('a')
selector doesn't work?
I check this in firefinder and does return nothing (not info that there is zero elements)
Then check this:
h3:nth-child(1)
and it returns h3, so selector is almost good, but something with this(h3 has text 'a') text goes wrong.
:contains() is not was going to be a CSS3 selector (thanks T.J. Crowder for the link), but it didn't make it, most likely because the way it works tends to lead to severe performance and over-selection issues. For example, if an element E matches :contains() for a given string argument, then all of its ancestors would also match; using it with a universal selector would lead to unexpected results with certain style properties, on top of being slow for the browser.
There is no other CSS selector that serves a purpose like :contains(). So you'll have to find some other way, either by modifying your HTML or even by using jQuery's :contains(), to achieve the effect you want:
Select an h3 element
if it is the first child of its parent
and its text contains the letter 'a'.
For jQuery and Selenium RC users: :contains() is implemented in the Sizzle selector engine used by jQuery, which is also used in Selenium RC (but not Selenium WebDriver). It works as described in this decade-old revision of the CSS3 spec, but again, due to how the spec describes it, you need to use it with care or it may lead to unexpected selections.
On a final note, h3:nth-child(1) can be replaced with h3:first-child, which as a CSS2 selector has better browser support.
If you're trying to use :contains(a) to find an anchor tag (rather than the letter A), you could use:
h3:nth-child(1) a
or
h3:first-child a
The :contains() pseudo-class isn't in the CSS Spec and is not supported by either Firefox or Chrome.
You can find a couple of detailed discussion in:
selenium.common.exceptions.InvalidSelectorException with "span:contains('string')"
Finding link using text in CSS Selector is not working
Solution
As a solution you have to drop the contains() part and your effective locator will be:
h3:nth-child(1)
Further as #BoltClock mentioned within his answer, you can also use:
h3:first-child
As an alternative, you can also use:
h3:first-of-type
tl; dr
selenium.common.exceptions.InvalidSelectorException with "span:contains('string')"
Finding link using text in CSS Selector is not working

Resources