capybara icon indicating copy to clipboard operation
capybara copied to clipboard

Capybara.string treats newlines as meaningful

Open mockdeep opened this issue 3 years ago • 7 comments

Meta

Capybara Version: 3.0 - 3.33.0 Driver Information (and browser if relevant): Not relevant, using Capybara.string

Expected Behavior

Capybara.string should ignore newlines (\n) in content. In Capybara 2.18 the following works:

html = "<p>\nThanks,\nSonya Signer\n</p>"

Capybara.string(html).has_text? "Thanks, Sonya Signer"
#=> true

Actual Behavior

Capybara.string treats newlines in HTML as meaningful content as of Capybara 3.0:

html = "<p>\nThanks,\nSonya Signer\n</p>"

Capybara.string(html).has_text? "Thanks, Sonya Signer"
#=> false

mockdeep avatar Oct 02 '20 23:10 mockdeep

This is because Capybara 3 changed the text method to return something that should more closely match what the browser actually shows on screen. However, the Capybara::Simple class isn't doing as much as others (RackTest for instance) to clean up and parse that stuff. I guess the fact that no one else has commented shows how rarely Capybara.string is actually used since use cases in system/feature testing for it are pretty limited. Not sure whether or not we should change this currently but for now you should be able to pass the normalize_ws option to get what I believe you're expecting.

Capybara.string(html).has_text? "Thanks, Sonya Signer", normalize_ws: true

twalpole avatar Oct 05 '20 19:10 twalpole

Okay, we'll give that a try. We're not actually calling Capybara.string directly, but using them implicitly in view specs like:

expect(rendered).to have_text("Thanks, Sonya Signer")

I guess we'll have to figure out a monkey patch of some sort to handle it.

mockdeep avatar Oct 05 '20 22:10 mockdeep

You should be able to set Capybara.default_normalize_ws = true for your view specs for Capybara 3.x - you'll probably want to reset it to false for feature/system tests though since that setting will most likely go away in Capybara 4.x

twalpole avatar Oct 06 '20 01:10 twalpole

@twalpole is there an alternative that is forward compatible with Capybara 4.x? Or do we just need to kill our view specs?

mockdeep avatar Oct 06 '20 01:10 mockdeep

@mockdeep Probably not -- but that probably means I need to fix what Capybara::Simple is doing. Capybara.default_normalize_ws = true (and the normalize_ws option) was a temporary way to allow people with 2.x specs to run on 3.x, without updating their tests, but will be going away in 4.x. This is because text should be tested for the way the browser displays it (Capybara::Simple is obviously wrong on this currently). The real question is how to implement any Capybara::Simple changes now without breaking any tests that depend on the current behavior.

twalpole avatar Oct 06 '20 23:10 twalpole

The real question is how to implement any Capybara::Simple changes now without breaking any tests that depend on the current behavior.

Well, being that we're the only people on earth affected by this, it may not end up being a problem. That being said, maybe you could somehow use the normalize_ws option or something like it to transition people to the "fixed" version of Capybara::Simple. e.g.:

  • add an option specific to Capybara::Simple, defaulting it to false
  • add a warning that it will change to the true behavior for Capybara::Simple in the next major version
  • remove it in the next major version and normalize whitespace?

mockdeep avatar Oct 07 '20 18:10 mockdeep

Just want to mention that testing something like:

<div>
  <span>Hello</span>
  <span>World</span>
</div>

With:

expect(page).to have_text("Hello World")

Does not work unless normalize_ws is added. Which is surprising because "Hello World" is what users see on screen.

davidalejandroaguilar avatar Feb 07 '23 06:02 davidalejandroaguilar