2
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-03-03 23:54:20 +08:00
discourse/spec/system/reviewables_spec.rb
Krzysztof Kotlarek 53d799eb8b
DEV: Remove reviewable_ui_refresh feature flag and legacy code (#36752)
Following PR #36711 which enabled the refreshed review UI for all users, this commit removes the old feature flag infrastructure and cleans up legacy code that is no longer needed.

Backend Changes:
  - Removed ReviewableActionLog model and its spec entirely
  - Removed CalculateFinalStatusFromLogs service and spec
  - Removed site settings: force_old_reviewable_ui, reviewable_old_moderator_actions
  - Simplified ReviewableActionBuilder — stripped out legacy action-building methods (build_user_actions_bundle, build_post_actions_bundle, build_new_separated_actions)
  - Cleaned up reviewable models (ReviewableFlaggedPost, ReviewablePost, ReviewableQueuedPost, ReviewableUser, Chat::ReviewableMessage, ReviewablePostVotingComment) — removed unused/legacy action definitions
  - Removed legacy specs for action builder, action logs, flagged post actions, post actions, user actions, and status-from-logs
  - Updated system tests and page objects to reflect the new UI structure

  Frontend Changes:

  - Deleted legacy components: reviewable-item.gjs, reviewable-user.gjs, review-index-legacy.gjs
  - Renamed reviewable-refresh/ → reviewable/ — moved all sub-components (created-by, flagged-post, item, post, queued-post, topic-link, user, etc.) out of the refresh directory into the canonical reviewable/ namespace
  - Simplified reviewable/item.gjs — removed feature flag conditionals and legacy code paths
  - Cleaned up review/index.gjs and review/show.gjs templates — removed branching between old/new UI
  - Updated plugin components (chat, AI, post-voting) to import from reviewable/ instead of reviewable-refresh/
  - Removed acceptance tests (review-test.js) replaced by system tests
  - Renamed and updated integration tests from reviewable-refresh/* to reviewable/*

Plan for next PRs:
- Move plugins from Pages::RefreshedReview to Pages::Review 
- Move plugins to import from `reviewable/` and not `refreshed-reviewable/`
- Move reviewable-user.js import in plugin to use `reviewable/user.js`
- Remove unused settings like `reviewable_old_moderator_actions` from plugins
- Delete `Pages::RefreshedReview`
- Delete `reviewable-refresh/` directory
- Delete `reviewable-user.js` component
- Delete `reviewable_old_moderator_actions` site setting

Plugins PRs:
- https://github.com/discourse/discourse-akismet/pull/203
- https://github.com/discourse/discourse-antivirus/pull/98
- https://github.com/discourse/discourse-category-experts/pull/223
2026-02-23 10:45:36 +08:00

312 lines
11 KiB
Ruby

# frozen_string_literal: true
describe "Reviewables", type: :system do
let(:review_page) { PageObjects::Pages::Review.new }
fab!(:admin)
fab!(:theme)
fab!(:long_post, :post_with_very_long_raw_content)
fab!(:post)
let(:composer) { PageObjects::Components::Composer.new }
let(:moderator) { Fabricate(:moderator) }
let(:toasts) { PageObjects::Components::Toasts.new }
before { sign_in(admin) }
describe "when there is a flagged post reviewable with a short post" do
fab!(:short_reviewable) { Fabricate(:reviewable_flagged_post, target: post) }
it "should not show a button to expand/collapse the post content" do
visit("/review")
expect(review_page).to have_no_post_body_collapsed
expect(review_page).to have_no_post_body_toggle
end
describe "reviewable actions" do
it "should have agree_and_edit action" do
visit("/review")
select_kit =
PageObjects::Components::SelectKit.new(".dropdown-select-box.post-agree-and-hide")
select_kit.expand
expect(select_kit).to have_option_value("post-agree_and_edit")
end
it "agree_and_edit should open the composer" do
visit("/review")
select_kit =
PageObjects::Components::SelectKit.new(".dropdown-select-box.post-agree-and-hide")
select_kit.expand
find("[data-value='post-agree_and_edit']").click
expect(composer).to be_opened
expect(composer.composer_input.value).to eq(post.raw)
expect(toasts).to have_success(I18n.t("reviewables.actions.agree_and_edit.complete"))
end
it "should open a modal when suspending a user" do
visit("/review")
select_kit =
PageObjects::Components::SelectKit.new(".dropdown-select-box.post-agree-and-hide")
select_kit.expand
select_kit.select_row_by_value("post-agree_and_suspend")
expect(review_page).to have_css(
"#discourse-modal-title",
text: I18n.t("js.flagging.take_action_options.suspend.title"),
)
end
it "should show a toast when disagreeing with a flag flag" do
visit("/review")
select_kit = PageObjects::Components::SelectKit.new(".dropdown-select-box.post-disagree")
select_kit.expand
select_kit.select_row_by_value("post-disagree")
expect(toasts).to have_success(I18n.t("reviewables.actions.disagree.complete"))
end
end
end
describe "when there is a queued post reviewable with a short post" do
fab!(:short_queued_reviewable, :reviewable_queued_post)
it "should not show a button to expand/collapse the post content" do
visit("/review")
expect(review_page).to have_no_post_body_collapsed
expect(review_page).to have_no_post_body_toggle
end
it "should apply correct button classes to actions" do
visit("/review")
expect(page).to have_css(".approve-post.btn-success")
expect(page).to have_css(".reject-post .btn-danger")
expect(page).to have_no_css(".approve-post.btn-default")
expect(page).to have_no_css(".reject-post .btn-default")
end
end
describe "when there is a reviewable 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 "Rejecting user sends rejection email and updates reviewable with rejection reason" do
rejection_reason = "user is spamming"
reviewable = ReviewableUser.find_by_target_id(user.id)
# cache it for later assertion instead of querying UserHistory
user_email = user.email
review_page.visit_reviewable(reviewable)
review_page.select_bundled_action(reviewable, "user-delete_user")
rejection_reason_modal.fill_in_rejection_reason(rejection_reason)
rejection_reason_modal.select_send_rejection_email_checkbox
rejection_reason_modal.delete_user
expect(review_page).to have_reviewable_with_rejected_status(reviewable)
mail = ActionMailer::Base.deliveries.first
expect(mail.to).to eq([user_email])
expect(mail.subject).to match(/You've been rejected on Discourse/)
expect(mail.body.raw_source).to include rejection_reason
end
it "Allows scrubbing user data after rejection" do
rejection_reason = "user is spamming"
scrubbing_reason = "a spammer who knows how to make GDPR requests"
reviewable = ReviewableUser.find_by_target_id(user.id)
review_page.visit_reviewable(reviewable)
review_page.select_bundled_action(reviewable, "user-delete_user")
rejection_reason_modal.fill_in_rejection_reason(rejection_reason)
rejection_reason_modal.delete_user
expect(review_page).to have_reviewable_with_rejected_status(reviewable)
review_page.click_scrub_user_button
expect(scrub_user_modal.scrub_button).to be_disabled
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"],
)
end
end
context "when performing a review action from the show route" do
fab!(:contact_group, :group)
fab!(:contact_user, :user)
before do
SiteSetting.site_contact_group_name = contact_group.name
SiteSetting.site_contact_username = contact_user.username
end
context "with a ReviewableQueuedPost" do
fab!(:queued_post_reviewable, :reviewable_queued_post)
it "delete_user does not delete reviewable" do
review_page.visit_reviewable(queued_post_reviewable)
expect(queued_post_reviewable).to be_pending
expect(queued_post_reviewable.target_created_by).to be_present
expect(review_page).to have_reviewable_with_pending_status(queued_post_reviewable)
review_page.select_bundled_action(queued_post_reviewable, "delete_user")
expect(review_page).to have_no_error_dialog_visible
expect(review_page).to have_reviewable_with_rejected_status(queued_post_reviewable)
expect(review_page).to have_no_reviewable_action_dropdown
expect(queued_post_reviewable.reload).to be_rejected
expect(queued_post_reviewable.target_created_by).to be_nil
end
it "allows revising and rejecting to send a PM to the user" do
revise_modal = PageObjects::Modals::Base.new
review_page.visit_reviewable(queued_post_reviewable)
expect(queued_post_reviewable).to be_pending
expect(queued_post_reviewable.target_created_by).to be_present
review_page.select_bundled_action(queued_post_reviewable, "revise_and_reject_post")
expect(revise_modal).to be_open
reason_dropdown =
PageObjects::Components::SelectKit.new(".revise-and-reject-reviewable__reason")
reason_dropdown.select_row_by_value(SiteSetting.reviewable_revision_reasons_map.first)
find(".revise-and-reject-reviewable__feedback").fill_in(with: "This is a test")
revise_modal.click_primary_button
expect(review_page).to have_reviewable_with_rejected_status(queued_post_reviewable)
expect(queued_post_reviewable.reload).to be_rejected
topic = Topic.where(archetype: Archetype.private_message).last
expect(topic.topic_allowed_users.pluck(:user_id)).to include(contact_user.id)
expect(topic.topic_allowed_groups.pluck(:group_id)).to include(contact_group.id)
expect(topic.title).to eq(
I18n.t(
"system_messages.reviewable_queued_post_revise_and_reject.subject_template",
topic_title: queued_post_reviewable.topic.title,
),
)
end
it "allows selecting a custom reason for revise and reject" do
revise_modal = PageObjects::Modals::Base.new
review_page.visit_reviewable(queued_post_reviewable)
expect(queued_post_reviewable).to be_pending
expect(queued_post_reviewable.target_created_by).to be_present
review_page.select_bundled_action(queued_post_reviewable, "revise_and_reject_post")
expect(revise_modal).to be_open
reason_dropdown =
PageObjects::Components::SelectKit.new(".revise-and-reject-reviewable__reason")
reason_dropdown.select_row_by_value("other_reason")
find(".revise-and-reject-reviewable__custom-reason").fill_in(with: "I felt like it")
find(".revise-and-reject-reviewable__feedback").fill_in(with: "This is a test")
revise_modal.click_primary_button
expect(review_page).to have_reviewable_with_rejected_status(queued_post_reviewable)
end
context "with reviewable claiming enabled" do
before { SiteSetting.reviewable_claiming = "required" }
it "properly claims and unclaims the reviewable" do
review_page.visit_reviewable(queued_post_reviewable)
expect(review_page).to have_no_reviewable_action_dropdown
review_page.click_claim_reviewable
expect(review_page).to have_reviewable_action_dropdown
review_page.click_unclaim_reviewable
expect(review_page).to have_no_reviewable_action_dropdown
end
end
end
end
describe "when there is an unknown plugin reviewable" do
fab!(:reviewable) { Fabricate(:reviewable_flagged_post, target: long_post) }
fab!(:reviewable2, :reviewable)
before do
reviewable.update_columns(type: "UnknownPlugin", type_source: "some-plugin")
reviewable2.update_columns(type: "UnknownSource", type_source: "unknown")
end
it "informs admin and allows to delete them" do
visit("/review")
expect(review_page).to have_information_about_unknown_reviewables_visible
expect(review_page).to have_listing_for_unknown_reviewables_plugin(
reviewable.type,
reviewable.type_source,
)
expect(review_page).to have_listing_for_unknown_reviewables_unknown_source(reviewable2.type)
review_page.click_ignore_all_unknown_reviewables
expect(review_page).to have_no_information_about_unknown_reviewables_visible
end
it "does not inform moderator about them" do
sign_in(moderator)
visit("/review")
expect(review_page).to have_no_information_about_unknown_reviewables_visible
end
end
describe "custom community moderator guide topic" do
fab!(:group)
fab!(:topic) { Fabricate(:topic, title: "Moderator guide") }
fab!(:post) { Fabricate(:post, topic: topic) }
fab!(:reviewable, :reviewable_queued_post)
before { group.add(admin) }
it "displays the custom guide topic link when configured" do
SiteSetting.moderator_guide_topic = topic.id
review_page.visit_reviewable(reviewable)
expect(review_page).to have_css(
"a.review-resources__link",
text: I18n.t("js.review.help.community_moderation_guide"),
)
end
it "does not display anything when no custom guide topic configured" do
SiteSetting.moderator_guide_topic = ""
review_page.visit_reviewable(reviewable)
expect(review_page).to have_no_css(
"a.review-resources__link",
text: I18n.t("js.review.help.community_moderation_guide"),
)
end
end
end