2020-05-24 23:13:21 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require 'spec_helper'
|
|
|
|
|
2020-07-28 23:09:34 +05:30
|
|
|
RSpec.describe StubFeatureFlags do
|
2021-01-03 14:25:43 +05:30
|
|
|
let_it_be(:dummy_feature_flag) { :dummy_feature_flag }
|
|
|
|
|
2021-02-22 17:27:13 +05:30
|
|
|
let_it_be(:dummy_definition) do
|
|
|
|
Feature::Definition.new(
|
2021-01-03 14:25:43 +05:30
|
|
|
nil,
|
|
|
|
name: dummy_feature_flag,
|
|
|
|
type: 'development',
|
2021-02-22 17:27:13 +05:30
|
|
|
default_enabled: false
|
2021-01-03 14:25:43 +05:30
|
|
|
)
|
2021-02-22 17:27:13 +05:30
|
|
|
end
|
2021-01-03 14:25:43 +05:30
|
|
|
|
2021-02-22 17:27:13 +05:30
|
|
|
# We inject dummy feature flag defintion
|
|
|
|
# to ensure that we strong validate it's usage
|
|
|
|
# as well
|
|
|
|
before(:all) do
|
|
|
|
Feature::Definition.definitions[dummy_feature_flag] = dummy_definition
|
2021-01-03 14:25:43 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
after(:all) do
|
|
|
|
Feature::Definition.definitions.delete(dummy_feature_flag)
|
|
|
|
end
|
2020-05-24 23:13:21 +05:30
|
|
|
|
|
|
|
describe '#stub_feature_flags' do
|
|
|
|
using RSpec::Parameterized::TableSyntax
|
|
|
|
|
2021-01-03 14:25:43 +05:30
|
|
|
let(:feature_name) { dummy_feature_flag }
|
2020-05-24 23:13:21 +05:30
|
|
|
|
|
|
|
context 'when checking global state' do
|
|
|
|
where(:feature_actors, :expected_result) do
|
|
|
|
false | false
|
|
|
|
true | true
|
|
|
|
:A | false
|
|
|
|
%i[A] | false
|
|
|
|
%i[A B] | false
|
|
|
|
end
|
|
|
|
|
|
|
|
with_them do
|
|
|
|
before do
|
2020-06-23 00:09:42 +05:30
|
|
|
stub_feature_flags(feature_name => actor(feature_actors))
|
2020-05-24 23:13:21 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it { expect(Feature.enabled?(feature_name)).to eq(expected_result) }
|
|
|
|
it { expect(Feature.disabled?(feature_name)).not_to eq(expected_result) }
|
|
|
|
|
2022-07-16 23:28:13 +05:30
|
|
|
context 'default_enabled_if_undefined does not impact feature state' do
|
2021-02-22 17:27:13 +05:30
|
|
|
before do
|
|
|
|
allow(dummy_definition).to receive(:default_enabled).and_return(true)
|
|
|
|
end
|
|
|
|
|
2022-07-16 23:28:13 +05:30
|
|
|
it { expect(Feature.enabled?(feature_name, default_enabled_if_undefined: true)).to eq(expected_result) }
|
|
|
|
it { expect(Feature.disabled?(feature_name, default_enabled_if_undefined: true)).not_to eq(expected_result) }
|
2020-05-24 23:13:21 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when checking scoped state' do
|
|
|
|
where(:feature_actors, :tested_actor, :expected_result) do
|
|
|
|
false | nil | false
|
|
|
|
true | nil | true
|
|
|
|
false | :A | false
|
|
|
|
true | :A | true
|
|
|
|
:A | nil | false
|
|
|
|
:A | :A | true
|
|
|
|
:A | :B | false
|
|
|
|
%i[A] | nil | false
|
|
|
|
%i[A] | :A | true
|
|
|
|
%i[A] | :B | false
|
|
|
|
%i[A B] | nil | false
|
|
|
|
%i[A B] | :A | true
|
|
|
|
%i[A B] | :B | true
|
|
|
|
end
|
|
|
|
|
|
|
|
with_them do
|
|
|
|
before do
|
2020-06-23 00:09:42 +05:30
|
|
|
stub_feature_flags(feature_name => actor(feature_actors))
|
2020-05-24 23:13:21 +05:30
|
|
|
end
|
|
|
|
|
2020-06-23 00:09:42 +05:30
|
|
|
it { expect(Feature.enabled?(feature_name, actor(tested_actor))).to eq(expected_result) }
|
|
|
|
it { expect(Feature.disabled?(feature_name, actor(tested_actor))).not_to eq(expected_result) }
|
2020-05-24 23:13:21 +05:30
|
|
|
|
2022-07-16 23:28:13 +05:30
|
|
|
context 'default_enabled_if_undefined does not impact feature state' do
|
2021-02-22 17:27:13 +05:30
|
|
|
before do
|
|
|
|
allow(dummy_definition).to receive(:default_enabled).and_return(true)
|
|
|
|
end
|
|
|
|
|
2022-07-16 23:28:13 +05:30
|
|
|
it { expect(Feature.enabled?(feature_name, actor(tested_actor), default_enabled_if_undefined: true)).to eq(expected_result) }
|
|
|
|
it { expect(Feature.disabled?(feature_name, actor(tested_actor), default_enabled_if_undefined: true)).not_to eq(expected_result) }
|
2020-05-24 23:13:21 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'type handling' do
|
|
|
|
context 'raises error' do
|
|
|
|
where(:feature_actors) do
|
2021-12-11 22:18:48 +05:30
|
|
|
['string', 1, 1.0, Object.new]
|
2020-05-24 23:13:21 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
with_them do
|
2020-06-23 00:09:42 +05:30
|
|
|
subject { stub_feature_flags(feature_name => actor(feature_actors)) }
|
2020-05-24 23:13:21 +05:30
|
|
|
|
|
|
|
it { expect { subject }.to raise_error(ArgumentError, /accepts only/) }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'does not raise error' do
|
|
|
|
where(:feature_actors) do
|
2020-06-23 00:09:42 +05:30
|
|
|
[true, false, nil, stub_feature_flag_gate(100), User.new]
|
2020-05-24 23:13:21 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
with_them do
|
2020-06-23 00:09:42 +05:30
|
|
|
subject { stub_feature_flags(feature_name => actor(feature_actors)) }
|
2020-05-24 23:13:21 +05:30
|
|
|
|
|
|
|
it { expect { subject }.not_to raise_error }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'subsquent run changes state' do
|
|
|
|
# enable FF only on A
|
2020-06-23 00:09:42 +05:30
|
|
|
stub_feature_flags({ feature_name => actor(%i[A]) })
|
|
|
|
expect(Feature.enabled?(feature_name)).to eq(false)
|
|
|
|
expect(Feature.enabled?(feature_name, actor(:A))).to eq(true)
|
|
|
|
expect(Feature.enabled?(feature_name, actor(:B))).to eq(false)
|
2020-05-24 23:13:21 +05:30
|
|
|
|
|
|
|
# enable FF only on B
|
2020-06-23 00:09:42 +05:30
|
|
|
stub_feature_flags({ feature_name => actor(%i[B]) })
|
|
|
|
expect(Feature.enabled?(feature_name)).to eq(false)
|
|
|
|
expect(Feature.enabled?(feature_name, actor(:A))).to eq(false)
|
|
|
|
expect(Feature.enabled?(feature_name, actor(:B))).to eq(true)
|
2020-05-24 23:13:21 +05:30
|
|
|
|
|
|
|
# enable FF on all
|
2020-06-23 00:09:42 +05:30
|
|
|
stub_feature_flags({ feature_name => true })
|
|
|
|
expect(Feature.enabled?(feature_name)).to eq(true)
|
|
|
|
expect(Feature.enabled?(feature_name, actor(:A))).to eq(true)
|
|
|
|
expect(Feature.enabled?(feature_name, actor(:B))).to eq(true)
|
2020-05-24 23:13:21 +05:30
|
|
|
|
|
|
|
# disable FF on all
|
2020-06-23 00:09:42 +05:30
|
|
|
stub_feature_flags({ feature_name => false })
|
|
|
|
expect(Feature.enabled?(feature_name)).to eq(false)
|
|
|
|
expect(Feature.enabled?(feature_name, actor(:A))).to eq(false)
|
|
|
|
expect(Feature.enabled?(feature_name, actor(:B))).to eq(false)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-10-24 23:57:45 +05:30
|
|
|
describe 'stub timing' do
|
|
|
|
context 'let_it_be variable' do
|
2021-01-03 14:25:43 +05:30
|
|
|
let_it_be(:let_it_be_var) { Feature.enabled?(dummy_feature_flag) }
|
2020-10-24 23:57:45 +05:30
|
|
|
|
|
|
|
it { expect(let_it_be_var).to eq true }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'before_all variable' do
|
|
|
|
before_all do
|
2021-01-03 14:25:43 +05:30
|
|
|
@suite_var = Feature.enabled?(dummy_feature_flag)
|
2020-10-24 23:57:45 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it { expect(@suite_var).to eq true }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'before(:all) variable' do
|
|
|
|
before(:all) do
|
2021-01-03 14:25:43 +05:30
|
|
|
@suite_var = Feature.enabled?(dummy_feature_flag)
|
2020-10-24 23:57:45 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it { expect(@suite_var).to eq true }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with stub_feature_flags meta' do
|
2021-01-03 14:25:43 +05:30
|
|
|
let(:var) { Feature.enabled?(dummy_feature_flag) }
|
2020-10-24 23:57:45 +05:30
|
|
|
|
|
|
|
context 'as true', :stub_feature_flags do
|
|
|
|
it { expect(var).to eq true }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'as false', stub_feature_flags: false do
|
|
|
|
it { expect(var).to eq false }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-06-23 00:09:42 +05:30
|
|
|
def actor(actor)
|
|
|
|
case actor
|
|
|
|
when Array
|
|
|
|
actor.map(&method(:actor))
|
|
|
|
when Symbol # convert to flipper compatible object
|
|
|
|
stub_feature_flag_gate(actor)
|
|
|
|
else
|
|
|
|
actor
|
2020-05-24 23:13:21 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|