phoenixframework / phoenix

Peace of mind from prototype to production
https://www.phoenixframework.org
MIT License
21.35k stars 2.87k forks source link

Channel test fails to compile on Elixir 1.9: "cannot invoke remote function String.Chars.to_string/1 inside a match" #3473

Closed seeekr closed 5 years ago

seeekr commented 5 years ago

Started working again on a project that I last touched on Elixir 1.8. Now on 1.9, when I try to run mix test my channel tests won't compile & run any more:

== Compilation error in file test/.../channels/mytest.exs ==
** (CompileError) test/.../channels/mytest.exs:17: cannot invoke remote function String.Chars.to_string/1 inside a match
    (elixir) src/elixir_bitstring.erl:150: :elixir_bitstring.do_expand_expr/4
    (elixir) src/elixir_bitstring.erl:27: :elixir_bitstring.expand/8
    (elixir) src/elixir_bitstring.erl:10: :elixir_bitstring.expand/4
    (stdlib) lists.erl:1354: :lists.mapfoldl/3
    (stdlib) lists.erl:1354: :lists.mapfoldl/3
    (stdlib) lists.erl:1355: :lists.mapfoldl/3
    (stdlib) lists.erl:1354: :lists.mapfoldl/3
    (stdlib) lists.erl:1355: :lists.mapfoldl/3
    (stdlib) lists.erl:1354: :lists.mapfoldl/3
    (stdlib) lists.erl:1355: :lists.mapfoldl/3
    (stdlib) lists.erl:1354: :lists.mapfoldl/3
    (ex_unit) expanding macro: ExUnit.Assertions.assert_receive/2

Test looks roughly like this:

test "correctly tracking note edit start and end", %{socket: socket} do
    push(socket, "edit_start", %{"note" => 1})

    assert_push "presence_diff", %{
      joins: %{
        "#{@uid}" => %{metas: [%{edits: %{1 => %{}}}]}
      }
    }
  end

The offending line #17 is the one with the assert_push. I don't have any special setup going.

What's going wrong here?

Environment

Elixir 1.9.0 (compiled with Erlang/OTP 22)


* Phoenix version (mix deps): `"phoenix": {:hex, :phoenix, "1.4.9", "746d098e10741c334d88143d3c94cab1756435f94387a63441792e66ec0ee974", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},`
* NodeJS version (node -v): -
* NPM version (npm -v): -
* Operating system: macOS Mojave 10.14.5

### Expected behavior
Test should compile and run.

### Actual behavior
Test does not compile.
seeekr commented 5 years ago

... and just installed elixir 1.8.2-otp-22 via asdf, verified that the occur indeed does not occur there.

josevalim commented 5 years ago

The snippet above works for me on Elixir v1.9.1 as long as the module attribute@uid is set. If it isn't set, then indeed it fails, but it also shows a warning. I didn't check if an unset @uid module attribute worked on v1.8 but I would argue that failing is the correct behaviour, as we need to call String.Chars on any non-binary interpolated value. Thanks for the report!

seeekr commented 5 years ago

@josevalim Ok, but @uid is clearly defined in the module that contains the test definition:

@uid 347435

The compiler is also not printing any warnings about it not being defined. If I remove that line, then it does print the warning you mention.

Am I doing something wrong here?

EDIT: And if I do replace that interpolation of @uid with a plain string, then the failure goes away on v1.9.1.

josevalim commented 5 years ago

@seeekr can you please provide a small app or a failing test case that reproduces the error then? I could not reproduce it with v1.9.1. Thanks!

seeekr commented 5 years ago

Ok, will do!

seeekr commented 5 years ago

@josevalim Here you go: https://github.com/seeekr/phoenixframework_3473

josevalim commented 5 years ago

@seeekr your @arg is an integer. Everything that is not a binary needs to invoke the protocol for conversion. If it works in the past, it was a bug where the protocol was being bypassed. :) Changing it to @arg "123" works.

seeekr commented 5 years ago

@josevalim Hmm, OK, I could understand that. Just 2 things:

1) We should create an issue that tracks improving the resulting error message, because it's not helpful at all. Right?

2) Even with @arg "123" I get an error like this:

CleanShot 2019-07-28 at 17 04 45@2x

(EDIT to add: Same error message 3 times, once per each test method.)

What else am I doing wrong?

seeekr commented 5 years ago
✗ elixir -v
Erlang/OTP 22 [erts-10.4.4] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe]

Elixir 1.9.1 (compiled with Erlang/OTP 20)
josevalim commented 5 years ago

Even with @arg "123" I get an error like this:

you are matching on %{socket: socket} on each test but there is no :socket key in the test data. You are missing it from your setup.

josevalim commented 5 years ago

And I am already working on a better error message for the interpolation one ;)

seeekr commented 5 years ago

Even with @arg "123" I get an error like this:

you are matching on %{socket: socket} on each test but there is no :socket key in the test data. You are missing it from your setup.

Thanks, my bad. Apparently I managed to remove the setup call from the generated test code.