tsvallender
tsvallender

Reputation: 2974

Test failing for feature that works using assert_changes

My chat app has a chat class and a message class; when a message is added to the chat, chat.updated_at should also be updated (achieved with belongs_to :chat, touch: true).

When I test this manually, it works correctly, the time is updated. My test below fails however, and I cannot work out why.

  test "sending a message should update chats updated timestamp" do
    sign_in @user
    assert_changes "@chat.updated_at" do
      post messages_path(params: { message: { 
        text: 'Hello', to_id: @bob.id, chat_id: @chat.id
        }})
      assert_response :success
    end
  end

I simply get the error @chat.updated_at didn't change.

My chat fixture is

one:
  id: 1
  subject: nil
  updated_at: <%= 2.hours.ago %>

Upvotes: 0

Views: 573

Answers (2)

max
max

Reputation: 102046

You need to reload the record from the database to get the object in your test to reflect the changes that were performed in the database:

  test "sending a message should update chats updated timestamp" do
    sign_in @user
    assert_changes "@chat.updated_at" do
      post messages_path(params: { message: { 
        text: 'Hello', to_id: @bob.id, chat_id: @chat.id
        }})
      @chat.reload
      assert_response :success
    end
  end

Remember that @chat in your test and controller point to completely different objects in memory.

Upvotes: 0

Joel Blum
Joel Blum

Reputation: 7878

I think you should use model.reload https://apidock.com/rails/ActiveRecord/Persistence/reload

assert_changes "@chat.reload.updated_at" do

Explanation: Once a Rails model is loaded from DB, when you access an attribute it will use the values that were already read and not make the same query again and again (unless explicitly told to do so with reload). And in your test, Ruby simply compares @chat.updated_at before and after but there is no second query on the second time, simply a cached attribute

Upvotes: 1

Related Questions