discourse/spec/services/upcoming_changes/toggle_spec.rb
Martin Brennan dcf6da9cef
UX: Allow more specific enabled for options for upcoming changes (#39916)
Certain upcoming changes do not make sense to enable for "Everyone",
like changes that will only affect the admin UI. We currently have
a disallow_enabled_for_groups option that changes the "Enabled for"
dropdown to only show Everyone and No one, but this is a bit of a blunt
instrument.

This change adds an `allow_enabled_for` option for upcoming changes
which is a YAML array:

* When omitted, the "Enabled for" dropdown will show Everyone, Staff,
Specific group(s) and No one.
* When set to everyone, the dropdown will only show Everyone and No one.
* When set to staff, the dropdown will only show Staff and No one.
* It can also be set to staff and specific_groups

This commit also changes the reporting_improvements upcoming change
to be staff, specific_groups and adds a DB migration to account for
this.
2026-05-13 10:22:06 +10:00

300 lines
9.4 KiB
Ruby

# frozen_string_literal: true
RSpec.describe UpcomingChanges::Toggle do
describe UpcomingChanges::Toggle::Contract, type: :model do
it { is_expected.to validate_presence_of :setting_name }
end
describe ".call" do
subject(:result) { described_class.call(params:, **dependencies, options:) }
fab!(:admin)
let(:params) { { setting_name:, enabled: } }
let(:enabled) { true }
let(:setting_name) { :enable_form_templates }
let(:dependencies) { { guardian: } }
let(:options) { {} }
let(:guardian) { admin.guardian }
context "when data is invalid" do
let(:setting_name) { nil }
it { is_expected.to fail_a_contract }
end
context "when setting_name is invalid" do
let(:setting_name) { "wrong_value" }
it { is_expected.to fail_a_policy(:setting_is_available) }
end
context "when a non-admin user tries to change a setting" do
let(:guardian) { Guardian.new }
it { is_expected.to fail_a_policy(:current_user_is_admin) }
end
context "when everything's ok" do
it { is_expected.to run_successfully }
context "when allow_enabled_for restricts to [everyone]" do
before do
mock_upcoming_change_metadata(
enable_form_templates: {
impact: "feature,all_members",
status: :experimental,
impact_type: "feature",
impact_role: "all_members",
allow_enabled_for: [:everyone],
},
)
end
context "when toggling on with existing groups" do
let(:enabled) { true }
fab!(:site_setting_group) do
Fabricate(:site_setting_group, name: "enable_form_templates", group_ids: "1|2")
end
before { SiteSetting.enable_form_templates = false }
it "clears the SiteSettingGroup record" do
expect { result }.to change {
SiteSettingGroup.where(name: "enable_form_templates").count
}.from(1).to(0)
end
end
context "when toggling off with existing groups" do
let(:enabled) { false }
fab!(:site_setting_group) do
Fabricate(:site_setting_group, name: "enable_form_templates", group_ids: "1|2")
end
before { SiteSetting.enable_form_templates = true }
it "clears the SiteSettingGroup record" do
expect { result }.to change {
SiteSettingGroup.where(name: "enable_form_templates").count
}.from(1).to(0)
end
end
context "when toggling on with no existing groups" do
let(:enabled) { true }
before { SiteSetting.enable_form_templates = false }
it { is_expected.to run_successfully }
end
end
context "when allow_enabled_for is [staff, specific_groups]" do
before do
mock_upcoming_change_metadata(
enable_form_templates: {
impact: "feature,all_members",
status: :experimental,
impact_type: "feature",
impact_role: "all_members",
allow_enabled_for: %i[staff specific_groups],
},
)
SiteSetting.enable_form_templates = false
end
context "when toggling on with no existing groups (target would be everyone)" do
let(:enabled) { true }
it { is_expected.to fail_a_policy(:allowed_enabled_for_target) }
end
context "when toggling on with existing groups configured" do
let(:enabled) { true }
fab!(:site_setting_group) do
Fabricate(:site_setting_group, name: "enable_form_templates", group_ids: "1|2")
end
it { is_expected.to run_successfully }
it "preserves the SiteSettingGroup record" do
expect { result }.not_to change {
SiteSettingGroup.where(name: "enable_form_templates").count
}
end
end
context "when toggling off" do
let(:enabled) { false }
it { is_expected.to run_successfully }
end
end
context "when allow_enabled_for is omitted" do
let(:enabled) { true }
before { SiteSetting.enable_form_templates = false }
it { is_expected.to run_successfully }
end
context "when log_change is true" do
let(:options) { { log_change: true } }
context "when enabling the setting" do
let(:enabled) { true }
before { SiteSetting.enable_form_templates = false }
it "enables the specified setting" do
expect { result }.to change { SiteSetting.enable_form_templates }.to(true)
end
it "creates an entry in the staff action logs with correct context" do
expect { result }.to change {
UserHistory.where(
action: UserHistory.actions[:upcoming_change_toggled],
subject: "enable_form_templates",
).count
}.by(1)
expect(UserHistory.last.context).to eq(
I18n.t("staff_action_logs.upcoming_changes.log_manually_toggled"),
)
end
it "creates an UpcomingChangeEvent with manual_opt_in event_type" do
expect { result }.to change {
UpcomingChangeEvent.where(
event_type: :manual_opt_in,
upcoming_change_name: "enable_form_templates",
).count
}.by(1)
end
it "triggers the upcoming_change_enabled event" do
events =
DiscourseEvent
.track_events { result }
.select { |e| e[:event_name] == :upcoming_change_enabled }
expect(events.first[:params]).to eq([setting_name])
end
end
context "when disabling the setting" do
let(:enabled) { false }
before { SiteSetting.enable_form_templates = true }
it "disables the specified setting" do
expect { result }.to change { SiteSetting.enable_form_templates }.to(false)
end
it "creates an entry in the staff action logs with correct context" do
expect { result }.to change {
UserHistory.where(
action: UserHistory.actions[:upcoming_change_toggled],
subject: "enable_form_templates",
).count
}.by(1)
expect(UserHistory.last.context).to eq(
I18n.t("staff_action_logs.upcoming_changes.log_manually_toggled"),
)
end
it "creates an UpcomingChangeEvent with manual_opt_out event_type" do
expect { result }.to change {
UpcomingChangeEvent.where(
event_type: :manual_opt_out,
upcoming_change_name: "enable_form_templates",
).count
}.by(1)
end
it "triggers the upcoming_change_disabled event" do
events =
DiscourseEvent
.track_events { result }
.select { |e| e[:event_name] == :upcoming_change_disabled }
expect(events.first[:params]).to eq([setting_name])
end
end
end
context "when log_change is false" do
let(:options) { { log_change: false } }
context "when enabling the setting" do
let(:enabled) { true }
before { SiteSetting.enable_form_templates = false }
it "enables the specified setting" do
expect { result }.to change { SiteSetting.enable_form_templates }.to(true)
end
it "does not create an entry in the staff action logs" do
expect { result }.not_to change {
UserHistory.where(
action: UserHistory.actions[:upcoming_change_toggled],
subject: "enable_form_templates",
).count
}
end
it "does not create an UpcomingChangeEvent" do
expect { result }.not_to change { UpcomingChangeEvent.count }
end
it "triggers the upcoming_change_enabled event" do
events =
DiscourseEvent
.track_events { result }
.select { |e| e[:event_name] == :upcoming_change_enabled }
expect(events.first[:params]).to eq([setting_name])
end
end
context "when disabling the setting" do
let(:enabled) { false }
before { SiteSetting.enable_form_templates = true }
it "disables the specified setting" do
expect { result }.to change { SiteSetting.enable_form_templates }.to(false)
end
it "does not create an entry in the staff action logs" do
expect { result }.not_to change {
UserHistory.where(
action: UserHistory.actions[:upcoming_change_toggled],
subject: "enable_form_templates",
).count
}
end
it "does not create an UpcomingChangeEvent" do
expect { result }.not_to change { UpcomingChangeEvent.count }
end
it "triggers the upcoming_change_disabled event" do
events =
DiscourseEvent
.track_events { result }
.select { |e| e[:event_name] == :upcoming_change_disabled }
expect(events.first[:params]).to eq([setting_name])
end
end
end
end
end
end