discourse/spec/system/page_objects/components/topic_list.rb
Mark VanLandingham 1e5e20ffc5
FEATURE: Notification/tracking changes for nested replies (#39750)
Reply consolidation by bucket for nested view. Replies under the same
parent now collapse into one notification ("3 new replies in your topic"
/ "to your post"). Clicking lands you at that bucket's level with
sort=new&collapse_replies=true so you only see the new content. Flat
topics keep the existing single-row consolidated shape (specs guard
against regression). Root posts that don't explicitly reply to
anyone resolve to the OP, so the OP still gets notified for fresh roots
in their own topic.
                                                                  
Auto-Track instead of auto-Watch for the OP. PMs and flat topics are
unchanged.
  
Topic-list "new replies" dot. Replaces the unread/new count badges for
nested topics when there's new content since the user's last visit. The
count-based UI doesn't fit nested's read pattern.
                                                                  
collapse_replies=true URL param. On the nested view, starts replies
hidden behind an Expand button. Set automatically by consolidated
notifications.

---------

Co-authored-by: Rafael Silva <xfalcox@gmail.com>
2026-05-07 12:33:56 -05:00

174 lines
5 KiB
Ruby

# frozen_string_literal: true
module PageObjects
module Components
class TopicList < PageObjects::Components::Base
TOPIC_LIST_BODY_SELECTOR = ".topic-list-body"
TOPIC_LIST_ITEM_SELECTOR = "#{TOPIC_LIST_BODY_SELECTOR} .topic-list-item"
def topic_list
TOPIC_LIST_BODY_SELECTOR
end
def has_topics?(count: nil)
if count.nil?
page.has_css?(TOPIC_LIST_ITEM_SELECTOR)
else
page.has_css?(TOPIC_LIST_ITEM_SELECTOR, count: count)
end
end
def has_no_topics?
page.has_no_css?(TOPIC_LIST_ITEM_SELECTOR)
end
def has_topic?(topic)
page.has_css?(topic_list_item_class(topic))
end
def has_no_topic?(topic)
page.has_no_css?(topic_list_item_class(topic))
end
def has_highlighted_topic?(topic)
page.has_css?("#{topic_list_item_class(topic)}[data-test-was-highlighted]")
end
def has_topic_checkbox?(topic)
page.has_css?("#{topic_list_item_class(topic)} input#bulk-select-#{topic.id}")
end
def has_no_topic_checkbox?(topic)
page.has_no_css?("#{topic_list_item_class(topic)} input#bulk-select-#{topic.id}")
end
def has_bulk_select_enabled?
page.has_css?("#{TOPIC_LIST_ITEM_SELECTOR} input.bulk-select")
end
def has_closed_status?(topic)
page.has_css?("#{topic_list_item_closed(topic)}")
end
def has_unread_badge?(topic)
page.has_css?("#{topic_list_item_unread_badge(topic)}")
end
def has_no_unread_badge?(topic)
page.has_no_css?("#{topic_list_item_unread_badge(topic)}")
end
def has_new_replies_dot?(topic)
page.has_css?("#{topic_list_item_new_replies_dot(topic)}")
end
def has_no_new_replies_dot?(topic)
page.has_no_css?("#{topic_list_item_new_replies_dot(topic)}")
end
def has_checkbox_selected_on_row?(n)
page.has_css?("#{TOPIC_LIST_ITEM_SELECTOR}:nth-child(#{n}) input.bulk-select:checked")
end
def has_no_checkbox_selected_on_row?(n)
page.has_no_css?("#{TOPIC_LIST_ITEM_SELECTOR}:nth-child(#{n}) input.bulk-select:checked")
end
def click_topic_checkbox(topic)
find("#{topic_list_item_class(topic)} input#bulk-select-#{topic.id}").click
end
def click_topic_title(topic)
find("#{topic_list_item_class(topic)} .raw-topic-link").click
end
def visit_topic_with_title(title)
find("#{TOPIC_LIST_BODY_SELECTOR} a", text: title).click
end
def visit_topic(topic)
find("#{topic_list_item_class(topic)} a.raw-topic-link").click
end
def visit_topic_last_reply_via_keyboard(topic)
find("#{topic_list_item_class(topic)} a.post-activity").send_keys(:return)
end
def visit_topic_first_reply_via_keyboard(topic)
find("#{topic_list_item_class(topic)} a.badge-posts").send_keys(:return)
end
def send_keys_to_topic(topic, *keys)
find("#{topic_list_item_class(topic)} a.raw-topic-link").send_keys(*keys)
end
def topic_list_item_class(topic)
"#{TOPIC_LIST_ITEM_SELECTOR}[data-topic-id='#{topic.id}']"
end
def topic(topic)
find(topic_list_item_class(topic))
end
def has_topic_tag?(topic, tag_name)
page.has_css?(
"#{topic_list_item_class(topic)} .discourse-tags .discourse-tag",
text: tag_name,
)
end
def has_no_topic_tag?(topic, tag_name)
page.has_no_css?(
"#{topic_list_item_class(topic)} .discourse-tags .discourse-tag",
text: tag_name,
)
end
def has_topic_tags?(topic, tags:)
tags.all? { |tag| has_topic_tag?(topic, tag.name) } &&
page.has_css?(
"#{topic_list_item_class(topic)} .discourse-tags .discourse-tag",
count: tags.size,
)
end
def has_no_topic_tags?(topic)
page.has_no_css?("#{topic_list_item_class(topic)} .discourse-tags .discourse-tag")
end
def click_topic_tag(topic, tag_name)
find("#{topic_list_item_class(topic)} .discourse-tags .discourse-tag", text: tag_name).click
end
def had_new_topics_alert?
page.has_css?(".show-more.has-topics")
end
def click_new_topics_alert
find(".show-more.has-topics").click
end
def has_pinned_status?(topic)
page.has_css?("#{topic_list_item_class(topic)} .topic-statuses .topic-status.--pinned")
end
def has_no_pinned_status?(topic)
page.has_no_css?("#{topic_list_item_class(topic)} .topic-statuses .topic-status.--pinned")
end
private
def topic_list_item_closed(topic)
"#{topic_list_item_class(topic)} .topic-statuses .topic-status svg[class*='d-icon-lock']"
end
def topic_list_item_unread_badge(topic)
"#{topic_list_item_class(topic)} .topic-post-badges .unread-posts"
end
def topic_list_item_new_replies_dot(topic)
"#{topic_list_item_class(topic)} .topic-post-badges .new-replies"
end
end
end
end