discourse/spec/system/viewing_reviewable_spec.rb
Kris 92521f46c3
UX: reset review queue tab, don't look up insights every toggle (#39271)
Fixes a couple issues reported here:
https://meta.discourse.org/t/ip-info-is-not-updated-when-you-switch-to-a-different-reviewable/391230

1. When you navigated from one review item directly to another, from
notifications for example, we weren't resetting the state so if you had
opened the insights tab it would remain open with stale IP data. Now
didUpdateAttrs will reset the state so the data will be fetched for the
new reviewable.

2. Every switch to the insights tab fetches data all over again — this
will check if it's been opened and shows/hides it with `hidden` to avoid
fetching the data every time
2026-04-15 11:48:59 -04:00

429 lines
14 KiB
Ruby

# frozen_string_literal: true
require "discourse_ip_info"
describe "Viewing reviewable item" do
fab!(:admin)
fab!(:moderator)
fab!(:group)
fab!(:reviewable_flagged_post) do
Fabricate(
:reviewable_flagged_post,
target_created_by: Fabricate(:user, email: "flagged@example.com"),
)
end
let(:review_page) { PageObjects::Pages::Review.new }
let(:review_note_form) { PageObjects::Components::ReviewNoteForm.new }
before do
group.add(admin)
sign_in(admin)
end
describe "when the reviewable item is a flagged post" do
it "shows the new reviewable UI" do
review_page.visit_reviewable(reviewable_flagged_post)
expect(page).to have_selector(".review-container")
end
it "shows the reviewable item with badges stating the flag reason and count" do
_spam_reviewable_score =
Fabricate(
:reviewable_score,
reviewable: reviewable_flagged_post,
reviewable_score_type: ReviewableScore.types[:spam],
)
_off_topic_reviewable_score =
Fabricate(
:reviewable_score,
reviewable: reviewable_flagged_post,
reviewable_score_type: ReviewableScore.types[:off_topic],
)
_illegal_reviewable_score =
Fabricate(
:reviewable_score,
reviewable: reviewable_flagged_post,
reviewable_score_type: ReviewableScore.types[:illegal],
)
_inappropriate_reviewable_score =
Fabricate(
:reviewable_score,
reviewable: reviewable_flagged_post,
reviewable_score_type: ReviewableScore.types[:inappropriate],
)
_needs_approval_reviewable_score =
Fabricate(
:reviewable_score,
reviewable: reviewable_flagged_post,
reviewable_score_type: ReviewableScore.types[:needs_approval],
)
flag_reason_component =
review_page.visit_reviewable(reviewable_flagged_post).flag_reason_component
expect(flag_reason_component).to have_spam_flag_reason(reviewable_flagged_post, count: 1)
expect(flag_reason_component).to have_off_topic_flag_reason(reviewable_flagged_post, count: 1)
expect(flag_reason_component).to have_illegal_flag_reason(reviewable_flagged_post, count: 1)
expect(flag_reason_component).to have_inappropriate_flag_reason(
reviewable_flagged_post,
count: 2,
)
expect(flag_reason_component).to have_needs_approval_flag_reason(
reviewable_flagged_post,
count: 1,
)
end
it "shows the topic status, title link, category badge and tags of the topic associated with the reviewable item correctly" do
post = reviewable_flagged_post.post
topic = reviewable_flagged_post.topic
category = Fabricate(:category)
topic.change_category_to_id(category.id)
tag_1 = Fabricate(:tag)
tag_2 = Fabricate(:tag)
topic.tags = [tag_1, tag_2]
topic.closed = true
topic.save!
topic_link_component =
review_page.visit_reviewable(reviewable_flagged_post).topic_link_component
expect(topic_link_component).to have_closed_topic_status
expect(topic_link_component).to have_topic_link(
topic_title: topic.title,
post_url: post.full_url,
)
expect(topic_link_component).to have_category_badge(category.name)
expect(topic_link_component).to have_tag_link(tag_name: tag_1.name, tag_url: tag_1.url)
expect(topic_link_component).to have_tag_link(tag_name: tag_2.name, tag_url: tag_2.url)
# TODO: Add test for watched words highlighting
end
it "allows to add notes and persists them when toggle tabs" do
review_page.visit_reviewable(reviewable_flagged_post)
review_page.click_timeline_tab
review_note_form.add_note("This is a review note.")
review_page.click_insights_tab
review_page.click_timeline_tab
expect(page).to have_text("This is a review note.")
end
it "shows confirmation dialog when navigating away with unsaved note, but not after clearing the note" do
dialog = PageObjects::Components::Dialog.new
review_page.visit_reviewable(reviewable_flagged_post)
review_page.click_timeline_tab
review_note_form.form.fill_in("content", with: "This is a draft note")
click_logo
expect(dialog).to be_open
expect(dialog).to have_content(I18n.t("js.form_kit.dirty_form"))
dialog.click_no
expect(page).to have_current_path("/review/#{reviewable_flagged_post.id}")
review_note_form.form.fill_in("content", with: "")
click_logo
expect(dialog).to be_closed
expect(page).to have_current_path("/")
end
it "displays the flagged user's email address in user activity" do
review_page.visit_reviewable(reviewable_flagged_post)
review_page.click_insights_tab
expect(page).to have_text("flagged@example.com")
end
describe "Moderation history" do
fab!(:flagged_user) { reviewable_flagged_post.target_created_by }
it "displays the number of times the user has been silenced, suspended and number of rejected posts" do
UserHistory.create!(
action: UserHistory.actions[:silence_user],
target_user_id: flagged_user.id,
acting_user_id: admin.id,
)
UserHistory.create!(
action: UserHistory.actions[:silence_user],
target_user_id: flagged_user.id,
acting_user_id: admin.id,
)
UserHistory.create!(
action: UserHistory.actions[:suspend_user],
target_user_id: flagged_user.id,
acting_user_id: admin.id,
)
ReviewableQueuedPost.create!(
created_by: admin,
target_created_by: flagged_user,
status: Reviewable.statuses[:rejected],
payload: {
raw: "test post 1",
},
)
ReviewableQueuedPost.create!(
created_by: admin,
target_created_by: flagged_user,
status: Reviewable.statuses[:rejected],
payload: {
raw: "test post 2",
},
)
review_page.visit_reviewable(reviewable_flagged_post)
review_page.click_insights_tab
expect(page).to have_text(
I18n.t("js.review.insights.moderation_history.silenced", count: 2),
)
expect(page).to have_text(
I18n.t("js.review.insights.moderation_history.suspended", count: 1),
)
expect(page).to have_text(
I18n.t("js.review.insights.moderation_history.rejected_posts", count: 2),
)
end
end
describe "IP lookup" do
fab!(:reviewable_flagged_post)
before do
reviewable_flagged_post.target_created_by.update!(ip_address: "81.2.69.142")
DiscourseIpInfo.open_db(File.join(Rails.root, "spec", "fixtures", "mmdb"))
Resolv::DNS
.any_instance
.stubs(:getname)
.with("81.2.69.142")
.returns("ip-81-2-69-142.example.com")
end
it "shows IP lookup information when insights tab is viewed" do
review_page.visit_reviewable(reviewable_flagged_post)
review_page.click_insights_tab
expect(review_page).to have_ip_lookup_info
end
it "displays IP location, hostname, and organization when available" do
review_page.visit_reviewable(reviewable_flagged_post)
review_page.click_insights_tab
expect(review_page).to have_ip_location("London, England, United Kingdom")
expect(review_page).to have_ip_hostname("ip-81-2-69-142.example.com")
end
it "shows other accounts link when there are multiple accounts with same IP" do
other_user_1 = Fabricate(:user, ip_address: "81.2.69.142")
other_user_2 = Fabricate(:user, ip_address: "81.2.69.142")
review_page.visit_reviewable(reviewable_flagged_post)
review_page.click_insights_tab
expect(review_page).to have_other_accounts_link(count: 2)
end
it "opens modal with account list when clicking other accounts link" do
other_user = Fabricate(:user, username: "suspicious_user", ip_address: "81.2.69.142")
review_page.visit_reviewable(reviewable_flagged_post)
review_page.click_insights_tab
review_page.click_other_accounts_link
expect(review_page).to have_ip_lookup_modal
expect(review_page).to have_account_in_modal(other_user.username)
end
it "shows correct IP when navigating between reviewables" do
other_reviewable =
Fabricate(
:reviewable_flagged_post,
target_created_by: Fabricate(:user, ip_address: "2.125.160.216"),
)
Resolv::DNS
.any_instance
.stubs(:getname)
.with("2.125.160.216")
.returns("ip-2-125-160-216.example.com")
review_page.visit_reviewable(reviewable_flagged_post)
review_page.click_insights_tab
expect(review_page).to have_ip_hostname("ip-81-2-69-142.example.com")
review_page.visit_reviewable(other_reviewable)
review_page.click_insights_tab
expect(review_page).to have_ip_hostname("ip-2-125-160-216.example.com")
end
context "when category moderator" do
fab!(:category)
fab!(:trust_level_1_user, :trust_level_1)
fab!(:category_moderation_group) do
Fabricate(
:category_moderation_group,
category: category,
group: trust_level_1_user.groups.last,
)
end
before do
SiteSetting.enable_category_group_moderation = true
reviewable_flagged_post.topic.change_category_to_id(category.id)
sign_in trust_level_1_user
end
it "does not show IP information" do
review_page.visit_reviewable(reviewable_flagged_post)
review_page.click_insights_tab
expect(review_page).to have_no_ip_lookup_info
end
end
end
end
describe "when the reviewable item is a queued post" do
fab!(:reviewable_queued_post)
it "allows to edit post when old moderator actions are enabled" do
review_page.visit_reviewable(reviewable_queued_post)
expect(page).to have_text("hello world post contents.")
review_page.click_edit_post_button
review_page.fill_post_content("Hello world from system spec!")
review_page.save_post_edit
expect(page).to have_text("Hello world from system spec!")
expect(page).not_to have_text("hello world post contents.")
end
it "shows context question for rejected queued post" do
review_page.visit_reviewable(reviewable_queued_post)
expect(review_page).to have_context_question(
reviewable_queued_post,
I18n.t("js.review.context_question.approve_post"),
)
end
end
describe "when the reviewable item is a user" do
fab!(:user)
let(:rejection_reason_modal) { PageObjects::Modals::RejectReasonReviewable.new }
let(:scrub_user_modal) { PageObjects::Modals::ScrubRejectedUser.new }
before do
SiteSetting.must_approve_users = true
Jobs.run_immediately!
user.update!(approved: false)
user.activate
end
it "Allow to delete and scrub user" do
reviewable = ReviewableUser.find_by_target_id(user.id)
review_page.visit_reviewable(reviewable)
expect(page).to have_text(user.name)
expect(page).to have_link(user.username, href: "/admin/users/#{user.id}/#{user.username}")
review_page.select_bundled_action(reviewable, "user-delete_user")
rejection_reason_modal.fill_in_rejection_reason("Spamming the site")
rejection_reason_modal.delete_user
expect(review_page).to have_reviewable_with_rejected_status(reviewable)
expect(page).to have_text(user.name)
review_page.click_scrub_user_button
scrubbing_reason = "a spammer who knows how to make GDPR requests"
scrub_user_modal.fill_in_scrub_reason(scrubbing_reason)
expect(scrub_user_modal.scrub_button).not_to be_disabled
scrub_user_modal.scrub_button.click
expect(review_page).to have_reviewable_with_scrubbed_by(reviewable, admin.username)
expect(review_page).to have_reviewable_with_scrubbed_reason(reviewable, scrubbing_reason)
expect(review_page).to have_reviewable_with_scrubbed_at(
reviewable,
reviewable.payload["scrubbed_at"],
)
expect(page).not_to have_text(user.name)
end
it "Allows to delete and block user" do
reviewable = ReviewableUser.find_by_target_id(user.id)
review_page.visit_reviewable(reviewable)
review_page.select_bundled_action(reviewable, "user-delete_user_block")
rejection_reason_modal.fill_in_rejection_reason("Spamming the site")
rejection_reason_modal.delete_user
expect(review_page).to have_reviewable_with_rejected_status(reviewable)
expect(review_page).to have_rejected_item_in_timeline(reviewable)
end
it "Allows to approve user" do
reviewable = ReviewableUser.find_by_target_id(user.id)
review_page.visit_reviewable(reviewable)
review_page.click_approve_user_button
expect(review_page).to have_reviewable_with_approved_status(reviewable)
expect(review_page).to have_approved_item_in_timeline(reviewable)
end
end
describe "moderator" do
before do
group.add(admin)
group.add(moderator)
sign_in(moderator)
end
it "shows claimed and unclaimed events in the timeline" do
SiteSetting.reviewable_claiming = "required"
review_page.visit_reviewable(reviewable_flagged_post)
expect(review_page).to have_history_items(count: 2)
expect(review_page).to have_created_at_history_item
review_page.click_claim_reviewable
page.refresh
expect(review_page).to have_history_items(count: 3)
expect(review_page).to have_claimed_history_item(moderator)
review_page.click_unclaim_reviewable
page.refresh
expect(review_page).to have_history_items(count: 4)
expect(review_page).to have_unclaimed_history_item(moderator)
# remove history items created by deleted users
UserDestroyer.new(admin).destroy(moderator)
sign_in(admin)
review_page.visit_reviewable(reviewable_flagged_post)
expect(review_page).to have_history_items(count: 2)
end
end
end