Capybara won't find a button by its "name" attribute - html

A W3C-validated HTML 5 web page contains this working, simple button inside a login form.
<input data-disable-with="Signing in, please wait&hellip;"
name="commit" type="submit" value="Sign in" />
I'm writing a largely pointless test :-) in a Rails 3.2.17 application that's just to get the hang of Capybara and I've already got completely stuck Googling, reading documentation and reading source code to the test framework, with no joy - attempting to find this button by its name (i.e. "commit") fails.
click_button("commit")
find_button("commit")
Both result in Capybara::ElementNotFound: Unable to find button "commit". If I use the visible button text of Sign in then the element is found, i.e. these:
click_button("Sign in")
find_button("Sign in")
...both work fine, so it would appear that the XML parser isn't having any trouble finding the element.
Documentation for click_button says that the locator works on "id, text or value", with "text" being meaningless for an input element like this (the visible text is taken from the value attribute), but relevant perhaps for button elements. So, we might expect that to fail, though if we view the code via the documentation, find that it calls down to find in the same way as find_button. Yet find_button is documented differently; it says it locates by "id, name or value". So sadly, we know from this that the documentation is broken because it says two different things for what turns out to be an identical call at the back end.
Either way, the element isn't found by name, and that means the lower level find call isn't searching name attributes as far as I can see. This means Capybara (2.2.1, on Nokogiri 1.6.1) is rather broken in that respect. How come nobody has noticed? I've Googled for ages and it doesn't seem to come up. I seem to be rather missing the point :-)
Why don't I just search for the English text in the button, you might ask? Because of internationalisation. This old, Rails 1 -> 2 -> 3 upgraded app has some I18n parts and other static text parts. I don't want to be forced to put I18n into any view that Capybara tests, just so I can have the test use I18n.t() to ensure a match despite different languages or locale file updates. Likewise, it would clearly be very stupid in 2014 to write hard-coded English strings into my tests.
That's why we have names and IDs and such... The unique (in theory!) identifiers that are machine-read, not human-read.
I could hack up something that CSS-selected by "type=submit" but seriously, why isn't Capybara searching the name attribute when its documentation says it does, and why does the documentation disagree on what attributes are searched on two methods that call down to exactly the same back-end implementation with exactly the same parameters?
TIA :)

It turns out the docs are misleading for both calls, as neither look at the attributes listed. It's also clearly very confusing what exactly a "button" means, since a couple of people herein seemed to think it literally only meant an HTML button element but that's not the case.
If you view the source for the documentation of, say, click_button:
https://github.com/jnicklas/capybara/blob/a94dfbc4d07dcfe53bbea334f7f47f584737a0c0/lib/capybara/node/actions.rb#L36
...you will see that this just calls (as I've mentioned elsewhere) to find with a type of :button, which in turn passes through to Capybara's Query engine which, in turn, ends up just using the standard internal selection mechanism to find things. It's quite elegant; in the same way that an external client can add their own custom selectors to making finding things more convenient:
http://rubydoc.info/github/jnicklas/capybara/master/Capybara#add_selector-class_method
...so Capybara adds its own selectors internally, including, importantly, :button:
https://github.com/jnicklas/capybara/blob/a94dfbc4d07dcfe53bbea334f7f47f584737a0c0/lib/capybara/selector.rb#L133
It's not done by any special case magic, just some predefined custom selectors. Thus, if you've been wondering what custom selectors are available from the get-go in Capybara, that's the file to read (it's probably buried in the docs too but I've not found the list myself yet).
Here, we see that the button code is actually calling XPath::HTML.button, which is a different chunk of code in a different repository, with this documentation:
http://rdoc.info/github/jnicklas/xpath/XPath/HTML#button-instance_method
...which is at the time of writing slightly out of date with respect to the code, since the code shows quite a lot more stuff being recognised, including input types of reset and button (i.e. <input type="button"...> rather than <button...>...</button>, though the latter is also included of course).
https://github.com/jnicklas/xpath/blob/59badfa50d645ac64c70fc6a0c2f7fe826999a1f/lib/xpath/html.rb#L22
We can also see in this code that the finder method really only finds by id, value and title - i.e. not by "text" and not by name either.
So assuming XPath is behaving as intended, though it's not clear from docs, we can see that Capybara isn't documenting itself correctly but probably ought to make the link down to XPath APIs for more information, to avoid the current duplication of information and the problems this can cause for both maintainers and API clients.
In the mean time, I've filed this issue:
https://github.com/jnicklas/capybara/issues/1267

You can also use css selectors which are default capybara locators. People say they are faster.
find('[name=commit]').click
Capybara do not look at name attribute in it's finders :(

You can use xpath selector if you want
find(:xpath, "//input[contains(#name, 'commit')]").click()

If anyone wants it is possible to add (quite easily) find by name selector. In order to do so:
Add following code to test/test_helper.rb (for minitest)
Capybara.add_selector(:name) do
xpath { |name| XPath.descendant[XPath.attr(:name).contains(name)] }
end
Use it
Now in your tests you can use following selector:
find(:name, 'part_of_the_name_attribute')
It will find every element which name attribute contains searched value.
Example
find(:name, 'user')
This will find elements (element could be of any type):
<select name='user_name'>
<input name='name_of_user'>
<textarea name='some_user_info'>

You can use this selector to find a button on a page with RSpec and Capybara:
expect(page).to have_selector(:link_or_button, "Button text")

Check your gem depencies. RSpec 3 or higher works with gem 'rspec-rails', '~> 3.7.1' then capybara version must be gem 'capybara', '~>2.18.0' and poltergeist should be gem 'poltergeist', '~>1.17.0'.

Related

How to use chrome dev tools to find elements based on css class or id?

Long time automation developer here (just for context).
It's been bugging me for quite a while that the dev tools in chrome used to find elements just don't seem to work as I expect. Hopefully someone can point out what I'm doing wrong.
Looking at , say, sauce labs page: https://saucelabs.com/blog/selenium-tips-finding-elements-by-their-inner-text-using-contains-a-css-pseudo-class
ok now that page has div's and anchors
and indeed I can do find ('a') or find('div')
but why do I have a problem using classes or id's ?
The find() method refers to window.find(), a non-standard API for the browser's built-in Find function. It does not find web elements the same way Selenium or Capybara do, and so it does not parse the input as a selector.
You find elements with selectors in Chrome DevTools using document.querySelector() or document.querySelectorAll(). There are no special methods in Chrome DevTools for this, however it does provide the $() and $$() aliases (respectively) to save you time and keystrokes.
You can use jquery code in chrome console, for example if you want to find something with class of "foo" you can write $('.foo') or a id of "bar" you write $('#bar')
You can read all about it here
Also you can just google what you want "Jquery how to find a div with id"

How to find the element in this below case while working with selenium IDE

Firebug shows : <a class="ng-binding" ng-click="goto(menu.MenuInfo.Href)">
FirePath shows : html/body/nav/div[1]/div[1]/ul/li[3]/a
It shows as above when I use Firebug or FirePath to find the web element;
Then I copy it to Selenium IDE Target text and click the find button , But it cannot find the web element.
How can I find the web element and make it run in Selenium IDE to record script?
Automatic XPath detectors are usually not a good choice when trying to figure out the Selenium locator for a specific web element. Especially expressions with numeric indexes (e.g. your li[3]) are likely to change if list/table items are removed, added or resorted.
The best way to locate an element is always by id, as this is always unique (unless you have invalid HTML). But your element doesn't have one, unfortunately.
For <a> elements, it's usually good to use the LinkText for locating the element, provided that a) it's unique and b) your site doesn't have a language toggle functionality, which usually changes all link texts.
Alternatively, you could use the tag name and class via CSS selector:
a.ng-binding
Still, it depends on the structure of your page whether this locator is unique or not. There are no general rules for finding the best locator, just good and bad strategies.

getElementByID() parameter explanation

Im looking at some automation scripts that were working with a web portal to save a lot of grunt work. The commands for selecting windows and such makes sense to me, however there are a lot of lines that look like
Set oSelect = wndw.document.getElementById("pvBody:PageTemplate:innerHolder:ctrlAddPassword:ddlSafename")
Or
Set oSelect = wndw.document.getElementById("pvBody:PageTemplate:innerHolder:ctrlAddPassword:PasswordProperties:rptRequiredProperties:_ctl2:ctrlRequiredProperties:ddlValue")
I understand what the program is doing here: it's selecting an element on the page to work with, but the massive string is confusing to me. I know it probably means nothing without the website itself, but it's all I have to go on myself.
I want to know how to find out what I would put there. Is it as simple as inspecting an element, or do I need to dig into the pages source to find out what it's named?
The strings are IDs of HTML elements. Someone apparently saw fit to choose IDs with some sort of inner structure, presumably to make them easier to find/generate/handle/whatever. From an HTML perspective they're just opaque strings, though. They could just as well be named "foo" and "bar" as long as they're unique inside the page.
If you need to identify IDs of elements you want to work with, you need to look at either the page source where such an element might look like this:
<select id="pvBody:PageTemplate:innerHolder:ctrlAddPassword:ddlSafename">
<option value="foo">23</option>
<option value="bar">42</option>
...
</select>
or at the code generating the page source (which implements the logic by which the ID is generated).

HTML rel="up" attribute?

I'm using mobile template HTML files on a PHPBB forum.
I tested the html for errors at http://validator.w3.org/
The test results showed the following error
Line 24, Column 66: {navlinks.FORUM_NAME}
Bad value up for attribute rel on element a: The string up is not a registered keyword or absolute URL.
Not having heard back from the author and not finding much on Google search, I'm trying to understrand what rel="up" does, if anything constructive.
Can't find any mention as an official HTML attribute
http://www.w3schools.com/tags/att_link_rel.asp
wondering if it's probably safe to just remove the phrase rel="up"
The Internet Assigned Numbers Authority (IANA) keeps a list of link relationships The latest version is from March 21 2013.
up: Refers to a parent document in a hierarchy of documents.
Unfortunately, despite the fact that this registry was long established, it was decided that HTML5 would not use this registry and would use a Wiki page to list the conforming link types instead.
Up, is listed in a rather insane section marked "dropped without prejudice", which nobody seems to know what to do with, or how to get those link types out of.
It's safe to drop it, but some browsers and browser plugins make use of it. For example, I use a Firefox plugin called "Link Widgets" like this to make use of the link type.
From: http://www.w3.org/MarkUp/html3/dochead.html
REL=Up
When the document forms part of a hierarchy, this link references the immediate parent of the current document.
If this is causing any specific problems or unexpected results, please post your code. Thanks.

Search box microformat?

Is there any microformat/standard for implementing search form on the site?
(access keys, naming etc.)
Any good practices?
The only things I can think of are that searches should be GET requests, and that you may want to implement a RESTful API that allows developers to query JSON and XML results in addition to HTML
If you are trying to implement a plugin for browsers like IE and Firefox to allow for search/autocomplete in the search box of the browser, check out this: https://developer.mozilla.org/en/creating_opensearch_plugins_for_firefox
Here are some conventions I follow. Forgive me if these are not exactly on topic with microformats, or "technically not" in the way I describe the various parts to my answer.
I have found validation in these few standards I've copied from others:
HTML form ID = "search"
Action URL for the form is //root-of-site/search/
Search Results URL construct:
//root-of-site/search?q=queryClause1+Clause2&AnotherParamName=foo
[personally that structure bugs me a little because search-forward-slash appears to be a directory, and the search-question-mark looks like a page taking a query string, and IMO a page should have a suffix. I've been tempted to use search.cgi or search.app, but I see the big guys using /search?q= and so it is]
ID of search query is "q" (this is nearly universal in adoption)