Files
sure/test/models/assistant_message_test.rb
Guillem Arias Fauste 5937195df0 fix(chat): clear assistant bubble on destroy so the chat doesn't hang on Thinking (#2315)
* fix(chat): clear the assistant message bubble when a turn is destroyed

When an assistant turn fails before any text streams (e.g. a provider
auth/model/network error on the first call), Assistant::Builtin#respond_to
destroys the still-pending message. Message only broadcast on create and
update, never on destroy, so the rendered 'Thinking…' bubble was never
removed — the chat appeared stuck thinking forever even though the job
had already errored (and appended an error via chat#add_error below it).

Add after_destroy_commit broadcast_remove_to so a destroyed message is
removed from the page.

* refactor(chat): trim destroy-broadcast comment to one line

Project convention asks for comments only when the why is non-obvious; the
behaviour is already covered by the commit/PR description. Per review feedback.

---------

Co-authored-by: Guillem Arias <guillem.arias@col.vueling.com>
2026-06-14 22:09:02 +02:00

29 lines
1.0 KiB
Ruby

require "test_helper"
class AssistantMessageTest < ActiveSupport::TestCase
setup do
@chat = chats(:one)
end
test "broadcasts append after creation" do
message = AssistantMessage.create!(chat: @chat, content: "Hello from assistant", ai_model: "gpt-4.1")
message.update!(content: "updated")
streams = capture_turbo_stream_broadcasts(@chat)
assert_equal 2, streams.size
assert_equal "append", streams.first["action"]
assert_equal @chat.messages_target, streams.first["target"]
assert_equal "update", streams.last["action"]
assert_equal "assistant_message_#{message.id}", streams.last["target"]
end
test "broadcasts remove after destroy so a failed turn's bubble is cleared" do
message = AssistantMessage.create!(chat: @chat, content: "Hello from assistant", ai_model: "gpt-4.1")
message.destroy!
streams = capture_turbo_stream_broadcasts(@chat)
assert_equal "remove", streams.last["action"]
assert_equal "assistant_message_#{message.id}", streams.last["target"]
end
end