zachallaun / mneme

Snapshot testing for Elixir
https://hex.pm/packages/mneme
100 stars 5 forks source link

Add auto_assert_receive/auto_assert_received #2

Closed tcoopman closed 1 year ago

tcoopman commented 1 year ago

I don't think it's possible to handle assert_receive and assert_received currently. But this would be great.

I'm not sure it makes complete sense though, because you can potentially receive many messages and only be interested in 1.

zachallaun commented 1 year ago

On the roadmap! I’d also like an auto_assert_raises.

I’ve been explicitly keeping myself from working on these too early, as I really want to get auto_assert “feeling right” before expanding the API.

zachallaun commented 1 year ago

Regarding many messages: Mneme already has the ability to offer multiple patterns that you can select from, so we’ll likely display all messages and you select the one you’re interested in if there are many.

I’ve also been thinking that we could special-case certain conventional messages to generate certain patterns, e.g. :DOWN messages might default to

{:DOWN, _ref, :process, ^pid, :normal}

# instead of 

{:DOWN, ref, :process, ^pid, :normal} when is_reference(ref)
zachallaun commented 1 year ago

Hoping to implement this somewhat soon. Some notes:

How do we handle timeouts for new auto_assert_receives?

# defaults to 100ms, same as assert_receive
auto_assert_receive

# what if we want a different timeout? this is ambiguous
auto_assert_receive 500

# could use an options list, but it's technically still ambiguous,
# just maybe less likely to conflict with an actual message
auto_assert_receive timeout: 500

We could just not allow specifying a timeout other than 100ms, but I don't like that option. I imagine auto_assert_receive with a longer timeout would be a useful tool to understand what messages the test process was getting.

When generating new assertions

test "example test" do
  something_that_should_trigger_messages()
  auto_assert_received   #1
  auto_assert_receive    #2
end

When we don't have a pattern yet, we should just sleep the process for the timeout duration and then snapshot Process.info(self(), :messages). This way, we aren't consuming from the message queue and after prompting for the message, we can emit a regular assert_receive that can consume from the queue.

When updating assertions

test "example test" do
  something_that_should_trigger_messages()
  auto_assert_receive {:ok, :some_message}
end

If we're updating, that means the generated ExUnit assert_receive didn't match the message in the timeout window, so we should just snapshot Process.info(self(), :messages) and use whatever we did get when prompting to update. If the message queue is empty, the assertion fails.

zachallaun commented 1 year ago

Closed by be6b00fb32fb0e09288410e94a170d62e61869e9.