Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow locating disabled buttons or fields #47

Closed
wapcaplet opened this issue Dec 6, 2012 · 8 comments
Closed

Allow locating disabled buttons or fields #47

wapcaplet opened this issue Dec 6, 2012 · 8 comments

Comments

@wapcaplet
Copy link
Contributor

Commit a8f970d appears to have removed the ability to locate a disabled form field or button. For example, given this HTML:

<input type="submit" value="Save" disabled="disabled" />

Then an attempt to merely find the button fails:

page.has_xpath?(XPath::HTML.button("Save"))
=> false

I don't think the button xpath should be contingent upon the button being enabled. The button exists, and is visible to the user. I understand that for the purposes of interactivity (clicking/activating it), we may want the button to be "nonexistent". Perhaps it would make sense to include a second parameter to the #button method?

def button(locator, must_be_enabled=false)
  if must_be_enabled
    ...
  else
    ...
  end
end

Then one could do:

XPath::HTML.button("Save", true) # nil if the button exists, but is not enabled
XPath::HTML.button("Save", false) # returns enabled or disabled button

Or maybe separate methods specifically for locating enabled buttons/fields:

def button(locator) ...
def enabled_button(locator) ...

(I think I prefer the second solution; positional boolean parameters make for poor readability in client code).

Or is there another way to locate disabled buttons/fields that I'm overlooking?

I'd be happy to implement either of the above solutions and submit a pull request, but thought it best to discuss beforehand.

@jamesarosen
Copy link

I strongly agree. I'd like to test that certain fields and buttons start off as disabled, then become enabled as the user changes other data.

I had even written the following Capybara extensions before I realized that XPath was doing the filtering automatically (and without an override):

Capybara::Node::Element.class_eval do
  def enabled?
    !disabled?
  end

  def disabled?
    self[:disabled] == 'disabled'
  end
end

Capybara::Selector.class_eval do
  all[:button].filter(:enabled)  { |node, value| value ^ node.disabled? }
  all[:button].filter(:disabled) { |node, value| value ^ node.enabled? }
end

None of the other XPath selectors take multiple arguments. Thus, I recommend either

  1. multiple methods: field (disabled or enabled), enabled_field, and disabled_field
  2. the locator argument can be a Hash: field(:text => 'foo', :disabled => true) or field(:id => 'bar', :disabled => false)

@caseyprovost
Copy link

I agree with jamesarosen, the ability to find a disabled element is crucial to testing the UI of our application. There are many reasons why someone might want to find disabled inputs for testing.

Some examples:

  • an input starts of disabled, but after some js validation becomes enabled
  • an input is disabled, but when a permissions is granted it becomes enabled

I am a fan of the following tweak to the field finder api:
field(:id => 'bar', :disabled => false)

@Darkvater
Copy link

I agree. Just ran into this issue. Even if a field is disabled you might want to assert its value. Not being able to select the field at all is not optimal to say the least.

@MarceloCajueiro
Copy link

I agree with you guys.

I'm having the same issue here. I'm updating the capybara to 2.0 and now I can't find disabled fields.

So @jnicklas what do you think? Do we can do a patch?

@MarceloCajueiro
Copy link

I did a temporary monkey patch (shame on me) to we use until we found a solution:

module XPath
  module HTML

  protected

    def locate_field(xpath, locator)
      locate_field = xpath[attr(:id).equals(locator) | attr(:name).equals(locator) | attr(:placeholder).equals(locator) | attr(:id).equals(anywhere(:label)[string.n.contains(locator)].attr(:for))]
      locate_field += descendant(:label)[string.n.contains(locator)].descendant(xpath)
      # locate_field[~attr(:disabled)]
    end
  end
end

@jnicklas
Copy link
Collaborator

We no longer filter away disabled elements. Capybara 2.1 implements this as a filter instead of hardcoding it in XPath itself.

@jamesarosen
Copy link

Thanks, @jnicklas :)

@MarceloCajueiro
Copy link

👏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants