-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Introduce Node#has_element?
#2700
Conversation
9dd66fa
to
db4abfe
Compare
The reason this hasn't been done previously is because of the difficulty in communicating the edge cases around the system option collisions and peoples general inability to understand the difference between properties and attributes. That combined with my belief we should be getting rid of the predicates rather than adding more has me leaning towards no on this, but I'll leave it open while I think about it |
While other, more specific, selectors and matches exist, it's very common for test suites to fall back to CSS's support for attribute matching. For example, it's common for suites to find `<img>` elements by their `[src]` value through concatenating a CSS Selector string: ```ruby have_css("img[src=#{image_path}]") ``` Sometimes, including double quotes into the String isn't necessary, but when it is, it leads to escaping, combined `'` and `"` usage, alternative syntaxes like `%{...}`, or calls to `String#inspect`: ```ruby have_css("img[src=\"#{image_path}\"]") have_css('img[src="#{image_path}"]') have_css(%{img[src="#{image_path}"]}) have_css("img[src=#{image_path.inspect}]") ``` The `:element` selector thrives in circumstances like this: ```ruby have_selector :element, "img", src: image_path ``` In my experience, it's uncommon for teams to even _be aware_ that the `:element` selector exists, let alone make longer-form calls like `have_selector` that require both the `:element` and `"img"` argument. This commit proposes the `Node#has_element?` and `Node#has_no_element?` methods to power `have_element`, `assert_element`, etc. The hope is that the generated Ruby documentation will popularize the use of the `:element` selector.
db4abfe
to
cf6f6a3
Compare
I'm not sure I understand what you mean. Would you be able to share an example?
When I introduced these changes, I only had Rack Test, structure, and attributes in mind. I hadn't considered access to properties. Since these new methods boil down to short-hands for the
Is the idea that reducing the number of aliases like |
As an example, what exactly does On the predicates question, I'm referring to only the predicate methods (those ending in ?) not the matchers. There really is no good reason for using the predicates in tests, and yet people continue to do so. |
@twalpole would this be a more acceptable changeset if it only introduced the |
@twalpole as an alternative to playing whack-a-mole with selectors and helpers, I wonder if you're interested in expanding Capybara's public API to make this something that consumer applications or libraries can do on their own. Something like: class ATestCase < ActiveSupport::TestCase
include Capybara::Minitest::Assertions
define_assertions_for_selector :element
end
RSpec.describe MyClass do
define_matchers_for_selector :element
end Capybara could use that same macro internally. I think it might be helpful to provide simplified user-facing porcelain. I've made the mistake of defining an assertion like: def assert_element(...)
assert_selector(:element, ...)
end
def assert_no_element(...)
assert_no_selector(:element, ...)
end While this works for most cases, it ignores baking-in support for the I'm happy to explore this in a separate PR. Is that something that would be a compromise on the continuum between adding a new predicate method and making no changes? |
I've changed my mind on this, I'm going to merge just for consistency in the v3.x branch --- can revist cleanup when we get to 4.x |
|
||
it 'should be true if the given element is on the page' do | ||
expect(@session).to have_element('a', id: 'foo') | ||
expect(@session).to have_element('a', text: 'A link', href: '/with_simple_html') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test generates invalid xpath:
$x("(.//*[(local-name(.) = 'a')][(./@href = '/with_simple_html')])[]")
VM99:1 Uncaught DOMException: Failed to execute '$x' on 'CommandLineAPI': The string '(.//*[(local-name(.) = 'a')][(./@href = '/with_simple_html')])[]' is not a valid XPath expression.
at <anonymous>:1:1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same error on WebKit, Firefox.
https://github.com/YusukeIwaki/capybara-playwright-driver/actions/runs/7960366033/job/21729306511?pr=71
While other, more specific, selectors and matches exist, it's very common for test suites to fall back to CSS's support for attribute matching.
For example, it's common for suites to find
<img>
elements by their[src]
value through concatenating a CSS Selector string:Sometimes, including double quotes into the String isn't necessary, but when it is, it leads to escaping, combined
'
and"
usage, alternative syntaxes like%{...}
, or calls toString#inspect
:The
:element
selector thrives in circumstances like this:In my experience, it's uncommon for teams to even be aware that the
:element
selector exists, let alone make longer-form calls likehave_selector
that require both the:element
and"img"
argument.This commit proposes the
Node#has_element?
andNode#has_no_element?
methods to powerhave_element
,assert_element
, etc. The hope is that the generated Ruby documentation will popularize the use of the:element
selector.With this new method, the calls above are much more concise:
They even support regular expressions in a way that was tricky before: