rubocop / rubocop-capybara

Code style checking for Capybara files.
https://docs.rubocop.org/rubocop-capybara
MIT License
40 stars 8 forks source link

Add new `Capybara/ClickLinkOrButtonStyle` cop #61

Closed ydah closed 11 months ago

ydah commented 1 year ago

Fix: https://github.com/rubocop/rubocop-capybara/issues/58


Before submitting the PR make sure the following are checked:

If you have created a new cop:

mvz commented 11 months ago

I'm not sure why it's supposed to be bad to use click_link_or_button when you don't know or care what interface element is used, but use a more specific method when you do know?

Put another way, the issue #58 says "There is no information which style is preferred.", but I don't think this is a matter of style at all!

iainbeeston commented 11 months ago

Can someone explain the rationale behind why using click_link and click_button is better than click_link_or_button and click_on? Maybe I'm missing something here, but I would have expected click_on and click_link_or_button to be better because your tests will be less tightly coupled to your HTML and it more closely reflects how a user would behave (there's no way a user can tell the difference between a button and a link styled to look like a button)

ydah commented 11 months ago

I thought strict was better when I first created this cop, but I reconsidered that you are right that click_on or click_link_or_button would indeed be less tied to the test and HTML and more faithful to how the user behaves. would you like to send a PR?

iainbeeston commented 10 months ago

@ydah To be honest my preference would be that this rule is disabled by default, but I appreciate that many other people would find it helpful

ydah commented 10 months ago

@iainbeeston Thank you for your feedback, we appreciate it. We will consider whether to enable or disable this cop by default at the time of the next major version update.

samrjenkins commented 10 months ago

For the reasons mentioned above, I too have always preferred click_on.

franzliedke commented 10 months ago

@mvz @iainbeeston @ydah Let me open another round. 🤓

Here's why I will definitely stay with the strict mode (if my team agrees ^^): buttons and links are very different in terms of semantics. No matter whether they look the same to the user, they should not be used interchangably.

I really like that writing good Capybara tests often forces me to solve problems that also solve problems for e.g. sight-impaired users (e.g. somehow creating a unique accessible label to avoid using IDs or other technical details as selectors). With the loose default, this cop would work against that.

mvz commented 10 months ago

For my use case 'strict' mode just means more work when the UI changes.

On the other hand, I don't want to be forced to change everywhere there is click_link to click_link_or_button.

For me, the one thing that would be useful is enforcing a choice of either click_on or click_link_or_button, rather than having a mix. This would mean still allowing click_link or click_button as well.

I see that a PR was merged changing to enforced_style: link_or_button, but I'm afraid this is equally useless to me.

samrjenkins commented 10 months ago

With the loose default, this cop would work against that.

@franzliedke I'm not sure I follow your reasoning. How does link-button agnosticism encourage more accessible markup?

I too am a strong advocate for using Capybara tests as a prompt for improving HTML accessibility, but I normally find myself reaching for title and aria-label attributes rather then converting <a>s to <button>s or vice versa. I'm not sure I see how stricter Capybara click_ matchers helps in this regard.

I also agree that links and buttons should not be used interchangeably; they have different use cases. However, to the user, they provide indistinguishable UX. They are semantically different to an engineer but semantically indistinguishable to the end user.

franzliedke commented 10 months ago

For my use case 'strict' mode just means more work when the UI changes.

@mvz I often find this argument confusing. When behavior changes (and that is the case when changing from button to link, or vice versa), I would expect having to make changes in tests.

I am not proposing to break your use case (you can still configure Rubocop to your preference, strict is just a default), I am just throwing my 2c in to vote against making this the default. If Rubocop makes a choice on a default, then that default should push (or gently nudge) people to do "the right thing", which - to me - is always accessibility over some notion of developer comfort.

For me, the one thing that would be useful is enforcing a choice of either click_on or click_link_or_button, rather than having a mix. This would mean still allowing click_link or click_button as well.

I am confused. According to the examples in #76, the new default link_or_button allows both click_on and click_link_or_button (they are just aliases anyway). And they disallow click_link and click_button.

@franzliedke I'm not sure I follow your reasoning. How does link-button agnosticism encourage more accessible markup?

@samrjenkins I meant to express the opposite: Encouraging devs to ignore the difference between button and link has the potential to hurt accessibility. Thus, the new "loose" (non-strict) default has the potential to hurt accessibility.

However, to the user, they provide indistinguishable UX. They are semantically different to an engineer but semantically indistinguishable to the end user.

I disagree. Keyboard interaction, mouseover, ctrl+click are all different, that's also user-visible behavior.

franzliedke commented 10 months ago

@ydah I just realized that #76 calls the strict setting deprecated. 😱 I obviously prefer to keep strict as default, but at the very least I hope to have convinced you all to at least keep that mode available.

samrjenkins commented 10 months ago

@franzliedke apologies. I mistyped. I should have asked: How does link-button agnosticism DIScourage more accessible markup?

franzliedke commented 10 months ago

Ah, thanks for clarifying. 🙈

Agnosticism enforces the notion that there's no difference between links and buttons; that is factually wrong and hurts accessibility.

mvz commented 10 months ago

@franzliedke

When behavior changes (and that is the case when changing from button to link, or vice versa), I would expect having to make changes in tests.

I agree, but this should only be the case in tests where the change in behavior is relevant to thing being tested. If it is relevant, I would definitely use click_link or click_button. If it is not relevant, I would use click_on.

franzliedke commented 10 months ago

That's great. 👍🏼

Aren't linters supposed to provide the safe path forward, and point out potential problems. (There's always some human judgement necessary, especially when it comes to the amount and level of suggestions that Rubocop makes.) I argue for the default to be that safe path, and for anyone who wants to say "I know what I'm doing", there's rubocop:disable (or the config).

mvz commented 10 months ago

Yes, I'm not against having to configure this cop to do what I want, and I can also see that requiring a specific action would be a good default.

What I am against is the idea that this is a matter of 'style'.

ydah commented 9 months ago

My apologies. I reminded myself that this cop is certainly not something that should be unified one way or the other, and that it is important to use it appropriately. How about we remove this cop for the next major version update?

franzliedke commented 7 months ago

I definitely like having it available, even if I don't prefer the default. 😉

graaff commented 7 months ago

@franzliedke apologies. I mistyped. I should have asked: How does link-button agnosticism DIScourage more accessible markup?

I'm late to the party here since this only showed up in a release now, but the answer to this question is that assistive software for people with disabilities uses the distinction between links and buttons to better help explain what will happen when one is followed or pressed.

If your site is audited for WCAG 2.1 compliance using e.g. links for in-page actions will definitely get flagged and your site won't be compliant. So knowing when to use a button or a link is important even when visible there is not going to be a difference.

I really hope that this default can be reverted so that the default will be to be explicit about using links or buttons and thus create more accessible websites.

ermolaev commented 7 months ago

now false positive if finding link by href

click_link(href: seo_link)

# Capybara/ClickLinkOrButtonStyle: Use click_link_or_button or click_on instead of click_link.
Failure/Error: click_on(href: seo_link)
ArgumentError:
     Invalid option(s) :href, should be one of :above, :below, :left_of, :right_of, :near, :count, :minimum, :maximum, :between, :text, :id, :class, :style, :visible, :obscured, :exact, :exact_text, :normalize_ws, :match, :wait, :filter_set, :focused, :disabled
jgarber623 commented 7 months ago

Similar to @ermolaev's comment above, I'm seeing the same error from Capybara when following this cop's advice:

# Test passes
# Capybara/ClickLinkOrButtonStyle complains
click_button title: "Delete"
# Test fails
# Capybara/ClickLinkOrButtonStyle happy
click_on title: "Delete"

The exception (same as @ermolaev's):

     Failure/Error: click_on title: 'Delete'

     ArgumentError:
       Invalid option(s) :title, should be one of :above, :below, :left_of, :right_of, :near, :count, :minimum, :maximum, :between, :text, :id, :class, :style, :visible, :obscured, :exact, :exact_text, :normalize_ws, :match, :wait, :filter_set, :focused, :disabled

From that, it's not entirely clear to me if this is an issue with this cop's guidance or in Capybara itself. The various methods appear equivalent and I'm having trouble tracing the source of the ArgumentError in the Capybara::Node::Actions class:

# Lines 25–28
def click_link_or_button(locator = nil, **options)
  find(:link_or_button, locator, **options).click
end
alias_method :click_on, :click_link_or_button

# Lines 41–43
def click_link(locator = nil, **options)
  find(:link, locator, **options).click
end

# Lines 57–59
def click_button(locator = nil, **options)
  find(:button, locator, **options).click
end
ydah commented 7 months ago

I think proceeding in the direction of deleting Capybara/ClickLinkOrButtonStyle while creating a transition destination as follows. If you have any opinions, I would like to hear them.