discourse/spec/system/post_stream_spec.rb
2026-03-20 00:39:52 +01:00

179 lines
6.2 KiB
Ruby

# frozen_string_literal: true
describe "Post stream" do
fab!(:user)
fab!(:admin)
context "when posting" do
let(:topic) { Fabricate(:topic, user: user) }
let(:post) { Fabricate(:post, topic: topic, user: user) }
let(:topic_page) { PageObjects::Pages::Topic.new }
let(:composer) { PageObjects::Components::Composer.new }
before do
SiteSetting.post_menu_hidden_items = ""
sign_in(admin)
end
it "can reply to a post and edit the reply" do
# Visit topic and initiate reply
topic_page.visit_topic(post.topic)
topic_page.click_post_action_button(post, :reply)
expect(composer).to be_opened
# Create initial reply
composer.type_content("This is a reply")
composer.submit
expect(composer).to be_closed
# Verify initial reply
reply = Post.last
expect(topic_page).to have_post_number(reply.post_number)
expect(topic_page).to have_post_content(
post_number: reply.post_number,
content: "This is a reply",
)
# Edit the reply
expect(topic_page).to have_post_action_button(reply, :edit)
topic_page.click_post_action_button(reply, :edit)
expect(composer).to be_opened
composer.type_content("This is an edited reply")
composer.submit
# Verify edited reply
expect(topic_page).to have_post_action_button(reply, :edit)
expect(topic_page).to have_post_content(
post_number: reply.post_number,
content: "This is an edited reply",
)
end
end
context "when hiding scrollable content" do
let!(:topic) { Fabricate(:topic) }
let!(:posts) { Fabricate.times(60, :post, topic: topic) }
let(:topic_page) { PageObjects::Pages::Topic.new }
before { sign_in(user) }
it "hides and shows content above the post stream based on loaded posts" do
topic_page.visit_topic(topic, post_number: 30)
expect(page).to have_css("[data-post-number='30']")
expect(page).to have_no_css("#main-container")
topic_page.visit_topic(topic, post_number: 1)
expect(page).to have_css("[data-post-number='1']")
expect(page).to have_css("#main-container")
topic_page.visit_topic(topic, post_number: 30)
expect(page).to have_css("[data-post-number='30']")
expect(page).to have_no_css("#main-container")
visit "/"
expect(page).to have_css("#main-container")
end
end
context "when scrolling" do
let!(:topic) { Fabricate(:topic) }
let!(:posts) { Fabricate.times(20, :post, topic: topic) }
before { sign_in(user) }
it "cloaks posts that are far from the viewport" do
# Visit the topic page
visit "/t/#{topic.slug}/#{topic.id}/1"
# Ensure there are visible posts
expect(page).to have_css(".topic-post")
post_stream = find(".post-stream")
# Ensure the first post is uncloaked
expect(post_stream).to have_css("> [data-post-number='1']")
expect(post_stream).to have_no_css("> [data-post-number='1'].post-stream--cloaked")
# Check that some posts are cloaked (not all posts should be fully rendered at once)
# The posts that are far from the viewport should have the "post-stream--cloaked" class
expect(post_stream).to have_css(".post-stream--cloaked")
# Get the number of the last post
last_post_number = topic.highest_post_number
# Scroll to the bottom of the page to load more posts
# We use the :end key to scroll to the bottom
send_keys(:end)
# Verify that the last post is not cloaked
expect(post_stream).to have_no_css(
"> [data-post-number='#{last_post_number}'].post-stream--cloaked",
)
# Verify that some posts at the top are now cloaked
# we can check the first post to see if it's cloaked
expect(post_stream).to have_css("> [data-post-number='1'].post-stream--cloaked")
end
it "keeps the state of quoted posts after uncloaking them" do
first_post = posts[0]
second_post = posts[1]
second_post.raw =
"[quote=\"#{first_post.user.username}, post:1, topic:#{topic.id}\"]\nHello\n[/quote]\n#{first_post.raw}"
# Rebake the post to process the quote markup
second_post.rebake!
# Visit the topic page
visit "/t/#{topic.slug}/#{topic.id}/1"
post2_selector = "[data-post-number='2']"
# Find the post-stream container
post_stream = find(".post-stream")
# Verify the second post is initially visible (uncloaked)
expect(post_stream).to have_css(post2_selector)
expect(post_stream).to have_no_css("#{post2_selector}.post-stream--cloaked")
# Verify the quote starts collapsed
expect(post_stream).to have_css("#{post2_selector} aside.quote[data-expanded='false']")
# Find the blockquote and verify the initial state
blockquote = post_stream.find("#{post2_selector} aside.quote blockquote")
expect(blockquote).to have_content("Hello")
expect(blockquote).to have_no_content(first_post.raw)
# Expand the quote by clicking the toggle button
post_stream.find(
"#{post2_selector} aside.quote[data-expanded='false'] button.quote-toggle",
).click
expect(post_stream).to have_css("#{post2_selector} aside.quote[data-expanded='true']")
# Verify the expanded quote shows full content
blockquote = post_stream.find("#{post2_selector} aside.quote blockquote")
expect(blockquote).to have_content(first_post.raw)
# Scroll to bottom to trigger post cloaking
send_keys(:end)
# Verify that the second post gets cloaked and the quote is removed
expect(post_stream).to have_css("#{post2_selector}.post-stream--cloaked")
expect(post_stream).to have_no_css("#{post2_selector} aside.quote")
# Scroll back to top
send_keys(:home)
# Verify that the second post becomes visible again
expect(post_stream).to have_css(post2_selector)
expect(post_stream).to have_no_css("#{post2_selector}.post-stream--cloaked")
# Verify that the quote maintains an expanded state after uncloaking
expect(post_stream).to have_css("#{post2_selector} aside.quote[data-expanded='true']")
blockquote = post_stream.find("#{post2_selector} aside.quote blockquote")
expect(blockquote).to have_content(first_post.raw)
end
end
end