boydm / phoenix_integration

Lightweight server side integration test tools for Phoenix
Apache License 2.0
219 stars 25 forks source link

Regex bug #52

Closed aegatlin closed 2 years ago

aegatlin commented 3 years ago

Hello,

I'm testing against some html with a regex using Regex.compile! and there seems to be a bug where a valid regex will start to throw an error with the following error log:

** (Protocol.UndefinedError) protocol String.Chars not implemented for ~r/Team-oriented ReducedInc\s*blah/ of type Regex (a struct). This protocol is implemented for the following type(s): Phoenix.LiveComponent.CID, Postgrex.Copy, Postgrex.Query, Floki.Selector.AttributeSelector, Floki.Selector, Floki.Selector.Functional, Floki.Selector.Combinator, Floki.Selector.PseudoClass, Decimal, Float, DateTime, Time, List, Version.Requirement, Atom, Integer, Version, Date, BitString, NaiveDateTime, URI
     code: |> assert_response(
     stacktrace:
       (elixir 1.11.3) lib/string/chars.ex:3: String.Chars.impl_for!/1
       (elixir 1.11.3) lib/string/chars.ex:22: String.Chars.to_string/1
       (phoenix_integration 0.8.2) lib/phoenix_integration/assertions.ex:437: PhoenixIntegration.Assertions.assert_body/3
       (elixir 1.11.3) lib/enum.ex:798: Enum."-each/2-lists^foreach/1-0-"/2
       (phoenix_integration 0.8.2) lib/phoenix_integration/assertions.ex:81: PhoenixIntegration.Assertions.assert_response/2

When I look at line 437 of assertions.ex I don't understand what's happening, or how it got there, or why it's in the stack trace at all. It should be going into assert_body_html, and presumably it does when the very similar regex's pass the same test. To that point, a bunch of other versions of the Regex.compile! will work, in particular: Regex.compile!("#{company_name}\\s*") will work, but the minute I add anything after the *, e.g., Regex.compile!("#{company_name}\\s*x") it breaks.

The code which works is essentially:

conn |> follow_path("/") |> assert_response(html: Regex.compile!("#{company_name}\\s*"))

The code which will result in a stacktrace (instead of a pass/fail) is essentially:

conn |> follow_path("/") |> assert_response(html: Regex.compile!("#{company_name}\\s*x"))

The one difference is the x after the *. This is valid regex, of course, and will work in iex.

Thanks :D

boydm commented 3 years ago

Hi @aegatlin Can you please confirm that this issue happens in version 0.9 of phoenix_integration.

This is probably a tricky one to figure out and I'd like to know if it's already been fixed before digging in too deep.

Thank you!

adz commented 3 years ago

@boydm I was experiencing this same issue. I've traced it down to a problem when the RegExp does not match, and you are trying to print the match failure:

  defp assert_body(conn, expected, err_type \\ :body) do
    if conn.resp_body =~ expected do
      conn
    else
      msg =
        error_msg_type(conn, err_type) <>
          error_msg_expected("to find \"#{expected}\"") <>
          error_msg_found("Not in the response body\n") <> IO.ANSI.yellow() <> conn.resp_body

      raise %ResponseError{message: msg}
    end
  end

When rendering "to find\"#{expected}\" it is trying to render the RegExp as a string, which produces the given error, since RegExp can't be:

iex(1)> "#{~r/hi/}"
** (Protocol.UndefinedError) protocol String.Chars not implemented for ~r/hi/ of type Regex (a struct). This protocol is implemented for the following type(s): Postgrex.Query, Postgrex.Copy, Decimal, Integer, NaiveDateTime, Time, Date, URI, BitString, DateTime, Version.Requirement, Version, List, Atom, Float
    (elixir 1.11.3) lib/string/chars.ex:3: String.Chars.impl_for!/1
    (elixir 1.11.3) lib/string/chars.ex:22: String.Chars.to_string/1

To fix, I suppose we should use 'inspect':

iex(2)> "#{~r/hi/ |> inspect}"
"~r/hi/"
adz commented 3 years ago

Addressed here https://github.com/boydm/phoenix_integration/pull/57 Let me know if you'd like anything changed, or done differently

boydm commented 2 years ago

@adz. Thank you for fixing this. I really appreciate it.

The fix is merged into master