discourse/spec/system/admin_upcoming_changes_spec.rb
Jarek Radosz 5e096f06a2
DEV: Restore upcoming-changes specs (#39602)
Let's see if those are still flaky
2026-04-28 18:49:54 +02:00

444 lines
16 KiB
Ruby

# frozen_string_literal: true
describe "Admin upcoming changes" do
fab!(:current_user, :admin)
let(:upcoming_changes_page) { PageObjects::Pages::AdminUpcomingChanges.new }
before do
mock_upcoming_change_metadata(
{
enable_upload_debug_mode: {
impact: "other,developers",
status: :experimental,
impact_type: "other",
impact_role: "developers",
},
about_page_extra_groups_show_description: {
impact: "feature,all_members",
status: :stable,
impact_type: "feature",
impact_role: "all_members",
},
},
)
SiteSetting.about_page_extra_groups_show_description = false
sign_in(current_user)
end
it "shows a list of upcoming changes and their metadata" do
upcoming_changes_page.visit
expect(upcoming_changes_page).to have_change(:about_page_extra_groups_show_description)
expect(upcoming_changes_page).to have_change(:enable_upload_debug_mode)
expect(
upcoming_changes_page.change_item(:about_page_extra_groups_show_description),
).to have_status(:stable)
expect(
upcoming_changes_page.change_item(:about_page_extra_groups_show_description),
).to have_impact_role(:all_members)
end
it "does not show conceptual upcoming changes" do
mock_upcoming_change_metadata(
{
enable_upload_debug_mode: {
impact: "other,developers",
status: :experimental,
impact_type: "other",
impact_role: "developers",
},
about_page_extra_groups_show_description: {
impact: "feature,all_members",
status: :conceptual,
impact_type: "feature",
impact_role: "all_members",
},
},
)
upcoming_changes_page.visit
expect(upcoming_changes_page).to have_change(:enable_upload_debug_mode)
expect(upcoming_changes_page).to have_no_change(:about_page_extra_groups_show_description)
end
it "shows the permanent soon notice for stable changes but not for site_setting_default types" do
mock_upcoming_change_metadata(
{
about_page_extra_groups_show_description: {
impact: "feature,all_members",
status: :stable,
impact_type: "feature",
impact_role: "all_members",
},
enable_upload_debug_mode: {
impact: "site_setting_default,all_members",
status: :stable,
impact_type: "site_setting_default",
impact_role: "all_members",
},
},
)
upcoming_changes_page.visit
expect(
upcoming_changes_page.change_item(:about_page_extra_groups_show_description),
).to have_permanent_soon_notice
expect(
upcoming_changes_page.change_item(:enable_upload_debug_mode),
).to have_no_permanent_soon_notice
end
it "does not show permanent upcoming changes" do
mock_upcoming_change_metadata(
{
allow_uppercase_posts: {
impact: "feature,all_members",
status: :permanent,
impact_type: "feature",
impact_role: "all_members",
},
},
)
upcoming_changes_page.visit
expect(upcoming_changes_page).to have_no_change(:allow_uppercase_posts)
end
it "shows upcoming changes from plugins" do
upcoming_changes_page.visit
expect(upcoming_changes_page).to have_change(:enable_experimental_sample_plugin_feature)
expect(
upcoming_changes_page.change_item(:enable_experimental_sample_plugin_feature),
).to have_plugin_name("Sample plugin")
end
it "can enable and disable an upcoming change using the dropdown" do
upcoming_changes_page.visit
expect(upcoming_changes_page.change_item(:enable_upload_debug_mode)).to be_disabled
upcoming_changes_page.change_item(:enable_upload_debug_mode).select_enabled_for("everyone")
expect(upcoming_changes_page).to have_enabled_for_success_toast("everyone")
expect(upcoming_changes_page.change_item(:enable_upload_debug_mode)).to be_enabled
expect(SiteSetting.enable_upload_debug_mode).to be_truthy
# Revisit the page to skip the rate limit
upcoming_changes_page.visit
expect(upcoming_changes_page.change_item(:enable_upload_debug_mode)).to be_enabled
upcoming_changes_page.change_item(:enable_upload_debug_mode).select_enabled_for("no_one")
expect(upcoming_changes_page).to have_disabled_success_toast
expect(upcoming_changes_page.change_item(:enable_upload_debug_mode)).to be_disabled
expect(SiteSetting.enable_upload_debug_mode).to be_falsey
end
it "tests different enabled_for options behavior" do
upcoming_changes_page.visit
# Add a group to test clearing behavior
SiteSetting.enable_upload_debug_mode = true
Fabricate(
:site_setting_group,
name: "enable_upload_debug_mode",
group_ids: Group::AUTO_GROUPS[:trust_level_4].to_s,
)
# Refresh after setting up the group
upcoming_changes_page.visit
expect(upcoming_changes_page.change_item(:enable_upload_debug_mode)).to have_groups(
"trust_level_4",
)
expect(UpcomingChanges.has_groups?(:enable_upload_debug_mode)).to be_truthy
# Test 'no_one' option - should disable the change and clear groups
upcoming_changes_page.change_item(:enable_upload_debug_mode).select_enabled_for("no_one")
expect(upcoming_changes_page).to have_disabled_success_toast
expect(upcoming_changes_page.change_item(:enable_upload_debug_mode)).to be_disabled
upcoming_changes_page.visit
expect(upcoming_changes_page.change_item(:enable_upload_debug_mode)).to have_no_group_selector
expect(SiteSetting.enable_upload_debug_mode).to be_falsey
expect(UpcomingChanges.has_groups?(:enable_upload_debug_mode)).to be_falsey
# Test 'everyone' option - should enable the change and clear groups
upcoming_changes_page.change_item(:enable_upload_debug_mode).select_enabled_for("everyone")
expect(upcoming_changes_page).to have_enabled_for_success_toast("everyone")
expect(upcoming_changes_page.change_item(:enable_upload_debug_mode)).to be_enabled
upcoming_changes_page.visit
expect(upcoming_changes_page.change_item(:enable_upload_debug_mode)).to have_no_group_selector
expect(SiteSetting.enable_upload_debug_mode).to be_truthy
# Test 'staff' option - should enable the change and set staff group
upcoming_changes_page.change_item(:enable_upload_debug_mode).select_enabled_for("staff")
expect(upcoming_changes_page).to have_enabled_for_success_toast(
"staff",
translation_args: {
staffGroupName: I18n.t("groups.default_names.staff").titleize,
},
)
expect(upcoming_changes_page.change_item(:enable_upload_debug_mode)).to be_enabled
upcoming_changes_page.visit
expect(UpcomingChanges.has_groups?(:enable_upload_debug_mode)).to be_truthy
expect(SiteSetting.enable_upload_debug_mode).to be_truthy
# Test 'groups' option - should not change enabled state until groups are selected and saved
upcoming_changes_page.change_item(:enable_upload_debug_mode).select_enabled_for("groups")
upcoming_changes_page.change_item(:enable_upload_debug_mode).add_group("trust_level_4")
upcoming_changes_page.change_item(:enable_upload_debug_mode).save_groups
expect(upcoming_changes_page).to have_enabled_for_success_toast(
"specific_groups_with_group_names",
translation_args: {
groupNames: "staff, trust_level_4",
count: 2,
},
)
upcoming_changes_page.visit
expect(upcoming_changes_page.change_item(:enable_upload_debug_mode)).to have_groups(
"staff",
"trust_level_4",
)
expect(upcoming_changes_page.change_item(:enable_upload_debug_mode)).to be_enabled
expect(UpcomingChanges.has_groups?(:enable_upload_debug_mode)).to be_truthy
expect(SiteSetting.enable_upload_debug_mode).to be_truthy
end
it "can filter by name, description, plugin, status, impact type, or enabled/disabled" do
upcoming_changes_page.visit
# Filter by name
upcoming_changes_page.filter_controls.type_in_search("upload debug")
expect(upcoming_changes_page).to have_change(:enable_upload_debug_mode)
expect(upcoming_changes_page).to have_no_change(:about_page_extra_groups_show_description)
upcoming_changes_page.filter_controls.clear_search
# Filter by plugin
upcoming_changes_page.filter_controls.type_in_search("sample plugin")
expect(upcoming_changes_page).to have_change(:enable_experimental_sample_plugin_feature)
expect(upcoming_changes_page).to have_no_change(:about_page_extra_groups_show_description)
upcoming_changes_page.filter_controls.clear_search
upcoming_changes_page.filter_controls.toggle_dropdown_filters
# Filter by status
upcoming_changes_page.filter_controls.select_dropdown_option("Stable", dropdown_id: "status")
expect(upcoming_changes_page).to have_no_change(:enable_upload_debug_mode)
expect(upcoming_changes_page).to have_change(:about_page_extra_groups_show_description)
upcoming_changes_page.filter_controls.select_all_dropdown_option(dropdown_id: "status")
# Filter by impact type
upcoming_changes_page.filter_controls.select_dropdown_option("Feature", dropdown_id: "type")
expect(upcoming_changes_page).to have_no_change(:enable_upload_debug_mode)
expect(upcoming_changes_page).to have_change(:about_page_extra_groups_show_description)
upcoming_changes_page.filter_controls.select_all_dropdown_option(dropdown_id: "type")
# Filter by impact role
upcoming_changes_page.filter_controls.select_dropdown_option(
"Developers",
dropdown_id: "impactRole",
)
expect(upcoming_changes_page).to have_change(:enable_upload_debug_mode)
expect(upcoming_changes_page).to have_no_change(:about_page_extra_groups_show_description)
upcoming_changes_page.filter_controls.select_all_dropdown_option(dropdown_id: "impactRole")
# Filter by enabled/disabled
upcoming_changes_page.filter_controls.select_dropdown_option("Enabled", dropdown_id: "enabled")
expect(upcoming_changes_page).to have_no_change(:enable_upload_debug_mode)
expect(upcoming_changes_page).to have_no_change(:about_page_extra_groups_show_description)
upcoming_changes_page.filter_controls.select_all_dropdown_option(dropdown_id: "enabled")
end
it "displays a notification dot on the sidebar and clears it when navigating to upcoming changes" do
sidebar = PageObjects::Components::NavigationMenu::Sidebar.new
UpcomingChangeEvent.create!(
event_type: :added,
upcoming_change_name: "enable_upload_debug_mode",
)
visit "/admin"
sidebar.toggle_all_sections
expect(sidebar.find_section_link("admin_upcoming_changes")).to have_css(
".sidebar-section-link-suffix.admin-sidebar-nav-link__dot",
)
sidebar.find_section_link("admin_upcoming_changes").click
expect(sidebar.find_section_link("admin_upcoming_changes")).to have_no_css(
".sidebar-section-link-suffix.admin-sidebar-nav-link__dot",
)
end
it "does not display a notification dot when there are no new added events" do
sidebar = PageObjects::Components::NavigationMenu::Sidebar.new
current_user.custom_fields["last_visited_upcoming_changes_at"] = Time.current.iso8601
current_user.save_custom_fields
visit "/admin"
sidebar.toggle_all_sections
expect(sidebar.find_section_link("admin_upcoming_changes")).to have_no_css(
".sidebar-section-link-suffix.admin-sidebar-nav-link__dot",
)
end
context "when the staff group name has been localized" do
before do
SiteSetting.default_locale = "de"
Group.refresh_automatic_group!(:staff)
end
it "displays the localized name in the enabled for options and enabling staff works correctly" do
upcoming_changes_page.visit
upcoming_changes_page.change_item(:enable_upload_debug_mode).select_enabled_for(
Group.find(Group::AUTO_GROUPS[:staff]).name,
)
expect(upcoming_changes_page).to have_enabled_for_success_toast(
"staff",
translation_args: {
staffGroupName: I18n.t("groups.default_names.staff", locale: SiteSetting.default_locale),
},
)
expect(upcoming_changes_page.change_item(:enable_upload_debug_mode)).to be_enabled
expect(SiteSetting.enable_upload_debug_mode).to be_truthy
expect(SiteSettingGroup.find_by(name: "enable_upload_debug_mode").group_ids).to include(
Group::AUTO_GROUPS[:staff].to_s,
)
upcoming_changes_page.visit
expect(upcoming_changes_page.change_item(:enable_upload_debug_mode).enabled_for).to eq(
Group.find(Group::AUTO_GROUPS[:staff]).name,
)
end
end
context "when the upcoming change has a default override" do
let(:settings_page) { PageObjects::Pages::AdminSiteSettings.new }
before do
mock_upcoming_change_metadata(
{
enable_upload_debug_mode: {
impact: "other,developers",
status: :experimental,
impact_type: "other",
impact_role: "developers",
},
},
)
mock_upcoming_change_default_overrides(
{
suggested_topics_max_days_old: {
upcoming_change: :enable_upload_debug_mode,
new_default: 1000,
},
},
)
SiteSetting.enable_upload_debug_mode = true
SiteSetting.refresh!
end
it "shows information about the default override in the site settings UI" do
settings_page.visit("suggested_topics_max_days_old")
expect(settings_page).to have_upcoming_change_default_warning(
:suggested_topics_max_days_old,
old_default: 365,
new_default: 1000,
)
end
end
context "when the upcoming change has a boolean default override and the admin opts out" do
let(:settings_page) { PageObjects::Pages::AdminSiteSettings.new }
before do
mock_upcoming_change_metadata(
{
enable_upload_debug_mode: {
impact: "site_setting_default,all_members",
status: :experimental,
impact_type: "site_setting_default",
impact_role: "all_members",
},
},
)
mock_upcoming_change_default_overrides(
{
limit_suggested_to_category: {
upcoming_change: :enable_upload_debug_mode,
new_default: true,
},
},
)
SiteSetting.enable_upload_debug_mode = true
SiteSetting.refresh!
end
after do
clear_mocked_upcoming_change_metadata
clear_mocked_upcoming_change_default_overrides
end
it "preserves the admin's opt-out across page reload while still showing the override warning" do
settings_page.visit("limit_suggested_to_category")
expect(settings_page).to have_upcoming_change_default_warning(
:limit_suggested_to_category,
old_default: false,
new_default: true,
)
expect(
settings_page.find_setting(:limit_suggested_to_category).find(
".setting-value input[type=checkbox]",
),
).to be_checked
settings_page.toggle_setting(:limit_suggested_to_category)
# Wait for the save to land in the DB before forcing the in-process
# SiteSetting refresh below — the .overridden class only appears once
# the value has been persisted.
expect(
settings_page.find_setting(:limit_suggested_to_category, overridden: true),
).to be_present
# Production reproduces the bug because each unicorn worker re-runs
# SiteSetting.refresh! via the MessageBus subscriber after another
# worker persists a setting change. In a single-process system spec
# that subscriber doesn't fire, so we trigger the refresh explicitly
# to mirror what happens on the next request in a real deployment.
SiteSetting.refresh!
page.refresh
expect(settings_page).to have_upcoming_change_default_warning(
:limit_suggested_to_category,
old_default: false,
new_default: true,
)
expect(
settings_page.find_setting(:limit_suggested_to_category).find(
".setting-value input[type=checkbox]",
),
).not_to be_checked
end
end
end