0d138df952
Only index cards and comments if their card is `published?`, using a new method `searchable?` that is implemented on both Card and Comment. This prevents draft cards and their comments from being indexed. When drafts are published, the existing `update_in_search_index` callback creates the record via `upsert!`, or else ensures unpublished records are removed from the index. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
134 lines
5.5 KiB
Ruby
134 lines
5.5 KiB
Ruby
require "test_helper"
|
|
|
|
class Card::SearchableTest < ActiveSupport::TestCase
|
|
include SearchTestHelper
|
|
|
|
test "searchable? returns true for published cards" do
|
|
card = @board.cards.create!(title: "Published Card", status: "published", creator: @user)
|
|
assert card.searchable?
|
|
end
|
|
|
|
test "searchable? returns false for draft cards" do
|
|
card = @board.cards.create!(title: "Draft Card", status: "drafted", creator: @user)
|
|
assert_not card.searchable?
|
|
end
|
|
|
|
test "card search" do
|
|
# Searching by title
|
|
card = @board.cards.create!(title: "layout is broken", status: "published", creator: @user)
|
|
results = Card.mentioning("layout", user: @user)
|
|
assert_includes results, card
|
|
|
|
# Searching by comment
|
|
card_with_comment = @board.cards.create!(title: "Some card", status: "published", creator: @user)
|
|
card_with_comment.comments.create!(body: "overflowing text", creator: @user)
|
|
results = Card.mentioning("overflowing", user: @user)
|
|
assert_includes results, card_with_comment
|
|
|
|
# Sanitizing search query
|
|
card_broken = @board.cards.create!(title: "broken layout", status: "published", creator: @user)
|
|
results = Card.mentioning("broken \"", user: @user)
|
|
assert_includes results, card_broken
|
|
|
|
# Empty query returns no results
|
|
assert_empty Card.mentioning("\"", user: @user)
|
|
|
|
# Filtering by board_ids
|
|
other_board = Board.create!(name: "Other Board", account: @account, creator: @user)
|
|
card_in_board = @board.cards.create!(title: "searchable content", status: "published", creator: @user)
|
|
card_in_other_board = other_board.cards.create!(title: "searchable content", status: "published", creator: @user)
|
|
results = Card.mentioning("searchable", user: @user)
|
|
assert_includes results, card_in_board
|
|
assert_not_includes results, card_in_other_board
|
|
end
|
|
|
|
test "search content is truncated to a reasonable limit" do
|
|
search_record_class = Search::Record.for(@user.account_id)
|
|
|
|
# Create a card with unreasonably long content
|
|
long_content = "asdf " * Searchable::SEARCH_CONTENT_LIMIT
|
|
card = @board.cards.create!(title: "Card with long description", status: "published", creator: @user)
|
|
card.description = ActionText::Content.new(long_content)
|
|
card.save!
|
|
|
|
# Check if was indexed
|
|
results = Card.mentioning("asdf", user: @user)
|
|
assert_includes results, card
|
|
|
|
# Check the content length was within the limit
|
|
search_record = search_record_class.find_by(searchable_type: "Card", searchable_id: card.id)
|
|
assert search_record.content.bytesize <= Searchable::SEARCH_CONTENT_LIMIT
|
|
end
|
|
|
|
test "deleting card removes search record and FTS entry" do
|
|
search_record_class = Search::Record.for(@user.account_id)
|
|
card = @board.cards.create!(title: "Card to delete", status: "published", creator: @user)
|
|
|
|
# Verify search record exists
|
|
search_record = search_record_class.find_by(searchable_type: "Card", searchable_id: card.id)
|
|
assert_not_nil search_record, "Search record should exist after card creation"
|
|
|
|
# For SQLite, verify FTS entry exists
|
|
if search_record_class.connection.adapter_name == "SQLite"
|
|
fts_entry = search_record.search_records_fts
|
|
assert_not_nil fts_entry, "FTS entry should exist"
|
|
assert_equal card.title, fts_entry.title
|
|
end
|
|
|
|
# Delete the card
|
|
card.destroy
|
|
|
|
# Verify search record is deleted
|
|
search_record = search_record_class.find_by(searchable_type: "Card", searchable_id: card.id)
|
|
assert_nil search_record, "Search record should be deleted after card deletion"
|
|
|
|
# For SQLite, verify FTS entry is deleted
|
|
if search_record_class.connection.adapter_name == "SQLite"
|
|
fts_count = Search::Record::SQLite::Fts.where(rowid: card.id).count
|
|
assert_equal 0, fts_count, "FTS entry should be deleted"
|
|
end
|
|
end
|
|
|
|
test "updating a draft card does not index it" do
|
|
search_record_class = Search::Record.for(@user.account_id)
|
|
|
|
card = @board.cards.create!(title: "Draft card", creator: @user, status: "drafted")
|
|
assert_nil search_record_class.find_by(searchable_type: "Card", searchable_id: card.id)
|
|
|
|
card.update!(title: "Updated draft card")
|
|
assert_nil search_record_class.find_by(searchable_type: "Card", searchable_id: card.id),
|
|
"Draft card should not be indexed after update"
|
|
|
|
results = Card.mentioning("Updated", user: @user)
|
|
assert_not_includes results, card
|
|
end
|
|
|
|
test "publishing a draft card indexes it" do
|
|
search_record_class = Search::Record.for(@user.account_id)
|
|
|
|
card = @board.cards.create!(title: "Draft to publish", creator: @user, status: "drafted")
|
|
assert_nil search_record_class.find_by(searchable_type: "Card", searchable_id: card.id)
|
|
|
|
card.publish
|
|
search_record = search_record_class.find_by(searchable_type: "Card", searchable_id: card.id)
|
|
assert_not_nil search_record, "Published card should be indexed"
|
|
assert_equal card.id, search_record.card_id
|
|
|
|
results = Card.mentioning("publish", user: @user)
|
|
assert_includes results, card
|
|
end
|
|
|
|
test "unpublishing a draft card removes it from the search index" do
|
|
search_record_class = Search::Record.for(@user.account_id)
|
|
|
|
card = @board.cards.create!(title: "Draft to publish", creator: @user, status: "published")
|
|
assert_not_nil search_record_class.find_by(searchable_type: "Card", searchable_id: card.id)
|
|
|
|
card.update!(status: "drafted")
|
|
|
|
assert_nil search_record_class.find_by(searchable_type: "Card", searchable_id: card.id)
|
|
results = Card.mentioning("publish", user: @user)
|
|
assert_not_includes results, card
|
|
end
|
|
end
|