You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
HTML elements can contain multiple text nodes, which is particularly common when working with React-based libraries.
For example, [:div "foo" "bar"] in Reagent, will create a DOM element that the browser sees as <div>"foo" "bar"</div> (as shown in the inspector). (Or, with plain HTML, one can cause this to happen by doing: <div>foo<!-- --> bar</div>)
The current implementation of has-text? translates to the xpath .//*[contains(text(), \"foo bar\")], which only queries the first text node in a DOM element; in the above examples, "foo bar" would not be found, only "foo" would work.
Based on some research, it seems that using text() is an anti-pattern in xpath, and the recommended approach is to use string(): .//*[contains(string(), \"foo bar\")], which concatenates all the descendant text nodes. This approach works to find "foo bar" in the above examples.
I suggest changing the implementation of has-text? and related functions to use string() instead of text().
This does change behaviour slightly (it's more permissive), so alternatively, it might be good to add a :fn/has-string and has-string?.
@rafd thank you for submitting the issue! It has been fixed and will be available in the upcoming 0.3.9 release. Now the :fn/has-text term uses the string() method as you proposed (see the related PR).
HTML elements can contain multiple text nodes, which is particularly common when working with React-based libraries.
For example,
[:div "foo" "bar"]
in Reagent, will create a DOM element that the browser sees as<div>"foo" "bar"</div>
(as shown in the inspector). (Or, with plain HTML, one can cause this to happen by doing:<div>foo<!-- --> bar</div>
)The current implementation of
has-text?
translates to the xpath.//*[contains(text(), \"foo bar\")]
, which only queries the first text node in a DOM element; in the above examples,"foo bar"
would not be found, only"foo"
would work.Based on some research, it seems that using
text()
is an anti-pattern in xpath, and the recommended approach is to usestring()
:.//*[contains(string(), \"foo bar\")]
, which concatenates all the descendant text nodes. This approach works to find"foo bar"
in the above examples.I suggest changing the implementation of
has-text?
and related functions to usestring()
instead oftext()
.This does change behaviour slightly (it's more permissive), so alternatively, it might be good to add a
:fn/has-string
andhas-string?
.Some context / further resources:
The text was updated successfully, but these errors were encountered: