flipflop 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +5 -0
  3. data/.travis.yml +51 -0
  4. data/Gemfile +20 -0
  5. data/LICENSE +22 -0
  6. data/README.md +261 -0
  7. data/Rakefile +16 -0
  8. data/app/assets/stylesheets/flipflop.scss +109 -0
  9. data/app/controllers/concerns/flipflop/environment_filters.rb +5 -0
  10. data/app/controllers/flipflop/features_controller.rb +59 -0
  11. data/app/controllers/flipflop/strategies_controller.rb +30 -0
  12. data/app/models/flipflop/feature.rb +3 -0
  13. data/app/views/flipflop/features/index.html.erb +60 -0
  14. data/app/views/layouts/flipflop.html.erb +1 -0
  15. data/config/routes.rb +5 -0
  16. data/flipflop.gemspec +23 -0
  17. data/lib/flipflop/configurable.rb +27 -0
  18. data/lib/flipflop/engine.rb +58 -0
  19. data/lib/flipflop/facade.rb +23 -0
  20. data/lib/flipflop/feature_cache.rb +64 -0
  21. data/lib/flipflop/feature_definition.rb +15 -0
  22. data/lib/flipflop/feature_set.rb +99 -0
  23. data/lib/flipflop/strategies/abstract_strategy.rb +103 -0
  24. data/lib/flipflop/strategies/active_record_strategy.rb +43 -0
  25. data/lib/flipflop/strategies/cookie_strategy.rb +44 -0
  26. data/lib/flipflop/strategies/default_strategy.rb +15 -0
  27. data/lib/flipflop/strategies/lambda_strategy.rb +25 -0
  28. data/lib/flipflop/strategies/query_string_strategy.rb +17 -0
  29. data/lib/flipflop/strategies/session_strategy.rb +29 -0
  30. data/lib/flipflop/strategies/test_strategy.rb +40 -0
  31. data/lib/flipflop/version.rb +3 -0
  32. data/lib/flipflop.rb +26 -0
  33. data/lib/generators/flipflop/features/USAGE +8 -0
  34. data/lib/generators/flipflop/features/features_generator.rb +7 -0
  35. data/lib/generators/flipflop/features/templates/features.rb +21 -0
  36. data/lib/generators/flipflop/install/install_generator.rb +21 -0
  37. data/lib/generators/flipflop/migration/USAGE +5 -0
  38. data/lib/generators/flipflop/migration/migration_generator.rb +23 -0
  39. data/lib/generators/flipflop/migration/templates/create_features.rb +10 -0
  40. data/lib/generators/flipflop/routes/USAGE +7 -0
  41. data/lib/generators/flipflop/routes/routes_generator.rb +5 -0
  42. data/test/integration/app_test.rb +32 -0
  43. data/test/integration/dashboard_test.rb +162 -0
  44. data/test/test_helper.rb +96 -0
  45. data/test/unit/configurable_test.rb +104 -0
  46. data/test/unit/feature_cache_test.rb +142 -0
  47. data/test/unit/feature_definition_test.rb +42 -0
  48. data/test/unit/feature_set_test.rb +136 -0
  49. data/test/unit/flipflop_test.rb +99 -0
  50. data/test/unit/strategies/abstract_strategy_request_test.rb +42 -0
  51. data/test/unit/strategies/abstract_strategy_test.rb +124 -0
  52. data/test/unit/strategies/active_record_strategy_test.rb +157 -0
  53. data/test/unit/strategies/cookie_strategy_test.rb +126 -0
  54. data/test/unit/strategies/default_strategy_test.rb +44 -0
  55. data/test/unit/strategies/lambda_strategy_test.rb +137 -0
  56. data/test/unit/strategies/query_string_strategy_test.rb +70 -0
  57. data/test/unit/strategies/session_strategy_test.rb +101 -0
  58. data/test/unit/strategies/test_strategy_test.rb +76 -0
  59. metadata +134 -0
@@ -0,0 +1,21 @@
1
+ Flipflop.configure do
2
+ # Strategies will be used in the order listed here.
3
+ strategy :cookie
4
+ strategy :active_record
5
+ strategy :default
6
+
7
+ # Other strategies:
8
+ #
9
+ # strategy :session
10
+ # strategy :query_string
11
+ #
12
+ # strategy :my_strategy do |feature|
13
+ # # ... your custom code here; return true/false/nil.
14
+ # end
15
+
16
+ # Declare your features, e.g:
17
+ #
18
+ # feature :world_domination,
19
+ # default: true,
20
+ # description: "Take over the world."
21
+ end
@@ -0,0 +1,21 @@
1
+ require "generators/flipflop/features/features_generator"
2
+ require "generators/flipflop/migration/migration_generator"
3
+ require "generators/flipflop/routes/routes_generator"
4
+
5
+ class Flipflop::InstallGenerator < Rails::Generators::Base
6
+ def invoke_generators
7
+ Flipflop::FeaturesGenerator.new([], options).invoke_all
8
+ Flipflop::MigrationGenerator.new([], options).invoke_all
9
+ Flipflop::RoutesGenerator.new([], options).invoke_all
10
+ end
11
+
12
+ def configure_dashboard
13
+ environment <<-CONFIG
14
+ # Replace this with your own 'before_action' filter in ApplicationController
15
+ # to implement access control for the Flipflop dashboard, or provide a
16
+ # filter as lambda directly.
17
+ config.flipflop.dashboard_access_filter = :require_development
18
+
19
+ CONFIG
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ Description:
2
+ Generates migration to create the features table for the Feature model.
3
+
4
+ Example:
5
+ rails generate flipflop:migration
@@ -0,0 +1,23 @@
1
+ require "rails"
2
+ require "rails/generators/migration"
3
+ require "rails/generators/active_record"
4
+
5
+ class Flipflop::MigrationGenerator < Rails::Generators::Base
6
+ include Rails::Generators::Migration
7
+
8
+ source_root File.expand_path("../templates", __FILE__)
9
+
10
+ def create_migration_file
11
+ migration_template("create_features.rb", "db/migrate/create_features.rb")
12
+ end
13
+
14
+ # Stubbed in railties/lib/rails/generators/migration.rb
15
+ #
16
+ # This implementation is a simplified version of:
17
+ # activerecord/lib/rails/generators/active_record/migration.rb
18
+ #
19
+ # See: http://www.ruby-forum.com/topic/203205
20
+ def self.next_migration_number(dirname)
21
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
22
+ end
23
+ end
@@ -0,0 +1,10 @@
1
+ class CreateFeatures < ActiveRecord::Migration<%= Rails.version >= "5" ? "[#{ActiveRecord::Migration.current_version}]" : "" %>
2
+ def change
3
+ create_table :features do |t|
4
+ t.string :key, null: false
5
+ t.boolean :enabled, null: false, default: false
6
+
7
+ t.timestamps null: false
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ Description:
2
+ Add routes for the Flipflop dashboard.
3
+
4
+ Example:
5
+ rails generate flipflop:routes
6
+
7
+ This will add routes to app/routes.rb
@@ -0,0 +1,5 @@
1
+ class Flipflop::RoutesGenerator < Rails::Generators::Base
2
+ def add_route
3
+ route %{mount Flipflop::Engine => "/flipflop"}
4
+ end
5
+ end
@@ -0,0 +1,32 @@
1
+ require File.expand_path("../../test_helper", __FILE__)
2
+
3
+ describe Flipflop do
4
+ before do
5
+ @app = TestApp.new
6
+ end
7
+
8
+ subject do
9
+ @app
10
+ end
11
+
12
+ describe "middleware" do
13
+ it "should include cache middleware" do
14
+ middlewares = Rails.application.middleware.map(&:klass)
15
+ assert_includes middlewares, Flipflop::FeatureCache::Middleware
16
+ end
17
+ end
18
+
19
+ describe "module" do
20
+ before do
21
+ Flipflop::FeatureSet.current.instance_variable_set(:@features, {})
22
+ Module.new do
23
+ extend Flipflop::Configurable
24
+ feature :world_domination
25
+ end
26
+ end
27
+
28
+ it "should allow querying for features" do
29
+ assert_equal false, Flipflop.world_domination?
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,162 @@
1
+ require File.expand_path("../../test_helper", __FILE__)
2
+
3
+ require "capybara/dsl"
4
+
5
+ describe Flipflop do
6
+ include Capybara::DSL
7
+
8
+ before do
9
+ @app = TestApp.new
10
+ end
11
+
12
+ subject do
13
+ @app
14
+ end
15
+
16
+ describe "outside development and test" do
17
+ before do
18
+ Rails.env.stub(:test?, false) do
19
+ visit "/flipflop"
20
+ end
21
+ end
22
+
23
+ it "should be forbidden" do
24
+ assert_equal 403, page.status_code
25
+ end
26
+ end
27
+
28
+ describe "without features" do
29
+ before do
30
+ visit "/flipflop"
31
+ end
32
+
33
+ it "should show feature table with header" do
34
+ assert_equal ["Cookie", "Active record", "Default"],
35
+ all("thead th").map(&:text)[3..-1]
36
+ end
37
+
38
+ it "should show no features" do
39
+ assert all("tbody tr").empty?
40
+ end
41
+ end
42
+
43
+ describe "with features" do
44
+ before do
45
+ Flipflop::FeatureSet.current.instance_variable_set(:@features, {})
46
+ Module.new do
47
+ extend Flipflop::Configurable
48
+ feature :world_domination, description: "Try and take over the world!"
49
+ feature :shiny_things, default: true
50
+ end
51
+
52
+ Capybara.current_session.driver.browser.clear_cookies
53
+ Flipflop::Feature.delete_all
54
+
55
+ visit "/flipflop"
56
+ end
57
+
58
+ it "should show feature rows" do
59
+ assert_equal ["World domination", "Shiny things"],
60
+ all("tr[data-feature] td.name").map(&:text)
61
+ end
62
+
63
+ it "should show feature descriptions" do
64
+ assert_equal ["Try and take over the world!", "Shiny things."],
65
+ all("tr[data-feature] td.description").map(&:text)
66
+ end
67
+
68
+ describe "with cookie strategy" do
69
+ it "should enable feature" do
70
+ within("tr[data-feature=world-domination] td[data-strategy=cookie]") do
71
+ click_on "on"
72
+ end
73
+
74
+ within("tr[data-feature=world-domination]") do
75
+ assert_equal "on", first("td.status").text
76
+ assert_equal "on", first("td[data-strategy=cookie] input.active[type=submit]").value
77
+ end
78
+ end
79
+
80
+ it "should disable feature" do
81
+ within("tr[data-feature=world-domination] td[data-strategy=cookie]") do
82
+ click_on "off"
83
+ end
84
+
85
+ within("tr[data-feature=world-domination]") do
86
+ assert_equal "off", first("td.status").text
87
+ assert_equal "off", first("td[data-strategy=cookie] input.active[type=submit]").value
88
+ end
89
+ end
90
+
91
+ it "should enable and clear feature" do
92
+ within("tr[data-feature=world-domination] td[data-strategy=cookie]") do
93
+ click_on "on"
94
+ end
95
+
96
+ within("tr[data-feature=world-domination] td[data-strategy=cookie]") do
97
+ click_on "clear"
98
+ end
99
+
100
+ within("tr[data-feature=world-domination]") do
101
+ assert_equal "off", first("td.status").text
102
+ refute has_selector?("td[data-strategy=cookie] input.active[type=submit]")
103
+ end
104
+ end
105
+ end
106
+
107
+ describe "with active record strategy" do
108
+ it "should enable feature" do
109
+ within("tr[data-feature=world-domination] td[data-strategy=active-record]") do
110
+ click_on "on"
111
+ end
112
+
113
+ within("tr[data-feature=world-domination]") do
114
+ assert_equal "on", first("td.status").text
115
+ assert_equal "on", first("td[data-strategy=active-record] input.active[type=submit]").value
116
+ end
117
+ end
118
+
119
+ it "should disable feature" do
120
+ within("tr[data-feature=world-domination] td[data-strategy=active-record]") do
121
+ click_on "off"
122
+ end
123
+
124
+ within("tr[data-feature=world-domination]") do
125
+ assert_equal "off", first("td.status").text
126
+ assert_equal "off", first("td[data-strategy=active-record] input.active[type=submit]").value
127
+ end
128
+ end
129
+
130
+ it "should enable and clear feature" do
131
+ within("tr[data-feature=world-domination] td[data-strategy=active-record]") do
132
+ click_on "on"
133
+ end
134
+
135
+ within("tr[data-feature=world-domination] td[data-strategy=active-record]") do
136
+ click_on "clear"
137
+ end
138
+
139
+ within("tr[data-feature=world-domination]") do
140
+ assert_equal "off", first("td.status").text
141
+ refute has_selector?("td[data-strategy=active-record] input.active[type=submit]")
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ describe "with hidden strategy" do
148
+ before do
149
+ Flipflop::FeatureSet.current.instance_variable_set(:@strategies, {})
150
+ Module.new do
151
+ extend Flipflop::Configurable
152
+ strategy :query_string, hidden: true
153
+ end
154
+
155
+ visit "/flipflop"
156
+ end
157
+
158
+ it "should not show hidden strategy" do
159
+ assert_equal [], all("thead th").map(&:text)[3..-1]
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,96 @@
1
+ require "bundler/setup"
2
+ require "flipflop"
3
+
4
+ gem "minitest"
5
+ require "minitest/autorun"
6
+
7
+ require "action_controller"
8
+
9
+ # Who is setting this to true? :o
10
+ $VERBOSE = false
11
+
12
+ def create_request
13
+ env = Rack::MockRequest.env_for("/example")
14
+ request = ActionDispatch::TestRequest.new(env)
15
+ request.host = "example.com"
16
+
17
+ class << request
18
+ def cookie_jar
19
+ @cookie_jar ||= begin
20
+ method = ActionDispatch::Cookies::CookieJar.method(:build)
21
+ if method.arity == 2 # Rails 5.0
22
+ method.call(self, {})
23
+ else
24
+ method.call(self)
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ request
31
+ end
32
+
33
+ def reload_constant(name)
34
+ ActiveSupport::Dependencies.remove_constant(name.to_s)
35
+ path = ActiveSupport::Dependencies.search_for_file(name.to_s.underscore).sub!(/\.rb\z/, "")
36
+ ActiveSupport::Dependencies.loaded.delete(path)
37
+ Object.const_get(name)
38
+ end
39
+
40
+ class TestApp
41
+ class << self
42
+ def new
43
+ ActiveSupport::Dependencies.remove_constant("App")
44
+ super.tap do |current|
45
+ current.create!
46
+ current.load!
47
+ current.migrate!
48
+ reload_constant("Flipflop::Feature")
49
+ end
50
+ end
51
+ end
52
+
53
+ def create!
54
+ require "rails/generators"
55
+ require "rails/generators/rails/app/app_generator"
56
+ require "generators/flipflop/install/install_generator"
57
+
58
+ FileUtils.rm_rf(File.expand_path("../../tmp/app", __FILE__))
59
+ Dir.chdir(File.expand_path("../..", __FILE__))
60
+
61
+ Rails::Generators::AppGenerator.new(["tmp/app"],
62
+ quiet: true,
63
+ skip_active_job: true,
64
+ skip_bundle: true,
65
+ skip_gemfile: true,
66
+ skip_git: true,
67
+ skip_javascript: true,
68
+ skip_keeps: true,
69
+ skip_spring: true,
70
+ skip_test_unit: true,
71
+ skip_turbolinks: true,
72
+ ).invoke_all
73
+
74
+ Flipflop::InstallGenerator.new([],
75
+ quiet: true,
76
+ ).invoke_all
77
+ end
78
+
79
+ def load!
80
+ ENV["RAILS_ENV"] = "test"
81
+ require "rails"
82
+ require "flipflop/engine"
83
+ require File.expand_path("../../tmp/app/config/environment", __FILE__)
84
+ ActiveSupport::Dependencies.mechanism = :load
85
+ load(Rails.application.paths["config/features.rb"].existent.first)
86
+ require "capybara/rails"
87
+ end
88
+
89
+ def migrate!
90
+ ActiveRecord::Base.establish_connection
91
+
92
+ ActiveRecord::Tasks::DatabaseTasks.create_current
93
+ ActiveRecord::Migration.verbose = false
94
+ ActiveRecord::Migrator.migrate(Rails.application.paths["db/migrate"].to_a)
95
+ end
96
+ end
@@ -0,0 +1,104 @@
1
+ require File.expand_path("../../test_helper", __FILE__)
2
+
3
+ describe Flipflop::Configurable do
4
+ subject do
5
+ Flipflop::FeatureSet.current.reset!
6
+ Module.new do
7
+ extend Flipflop::Configurable
8
+ end
9
+ end
10
+
11
+ describe "feature" do
12
+ it "should append feature definition" do
13
+ subject.feature(:one, default: true)
14
+ subject.feature(:two, default: false)
15
+
16
+ assert_equal [:one, :two],
17
+ Flipflop::FeatureSet.current.features.map(&:key)
18
+ end
19
+
20
+ it "should append feature definition with default" do
21
+ subject.feature(:one, default: true)
22
+ subject.feature(:two, default: false)
23
+
24
+ assert_equal [true, false],
25
+ Flipflop::FeatureSet.current.features.map(&:default)
26
+ end
27
+ end
28
+
29
+ describe "strategy" do
30
+ it "should append strategy objects" do
31
+ strategy_class = Class.new(Flipflop::Strategies::AbstractStrategy)
32
+ strategies = [
33
+ strategy_class.new,
34
+ strategy_class.new,
35
+ ]
36
+
37
+ subject.strategy(strategies[0])
38
+ subject.strategy(strategies[1])
39
+
40
+ assert_equal strategies, Flipflop::FeatureSet.current.strategies
41
+ end
42
+
43
+ it "should append strategy classes" do
44
+ strategies = [
45
+ Class.new(Flipflop::Strategies::AbstractStrategy),
46
+ Class.new(Flipflop::Strategies::AbstractStrategy),
47
+ ]
48
+
49
+ subject.strategy(strategies[0])
50
+ subject.strategy(strategies[1])
51
+
52
+ assert_equal strategies, Flipflop::FeatureSet.current.strategies.map(&:class)
53
+ end
54
+
55
+ it "should append strategy classes with options" do
56
+ strategy_class = Class.new(Flipflop::Strategies::AbstractStrategy)
57
+
58
+ subject.strategy(strategy_class, name: "my strategy")
59
+ subject.strategy(strategy_class, name: "awesome strategy")
60
+
61
+ assert_equal ["my strategy", "awesome strategy"],
62
+ Flipflop::FeatureSet.current.strategies.map(&:name)
63
+ end
64
+
65
+ it "should append strategy symbols" do
66
+ subject.strategy(:cookie)
67
+ subject.strategy(:query_string)
68
+
69
+ assert_equal [
70
+ Flipflop::Strategies::CookieStrategy,
71
+ Flipflop::Strategies::QueryStringStrategy
72
+ ], Flipflop::FeatureSet.current.strategies.map(&:class)
73
+ end
74
+
75
+ it "should append strategy symbols with options" do
76
+ subject.strategy(:cookie, name: "my strategy")
77
+ subject.strategy(:query_string, name: "awesome strategy")
78
+
79
+ assert_equal ["my strategy", "awesome strategy"],
80
+ Flipflop::FeatureSet.current.strategies.map(&:name)
81
+ end
82
+
83
+ it "should append strategy lambda" do
84
+ subject.strategy { |feature| "hi!" }
85
+
86
+ assert_equal [Flipflop::Strategies::LambdaStrategy],
87
+ Flipflop::FeatureSet.current.strategies.map(&:class)
88
+ end
89
+
90
+ it "should append strategy lambda with name" do
91
+ subject.strategy(:my_strategy) { |feature| "hi!" }
92
+
93
+ assert_equal ["my_strategy"],
94
+ Flipflop::FeatureSet.current.strategies.map(&:name)
95
+ end
96
+
97
+ it "should append strategy lambda with name and options" do
98
+ subject.strategy("my strategy", description: "awesome") { |feature| "hi!" }
99
+
100
+ assert_equal ["awesome"],
101
+ Flipflop::FeatureSet.current.strategies.map(&:description)
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,142 @@
1
+ require File.expand_path("../../test_helper", __FILE__)
2
+
3
+ describe Flipflop::FeatureCache do
4
+ subject do
5
+ Flipflop::FeatureCache.current
6
+ end
7
+
8
+ after do
9
+ Flipflop::FeatureCache.current.disable!
10
+ end
11
+
12
+ describe "current" do
13
+ it "should return same instance" do
14
+ current = subject
15
+ assert_equal current, Flipflop::FeatureCache.current
16
+ end
17
+
18
+ it "should return new instance in different thread" do
19
+ current = subject
20
+ refute_equal current, Thread.new { Flipflop::FeatureCache.current }.value
21
+ end
22
+ end
23
+
24
+ describe "when enabled" do
25
+ before do
26
+ subject.enable!
27
+ end
28
+
29
+ describe "enabled" do
30
+ it "should return true" do
31
+ assert_equal true, subject.enabled?
32
+ end
33
+ end
34
+
35
+ describe "fetch" do
36
+ it "should store value by key" do
37
+ subject.fetch(:key) { 1 }
38
+ assert_equal 1, subject.fetch(:key) { 2 }
39
+ end
40
+
41
+ it "should not call block if cached" do
42
+ called = false
43
+ subject.fetch(:key) { 1 }
44
+ subject.fetch(:key) { called = true }
45
+ assert_equal false, called
46
+ end
47
+ end
48
+
49
+ describe "clear" do
50
+ it "should empty cache" do
51
+ subject.fetch(:key) { 1 }
52
+ subject.clear!
53
+ assert_equal 2, subject.fetch(:key) { 2 }
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "when disabled" do
59
+ before do
60
+ subject.disable!
61
+ end
62
+
63
+ describe "enabled" do
64
+ it "should return false" do
65
+ assert_equal false, subject.enabled?
66
+ end
67
+ end
68
+
69
+ describe "fetch" do
70
+ it "should not store value" do
71
+ subject.fetch(:key) { 1 }
72
+ assert_equal 2, subject.fetch(:key) { 2 }
73
+ end
74
+
75
+ it "should always call block" do
76
+ called = false
77
+ subject.fetch(:key) { 1 }
78
+ subject.fetch(:key) { called = true }
79
+ assert_equal true, called
80
+ end
81
+ end
82
+ end
83
+
84
+ describe "enable" do
85
+ it "should not clear cache" do
86
+ subject.enable!
87
+ subject.fetch(:key) { 1 }
88
+ subject.enable!
89
+ assert_equal 1, subject.fetch(:key) { 2 }
90
+ end
91
+ end
92
+
93
+ describe "disable" do
94
+ it "should clear cache" do
95
+ subject.enable!
96
+ subject.fetch(:key) { 1 }
97
+ subject.disable!
98
+ subject.enable!
99
+ assert_equal 2, subject.fetch(:key) { 2 }
100
+ end
101
+ end
102
+
103
+ describe "middleware" do
104
+ subject do
105
+ app = ->(env) {
106
+ raise env["error"] if env["error"]
107
+ env["cache"] = Flipflop::FeatureCache.current.enabled?
108
+ return [200, {}, ["ok"]]
109
+ }
110
+ Flipflop::FeatureCache::Middleware.new(app)
111
+ end
112
+
113
+ it "should call app" do
114
+ response = subject.call({})
115
+ assert_equal "ok", response[2].to_a.join
116
+ end
117
+
118
+ it "should enable cache before request" do
119
+ response = subject.call(env = {})
120
+ response[2].try(:close)
121
+ assert_equal true, env["cache"]
122
+ end
123
+
124
+ it "should disable cache after request" do
125
+ response = subject.call({})
126
+ response[2].try(:close)
127
+ assert_equal false, Flipflop::FeatureCache.current.enabled?
128
+ end
129
+
130
+ it "should disable cache after error" do
131
+ subject.call({ "error" => "boo!" }) rescue nil
132
+ assert_equal false, Flipflop::FeatureCache.current.enabled?
133
+ end
134
+
135
+ it "should not change cache if already enabled" do
136
+ Flipflop::FeatureCache.current.enable!
137
+ response = subject.call({})
138
+ response[2].try(:close)
139
+ assert_equal true, Flipflop::FeatureCache.current.enabled?
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,42 @@
1
+ require File.expand_path("../../test_helper", __FILE__)
2
+
3
+ describe Flipflop::FeatureDefinition do
4
+ describe "with defaults" do
5
+ subject do
6
+ Flipflop::FeatureDefinition.new(:my_key)
7
+ end
8
+
9
+ it "should have specified key" do
10
+ assert_equal :my_key, subject.key
11
+ end
12
+
13
+ it "should have humanized description" do
14
+ assert_equal "My key.", subject.description
15
+ end
16
+
17
+ it "should default to false" do
18
+ assert_equal false, subject.default
19
+ end
20
+ end
21
+
22
+ describe "with options" do
23
+ subject do
24
+ Flipflop::FeatureDefinition.new(:my_key,
25
+ default: true,
26
+ description: "Awesome feature",
27
+ )
28
+ end
29
+
30
+ it "should have specified key" do
31
+ assert_equal :my_key, subject.key
32
+ end
33
+
34
+ it "should have specified description" do
35
+ assert_equal "Awesome feature", subject.description
36
+ end
37
+
38
+ it "should have specified default" do
39
+ assert_equal true, subject.default
40
+ end
41
+ end
42
+ end