flipper-ui 0.2.0.beta2 → 0.2.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (218) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +12 -11
  3. data/README.md +5 -7
  4. data/examples/basic.ru +27 -26
  5. data/flipper-ui.gemspec +5 -3
  6. data/lib/flipper-ui.rb +1 -0
  7. data/lib/flipper/ui.rb +11 -2
  8. data/lib/flipper/ui/action.rb +45 -4
  9. data/lib/flipper/ui/actions/actors_gate.rb +48 -0
  10. data/lib/flipper/ui/actions/add_feature.rb +20 -0
  11. data/lib/flipper/ui/actions/boolean_gate.rb +26 -0
  12. data/lib/flipper/ui/actions/feature.rb +32 -0
  13. data/lib/flipper/ui/actions/features.rb +23 -3
  14. data/lib/flipper/ui/actions/file.rb +1 -1
  15. data/lib/flipper/ui/actions/gate.rb +11 -117
  16. data/lib/flipper/ui/actions/groups_gate.rb +43 -0
  17. data/lib/flipper/ui/actions/{index.rb → home.rb} +3 -3
  18. data/lib/flipper/ui/actions/percentage_of_actors_gate.rb +27 -0
  19. data/lib/flipper/ui/actions/percentage_of_time_gate.rb +27 -0
  20. data/lib/flipper/ui/actor.rb +13 -0
  21. data/lib/flipper/ui/assets/javascripts/application.coffee +0 -305
  22. data/lib/flipper/ui/assets/stylesheets/_bootstrap-compass.scss +9 -0
  23. data/lib/flipper/ui/assets/stylesheets/_bootstrap-mincer.scss +19 -0
  24. data/lib/flipper/ui/assets/stylesheets/_bootstrap-sprockets.scss +9 -0
  25. data/lib/flipper/ui/assets/stylesheets/_bootstrap.scss +50 -0
  26. data/lib/flipper/ui/assets/stylesheets/application.scss +33 -216
  27. data/lib/flipper/ui/assets/stylesheets/bootstrap/_alerts.scss +73 -0
  28. data/lib/flipper/ui/assets/stylesheets/bootstrap/_badges.scss +68 -0
  29. data/lib/flipper/ui/assets/stylesheets/bootstrap/_breadcrumbs.scss +26 -0
  30. data/lib/flipper/ui/assets/stylesheets/bootstrap/_button-groups.scss +243 -0
  31. data/lib/flipper/ui/assets/stylesheets/bootstrap/_buttons.scss +160 -0
  32. data/lib/flipper/ui/assets/stylesheets/bootstrap/_carousel.scss +269 -0
  33. data/lib/flipper/ui/assets/stylesheets/bootstrap/_close.scss +36 -0
  34. data/lib/flipper/ui/assets/stylesheets/bootstrap/_code.scss +69 -0
  35. data/lib/flipper/ui/assets/stylesheets/bootstrap/_component-animations.scss +37 -0
  36. data/lib/flipper/ui/assets/stylesheets/bootstrap/_dropdowns.scss +214 -0
  37. data/lib/flipper/ui/assets/stylesheets/bootstrap/_forms.scss +578 -0
  38. data/lib/flipper/ui/assets/stylesheets/bootstrap/_glyphicons.scss +305 -0
  39. data/lib/flipper/ui/assets/stylesheets/bootstrap/_grid.scss +84 -0
  40. data/lib/flipper/ui/assets/stylesheets/bootstrap/_input-groups.scss +166 -0
  41. data/lib/flipper/ui/assets/stylesheets/bootstrap/_jumbotron.scss +50 -0
  42. data/lib/flipper/ui/assets/stylesheets/bootstrap/_labels.scss +66 -0
  43. data/lib/flipper/ui/assets/stylesheets/bootstrap/_list-group.scss +124 -0
  44. data/lib/flipper/ui/assets/stylesheets/bootstrap/_media.scss +61 -0
  45. data/lib/flipper/ui/assets/stylesheets/bootstrap/_mixins.scss +39 -0
  46. data/lib/flipper/ui/assets/stylesheets/bootstrap/_modals.scss +150 -0
  47. data/lib/flipper/ui/assets/stylesheets/bootstrap/_navbar.scss +662 -0
  48. data/lib/flipper/ui/assets/stylesheets/bootstrap/_navs.scss +242 -0
  49. data/lib/flipper/ui/assets/stylesheets/bootstrap/_normalize.scss +427 -0
  50. data/lib/flipper/ui/assets/stylesheets/bootstrap/_pager.scss +54 -0
  51. data/lib/flipper/ui/assets/stylesheets/bootstrap/_pagination.scss +88 -0
  52. data/lib/flipper/ui/assets/stylesheets/bootstrap/_panels.scss +265 -0
  53. data/lib/flipper/ui/assets/stylesheets/bootstrap/_popovers.scss +135 -0
  54. data/lib/flipper/ui/assets/stylesheets/bootstrap/_print.scss +107 -0
  55. data/lib/flipper/ui/assets/stylesheets/bootstrap/_progress-bars.scss +87 -0
  56. data/lib/flipper/ui/assets/stylesheets/bootstrap/_responsive-embed.scss +35 -0
  57. data/lib/flipper/ui/assets/stylesheets/bootstrap/_responsive-utilities.scss +177 -0
  58. data/lib/flipper/ui/assets/stylesheets/bootstrap/_scaffolding.scss +162 -0
  59. data/lib/flipper/ui/assets/stylesheets/bootstrap/_tables.scss +234 -0
  60. data/lib/flipper/ui/assets/stylesheets/bootstrap/_theme.scss +273 -0
  61. data/lib/flipper/ui/assets/stylesheets/bootstrap/_thumbnails.scss +38 -0
  62. data/lib/flipper/ui/assets/stylesheets/bootstrap/_tooltip.scss +102 -0
  63. data/lib/flipper/ui/assets/stylesheets/bootstrap/_type.scss +298 -0
  64. data/lib/flipper/ui/assets/stylesheets/bootstrap/_utilities.scss +55 -0
  65. data/lib/flipper/ui/assets/stylesheets/bootstrap/_variables.scss +866 -0
  66. data/lib/flipper/ui/assets/stylesheets/bootstrap/_wells.scss +29 -0
  67. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_alerts.scss +14 -0
  68. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_background-variant.scss +11 -0
  69. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_border-radius.scss +18 -0
  70. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_buttons.scss +52 -0
  71. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_center-block.scss +7 -0
  72. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_clearfix.scss +22 -0
  73. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_forms.scss +88 -0
  74. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_gradients.scss +58 -0
  75. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_grid-framework.scss +81 -0
  76. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_grid.scss +122 -0
  77. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_hide-text.scss +21 -0
  78. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_image.scss +33 -0
  79. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_labels.scss +12 -0
  80. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_list-group.scss +31 -0
  81. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_nav-divider.scss +10 -0
  82. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_nav-vertical-align.scss +9 -0
  83. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_opacity.scss +8 -0
  84. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_pagination.scss +23 -0
  85. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_panels.scss +24 -0
  86. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_progress-bar.scss +10 -0
  87. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_reset-filter.scss +8 -0
  88. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_resize.scss +6 -0
  89. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_responsive-visibility.scss +21 -0
  90. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_size.scss +10 -0
  91. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_tab-focus.scss +9 -0
  92. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_table-row.scss +28 -0
  93. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_text-emphasis.scss +11 -0
  94. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_text-overflow.scss +8 -0
  95. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_vendor-prefixes.scss +222 -0
  96. data/lib/flipper/ui/assets/stylesheets/primer/.scss-lint.yml +446 -0
  97. data/lib/flipper/ui/assets/stylesheets/primer/_alerts.scss +106 -0
  98. data/lib/flipper/ui/assets/stylesheets/primer/_avatars.scss +36 -0
  99. data/lib/flipper/ui/assets/stylesheets/primer/_base.scss +40 -0
  100. data/lib/flipper/ui/assets/stylesheets/primer/_blankslate.scss +96 -0
  101. data/lib/flipper/ui/assets/stylesheets/primer/_buttons.scss +404 -0
  102. data/lib/flipper/ui/assets/stylesheets/primer/_counter.scss +10 -0
  103. data/lib/flipper/ui/assets/stylesheets/primer/_filter-list.scss +68 -0
  104. data/lib/flipper/ui/assets/stylesheets/primer/_flex-table.scss +20 -0
  105. data/lib/flipper/ui/assets/stylesheets/primer/_forms.scss +756 -0
  106. data/lib/flipper/ui/assets/stylesheets/primer/_layout.scss +69 -0
  107. data/lib/flipper/ui/assets/stylesheets/primer/_menu.scss +113 -0
  108. data/lib/flipper/ui/assets/stylesheets/primer/_mixins.scss +53 -0
  109. data/lib/flipper/ui/assets/stylesheets/primer/_normalize.scss +425 -0
  110. data/lib/flipper/ui/assets/stylesheets/primer/_states.scss +32 -0
  111. data/lib/flipper/ui/assets/stylesheets/primer/_tabnav.scss +65 -0
  112. data/lib/flipper/ui/assets/stylesheets/primer/_tooltips.scss +255 -0
  113. data/lib/flipper/ui/assets/stylesheets/primer/_truncate.scss +27 -0
  114. data/lib/flipper/ui/assets/stylesheets/primer/_type.scss +92 -0
  115. data/lib/flipper/ui/assets/stylesheets/primer/_utility.scss +73 -0
  116. data/lib/flipper/ui/assets/stylesheets/primer/_variables.scss +34 -0
  117. data/lib/flipper/ui/assets/stylesheets/primer/primer.scss +39 -0
  118. data/lib/flipper/ui/decorators/feature.rb +37 -4
  119. data/lib/flipper/ui/middleware.rb +12 -3
  120. data/lib/flipper/ui/public/css/application.css +2563 -144
  121. data/lib/flipper/ui/public/css/primer.css +1 -0
  122. data/lib/flipper/ui/public/css/primer/primer.css +1933 -0
  123. data/lib/flipper/ui/public/css/scss/primer.css +1933 -0
  124. data/lib/flipper/ui/public/fonts/bootstrap/glyphicons-halflings-regular.eot +0 -0
  125. data/lib/flipper/ui/public/fonts/bootstrap/glyphicons-halflings-regular.svg +288 -0
  126. data/lib/flipper/ui/public/fonts/bootstrap/glyphicons-halflings-regular.ttf +0 -0
  127. data/lib/flipper/ui/public/fonts/bootstrap/glyphicons-halflings-regular.woff +0 -0
  128. data/lib/flipper/ui/public/fonts/bootstrap/glyphicons-halflings-regular.woff2 +0 -0
  129. data/lib/flipper/ui/public/js/application.js +0 -539
  130. data/lib/flipper/ui/public/js/bootstrap-sprockets.js +12 -0
  131. data/lib/flipper/ui/public/js/bootstrap.js +2317 -0
  132. data/lib/flipper/ui/public/js/bootstrap.min.js +7 -0
  133. data/lib/flipper/ui/public/js/bootstrap/affix.js +162 -0
  134. data/lib/flipper/ui/public/js/bootstrap/alert.js +94 -0
  135. data/lib/flipper/ui/public/js/bootstrap/button.js +116 -0
  136. data/lib/flipper/ui/public/js/bootstrap/carousel.js +237 -0
  137. data/lib/flipper/ui/public/js/bootstrap/collapse.js +211 -0
  138. data/lib/flipper/ui/public/js/bootstrap/dropdown.js +161 -0
  139. data/lib/flipper/ui/public/js/bootstrap/modal.js +339 -0
  140. data/lib/flipper/ui/public/js/bootstrap/popover.js +108 -0
  141. data/lib/flipper/ui/public/js/bootstrap/scrollspy.js +172 -0
  142. data/lib/flipper/ui/public/js/bootstrap/tab.js +153 -0
  143. data/lib/flipper/ui/public/js/bootstrap/tooltip.js +476 -0
  144. data/lib/flipper/ui/public/js/bootstrap/transition.js +59 -0
  145. data/lib/flipper/ui/public/octicons/LICENSE.txt +9 -0
  146. data/lib/flipper/ui/public/octicons/README.md +1 -0
  147. data/lib/flipper/ui/public/octicons/octicons-local.ttf +0 -0
  148. data/lib/flipper/ui/public/octicons/octicons.css +236 -0
  149. data/lib/flipper/ui/public/octicons/octicons.eot +0 -0
  150. data/lib/flipper/ui/public/octicons/octicons.less +235 -0
  151. data/lib/flipper/ui/public/octicons/octicons.svg +200 -0
  152. data/lib/flipper/ui/public/octicons/octicons.ttf +0 -0
  153. data/lib/flipper/ui/public/octicons/octicons.woff +0 -0
  154. data/lib/flipper/ui/public/octicons/sprockets-octicons.scss +232 -0
  155. data/lib/flipper/ui/util.rb +4 -0
  156. data/lib/flipper/ui/version.rb +1 -1
  157. data/lib/flipper/ui/views/add_actor.erb +22 -0
  158. data/lib/flipper/ui/views/add_feature.erb +18 -0
  159. data/lib/flipper/ui/views/add_group.erb +31 -0
  160. data/lib/flipper/ui/views/feature.erb +209 -0
  161. data/lib/flipper/ui/views/features.erb +46 -0
  162. data/lib/flipper/ui/views/layout.erb +31 -149
  163. data/script/release +15 -0
  164. data/spec/flipper/ui/actions/actors_gate_spec.rb +68 -0
  165. data/spec/flipper/ui/actions/add_feature_spec.rb +17 -0
  166. data/spec/flipper/ui/actions/boolean_gate_spec.rb +41 -0
  167. data/spec/flipper/ui/actions/feature_spec.rb +59 -0
  168. data/spec/flipper/ui/actions/features_spec.rb +37 -0
  169. data/spec/flipper/ui/actions/file_spec.rb +43 -0
  170. data/spec/flipper/ui/actions/gate_spec.rb +24 -0
  171. data/spec/flipper/ui/actions/groups_gate_spec.rb +80 -0
  172. data/spec/flipper/ui/actions/home_spec.rb +16 -0
  173. data/spec/flipper/ui/actions/percentage_of_actors_gate_spec.rb +40 -0
  174. data/spec/flipper/ui/actions/percentage_of_time_gate_spec.rb +39 -0
  175. data/spec/flipper/ui/decorators/feature_spec.rb +38 -1
  176. data/spec/flipper/ui/decorators/gate_spec.rb +1 -1
  177. data/spec/flipper/ui_spec.rb +18 -441
  178. data/spec/helper.rb +22 -7
  179. metadata +199 -52
  180. data/examples/flipper.html +0 -14
  181. data/examples/flipper.png +0 -0
  182. data/lib/flipper/ui/assets/javascripts/spine/ajax.coffee +0 -223
  183. data/lib/flipper/ui/assets/javascripts/spine/list.coffee +0 -43
  184. data/lib/flipper/ui/assets/javascripts/spine/local.coffee +0 -16
  185. data/lib/flipper/ui/assets/javascripts/spine/manager.coffee +0 -83
  186. data/lib/flipper/ui/assets/javascripts/spine/relation.coffee +0 -148
  187. data/lib/flipper/ui/assets/javascripts/spine/route.coffee +0 -146
  188. data/lib/flipper/ui/assets/javascripts/spine/spine.coffee +0 -542
  189. data/lib/flipper/ui/assets/javascripts/spine/version +0 -1
  190. data/lib/flipper/ui/public/css/images/animated-overlay.gif +0 -0
  191. data/lib/flipper/ui/public/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  192. data/lib/flipper/ui/public/css/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  193. data/lib/flipper/ui/public/css/images/ui-bg_flat_10_000000_40x100.png +0 -0
  194. data/lib/flipper/ui/public/css/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  195. data/lib/flipper/ui/public/css/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  196. data/lib/flipper/ui/public/css/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  197. data/lib/flipper/ui/public/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  198. data/lib/flipper/ui/public/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  199. data/lib/flipper/ui/public/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  200. data/lib/flipper/ui/public/css/images/ui-icons_222222_256x240.png +0 -0
  201. data/lib/flipper/ui/public/css/images/ui-icons_228ef1_256x240.png +0 -0
  202. data/lib/flipper/ui/public/css/images/ui-icons_ef8c08_256x240.png +0 -0
  203. data/lib/flipper/ui/public/css/images/ui-icons_ffd27a_256x240.png +0 -0
  204. data/lib/flipper/ui/public/css/images/ui-icons_ffffff_256x240.png +0 -0
  205. data/lib/flipper/ui/public/css/jquery-ui-1.10.3.slider.min.css +0 -5
  206. data/lib/flipper/ui/public/js/handlebars.js +0 -1992
  207. data/lib/flipper/ui/public/js/jquery-ui-1.10.3.slider.min.js +0 -6
  208. data/lib/flipper/ui/public/js/jquery.js +0 -9555
  209. data/lib/flipper/ui/public/js/jquery.min.js +0 -4
  210. data/lib/flipper/ui/public/js/jquery.min.map +0 -1
  211. data/lib/flipper/ui/public/js/spine/ajax.js +0 -320
  212. data/lib/flipper/ui/public/js/spine/list.js +0 -72
  213. data/lib/flipper/ui/public/js/spine/local.js +0 -29
  214. data/lib/flipper/ui/public/js/spine/manager.js +0 -157
  215. data/lib/flipper/ui/public/js/spine/relation.js +0 -260
  216. data/lib/flipper/ui/public/js/spine/route.js +0 -223
  217. data/lib/flipper/ui/public/js/spine/spine.js +0 -927
  218. data/lib/flipper/ui/views/index.erb +0 -9
@@ -0,0 +1,39 @@
1
+ require 'helper'
2
+
3
+ describe Flipper::UI::Actions::PercentageOfTimeGate do
4
+ describe "POST /features/:feature/percentage_of_time" do
5
+ context "with valid value" do
6
+ before do
7
+ post "features/search/percentage_of_time",
8
+ {"value" => "24", "authenticity_token" => "a"},
9
+ "rack.session" => {:csrf => "a"}
10
+ end
11
+
12
+ it "enables the feature" do
13
+ flipper[:search].percentage_of_time_value.should be(24)
14
+ end
15
+
16
+ it "redirects back to feature" do
17
+ last_response.status.should be(302)
18
+ last_response.headers["Location"].should eq("/features/search")
19
+ end
20
+ end
21
+
22
+ context "with invalid value" do
23
+ before do
24
+ post "features/search/percentage_of_time",
25
+ {"value" => "555", "authenticity_token" => "a"},
26
+ "rack.session" => {:csrf => "a"}
27
+ end
28
+
29
+ it "does not change value" do
30
+ flipper[:search].percentage_of_time_value.should be(0)
31
+ end
32
+
33
+ it "redirects back to feature" do
34
+ last_response.status.should be(302)
35
+ last_response.headers["Location"].should eq("/features/search?error=Invalid+percentage+of+time+value%3A+value+must+be+a+positive+number+less+than+or+equal+to+100%2C+but+was+555")
36
+ end
37
+ end
38
+ end
39
+ end
@@ -4,7 +4,7 @@ require 'flipper/adapters/memory'
4
4
  describe Flipper::UI::Decorators::Feature do
5
5
  let(:source) { {} }
6
6
  let(:adapter) { Flipper::Adapters::Memory.new(source) }
7
- let(:flipper) { Flipper.new(adapter) }
7
+ let(:flipper) { build_flipper }
8
8
  let(:feature) { flipper[:some_awesome_feature] }
9
9
 
10
10
  subject {
@@ -56,4 +56,41 @@ describe Flipper::UI::Decorators::Feature do
56
56
  @result['gates'].should eq(gates)
57
57
  end
58
58
  end
59
+
60
+ describe "#<=>" do
61
+ let(:on) {
62
+ flipper.enable(:on_a)
63
+ described_class.new(flipper[:on_a])
64
+ }
65
+
66
+ let(:on_b) {
67
+ flipper.enable(:on_b)
68
+ described_class.new(flipper[:on_b])
69
+ }
70
+
71
+ let(:conditional) {
72
+ flipper.enable_percentage_of_time :conditional_a, 5
73
+ described_class.new(flipper[:conditional_a])
74
+ }
75
+
76
+ let(:off) {
77
+ described_class.new(flipper[:off_a])
78
+ }
79
+
80
+ it "sorts :on before :conditional" do
81
+ (on <=> conditional).should be(-1)
82
+ end
83
+
84
+ it "sorts :on before :off" do
85
+ (on <=> conditional).should be(-1)
86
+ end
87
+
88
+ it "sorts :conditional before :off" do
89
+ (on <=> conditional).should be(-1)
90
+ end
91
+
92
+ it "sorts on key for identical states" do
93
+ (on <=> on_b).should be(-1)
94
+ end
95
+ end
59
96
  end
@@ -5,7 +5,7 @@ require 'flipper/ui/decorators/gate'
5
5
  describe Flipper::UI::Decorators::Gate do
6
6
  let(:source) { {} }
7
7
  let(:adapter) { Flipper::Adapters::Memory.new(source) }
8
- let(:flipper) { Flipper.new(adapter) }
8
+ let(:flipper) { build_flipper }
9
9
  let(:feature) { flipper[:some_awesome_feature] }
10
10
  let(:gate) { feature.gate(:boolean) }
11
11
 
@@ -2,469 +2,46 @@ require 'helper'
2
2
  require 'rack/test'
3
3
  require 'flipper'
4
4
  require 'flipper/adapters/memory'
5
- require 'open-uri'
6
5
 
7
6
  describe Flipper::UI do
8
7
  include Rack::Test::Methods
9
8
 
10
- let(:source) { {} }
11
- let(:adapter) { Flipper::Adapters::Memory.new(source) }
9
+ let(:flipper) { build_flipper }
10
+ let(:app) { build_app(flipper) }
12
11
 
13
- let(:flipper) {
14
- Flipper.new(adapter, :instrumenter => ActiveSupport::Notifications)
15
- }
16
-
17
- let(:app) { described_class.app(flipper) }
18
-
19
- describe "Initializing middleware lazily with a block" do
20
- let(:app) { described_class.app(lambda { flipper }) }
12
+ describe "Initializing middleware with flipper instance" do
13
+ let(:app) { build_app(flipper) }
21
14
 
22
15
  it "works" do
23
- get '/features'
24
- last_response.status.should be(200)
25
- end
26
- end
27
-
28
- describe "GET /" do
29
- before do
30
- flipper[:stats].enable
31
- flipper[:search].enable
32
- get '/'
33
- end
34
-
35
- it "responds with 200" do
36
- last_response.status.should be(200)
37
- end
38
-
39
- it "renders view" do
40
- last_response.body.should match(/Flipper/)
41
- end
42
- end
43
-
44
- describe "GET /features" do
45
- before do
46
- flipper[:new_stats].enable
47
- flipper[:search].disable
48
- get '/features'
49
- end
50
-
51
- it "responds with 200" do
52
- last_response.status.should be(200)
53
- end
54
-
55
- it "responds with content type of json" do
56
- last_response.content_type.should eq('application/json')
57
- end
58
-
59
- it "renders view" do
60
- features = json_response
61
- features.should be_instance_of(Array)
62
-
63
- feature = features[0]
64
- feature['id'].should eq('new_stats')
65
- feature['name'].should eq('New Stats')
66
- feature['state'].should eq('on')
67
- feature['description'].should eq('Enabled')
68
- feature['gates'].first.should eq({
69
- 'key' => 'boolean',
70
- 'name' => 'boolean',
71
- 'value' => true,
72
- })
73
-
74
- feature = features[1]
75
- feature['id'].should eq('search')
76
- feature['name'].should eq('Search')
77
- feature['state'].should eq('off')
78
- feature['description'].should eq('Disabled')
79
- feature['gates'].first.should eq({
80
- 'key' => 'boolean',
81
- 'name' => 'boolean',
82
- 'value' => false,
83
- })
84
- end
85
- end
86
-
87
- describe "POST /features/:id/non_existent_gate_name" do
88
- before do
89
- feature = flipper[:some_thing]
90
- params = {
91
- 'value' => 'something',
92
- }
93
- post "/features/#{feature.name}/non_existent_gate_name", params
94
- end
95
-
96
- it "responds with 404" do
97
- last_response.status.should be(404)
98
- end
99
-
100
- it "includes status and message" do
101
- result = json_response
102
- result['status'].should eq('error')
103
- result['message'].should eq('I have no clue how to update the gate named "non_existent_gate_name".')
104
- end
105
- end
106
-
107
- describe "POST /features/:id/boolean" do
108
- before do
109
- feature = flipper[:some_thing]
110
- feature.enable
111
- params = {
112
- 'value' => 'false',
113
- }
114
- post "/features/#{feature.name}/boolean", params
115
- end
116
-
117
- it "responds with 200" do
16
+ flipper.enable :some_great_feature
17
+ get "/features"
118
18
  last_response.status.should be(200)
119
- end
120
-
121
- it "responds with json" do
122
- result = json_response
123
- result.should be_instance_of(Hash)
124
- result['name'].should eq('boolean')
125
- result['key'].should eq('boolean')
126
- result['value'].should eq(false)
127
- end
128
-
129
- it "updates gate state" do
130
- flipper[:some_thing].state.should be(:off)
19
+ last_response.body.should include("some_great_feature")
131
20
  end
132
21
  end
133
22
 
134
- describe "POST /features/:id/boolean for values that are URI encoded" do
135
- before do
136
- feature = flipper["feature:v1"]
137
- feature.enable
138
- params = {
139
- 'value' => 'false',
140
- }
141
- feature_encoded_name = URI.encode_www_form_component(feature.name)
142
- post "/features/#{feature_encoded_name}/boolean", params
143
- end
144
-
145
- it "responds with 200" do
146
- last_response.status.should be(200)
147
- end
148
-
149
- it "responds with json" do
150
- result = json_response
151
- result.should be_instance_of(Hash)
152
- result['name'].should eq('boolean')
153
- result['key'].should eq('boolean')
154
- result['value'].should eq(false)
155
- end
156
-
157
- it "updates gate state" do
158
- flipper["feature:v1"].state.should be(:off)
159
- end
160
- end
161
-
162
- describe "POST /features/:id/percentage_of_actors" do
163
- context "valid value" do
164
- before do
165
- feature = flipper[:some_thing]
166
- params = {
167
- 'value' => '5',
168
- }
169
- post "/features/#{feature.name}/percentage_of_actors", params
170
- end
171
-
172
- it "responds with 200" do
173
- last_response.status.should be(200)
174
- end
175
-
176
- it "responds with json" do
177
- result = json_response
178
- result.should be_instance_of(Hash)
179
- result['name'].should eq('percentage_of_actors')
180
- result['key'].should eq('percentage_of_actors')
181
- result['value'].should eq(5)
182
- end
183
-
184
- it "updates gate state" do
185
- gate_value(:some_thing, :percentage_of_actors).to_i.should be(5)
186
- end
187
- end
188
-
189
- context "invalid value" do
190
- before do
191
- feature = flipper[:some_thing]
192
- params = {
193
- 'value' => '555',
194
- }
195
- post "/features/#{feature.name}/percentage_of_actors", params
196
- end
197
-
198
- it "responds with 422" do
199
- last_response.status.should be(422)
200
- end
201
-
202
- it "includes status and message in response" do
203
- result = json_response
204
- result['status'].should eq('error')
205
- result['message'].should eq('value must be a positive number less than or equal to 100, but was 555')
206
- end
207
- end
208
- end
209
-
210
- describe "POST /features/:id/percentage_of_time" do
211
- context "valid value" do
212
- before do
213
- feature = flipper[:some_thing]
214
- params = {
215
- 'value' => '5',
216
- }
217
- post "/features/#{feature.name}/percentage_of_time", params
218
- end
219
-
220
- it "responds with 200" do
221
- last_response.status.should be(200)
222
- end
223
-
224
- it "responds with json" do
225
- result = json_response
226
- result.should be_instance_of(Hash)
227
- result['name'].should eq('percentage_of_time')
228
- result['key'].should eq('percentage_of_time')
229
- result['value'].should eq(5)
230
- end
231
-
232
- it "updates gate state" do
233
- gate_value(:some_thing, :percentage_of_time).to_i.should be(5)
234
- end
235
- end
236
-
237
- context "invalid value" do
238
- before do
239
- feature = flipper[:some_thing]
240
- params = {
241
- 'value' => '555',
242
- }
243
- post "/features/#{feature.name}/percentage_of_time", params
244
- end
245
-
246
- it "responds with 422" do
247
- last_response.status.should be(422)
248
- end
249
-
250
- it "includes status and message in response" do
251
- result = json_response
252
- result['status'].should eq('error')
253
- result['message'].should eq('value must be a positive number less than or equal to 100, but was 555')
254
- end
255
- end
256
- end
257
-
258
- describe "POST /features/:id/actor" do
259
- context "enable" do
260
- before do
261
- feature = flipper[:some_thing]
262
- params = {
263
- 'operation' => 'enable',
264
- 'value' => '11',
265
- }
266
- post "/features/#{feature.name}/actor", params
267
- end
268
-
269
- it "responds with 200" do
270
- last_response.status.should be(200)
271
- end
272
-
273
- it "responds with json" do
274
- result = json_response
275
- result.should be_instance_of(Hash)
276
- result['name'].should eq('actor')
277
- result['key'].should eq('actors')
278
- result['value'].should eq(['11'])
279
- end
280
-
281
- it "updates gate state" do
282
- gate_value(:some_thing, :actors).should include('11')
283
- end
284
- end
285
-
286
- context "disable" do
287
- before do
288
- feature = flipper[:some_thing]
289
- feature.enable Struct.new(:flipper_id).new('11')
290
- params = {
291
- 'operation' => 'disable',
292
- 'value' => '11',
293
- }
294
- post "/features/#{feature.name}/actor", params
295
- end
296
-
297
- it "responds with 200" do
298
- last_response.status.should be(200)
299
- end
300
-
301
- it "responds with json" do
302
- result = json_response
303
- result.should be_instance_of(Hash)
304
- result['name'].should eq('actor')
305
- result['key'].should eq('actors')
306
- result['value'].should eq([])
307
- end
308
-
309
- it "updates gate state" do
310
- gate_value(:some_thing, :actors).should_not include('11')
311
- end
312
- end
313
-
314
- context "invalid value" do
315
- before do
316
- feature = flipper[:some_thing]
317
- params = {
318
- 'operation' => 'enable',
319
- 'value' => '',
320
- }
321
- post "/features/#{feature.name}/actor", params
322
- end
323
-
324
- it "responds with 422" do
325
- last_response.status.should be(422)
326
- end
327
-
328
- it "updates gate state" do
329
- result = json_response
330
- result['status'].should eq('error')
331
- result['message'].should eq('"" is not a valid actor value.')
332
- end
333
- end
334
- end
335
-
336
- describe "POST /features/:id/group" do
337
- before do
338
- Flipper.register(:admins) { |user| user.admin? }
339
- end
340
-
341
- after do
342
- Flipper.unregister_groups
343
- end
344
-
345
- context "enable" do
346
- before do
347
- feature = flipper[:some_thing]
348
- params = {
349
- 'operation' => 'enable',
350
- 'value' => 'admins',
351
- }
352
- post "/features/#{feature.name}/group", params
353
- end
354
-
355
- it "responds with 200" do
356
- last_response.status.should be(200)
357
- end
358
-
359
- it "responds with json" do
360
- result = json_response
361
- result.should be_instance_of(Hash)
362
- result['name'].should eq('group')
363
- result['key'].should eq('groups')
364
- result['value'].should eq(['admins'])
365
- end
366
-
367
- it "updates gate state" do
368
- gate_value(:some_thing, :groups).should include('admins')
369
- end
370
- end
371
-
372
- context "disable" do
373
- before do
374
- feature = flipper[:some_thing]
375
- feature.enable flipper.group(:admins)
376
- params = {
377
- 'operation' => 'disable',
378
- 'value' => 'admins',
379
- }
380
- post "/features/#{feature.name}/group", params
381
- end
382
-
383
- it "responds with 200" do
384
- last_response.status.should be(200)
385
- end
386
-
387
- it "responds with json" do
388
- result = json_response
389
- result.should be_instance_of(Hash)
390
- result['name'].should eq('group')
391
- result['key'].should eq('groups')
392
- result['value'].should eq([])
393
- end
394
-
395
- it "updates gate state" do
396
- gate_value(:some_thing, :groups).should_not include('admins')
397
- end
398
- end
399
-
400
- context "when group is not found" do
401
- before do
402
- feature = flipper[:some_thing]
403
- params = {
404
- 'operation' => 'enable',
405
- 'value' => 'not_here',
406
- }
407
- post "/features/#{feature.name}/group", params
408
- end
409
-
410
- it "responds with 404" do
411
- last_response.status.should be(404)
412
- end
413
- end
414
-
415
- context "when group is empty" do
416
- before do
417
- feature = flipper[:some_thing]
418
- params = {
419
- 'operation' => 'enable',
420
- 'value' => '',
421
- }
422
- post "/features/#{feature.name}/group", params
423
- end
424
-
425
- it "responds with 422" do
426
- last_response.status.should be(422)
427
- end
428
-
429
- it "has message in body" do
430
- hash = JSON.load(last_response.body)
431
- hash["status"].should eq("error")
432
- hash["message"].should eq("Group name is required.")
433
- end
434
- end
435
- end
436
-
437
- describe "GET /images/logo.png" do
438
- before do
439
- get '/images/logo.png'
440
- end
23
+ describe "Initializing middleware lazily with a block" do
24
+ let(:app) { Flipper::UI.app(lambda { flipper }, secret: "test") }
441
25
 
442
- it "responds with 200" do
26
+ it "works" do
27
+ flipper.enable :some_great_feature
28
+ get "/features"
443
29
  last_response.status.should be(200)
30
+ last_response.body.should include("some_great_feature")
444
31
  end
445
32
  end
446
33
 
447
- describe "GET /css/application.css" do
448
- before do
449
- get '/css/application.css'
450
- end
451
-
452
- it "responds with 200" do
453
- last_response.status.should be(200)
34
+ describe "Creating app without secret" do
35
+ it "raises argument error" do
36
+ expect { Flipper::UI.app(flipper) }.to raise_error(ArgumentError, "Flipper::UI.app missing required option: secret")
454
37
  end
455
38
  end
456
39
 
457
- context "Request method unsupported by action" do
40
+ describe "Request method unsupported by action" do
458
41
  it "raises error" do
459
42
  expect {
460
- post '/images/logo.png'
43
+ head '/features'
461
44
  }.to raise_error(Flipper::UI::RequestMethodNotSupported)
462
45
  end
463
46
  end
464
-
465
- # Gets the adapter value for a given feature name and gate key.
466
- def gate_value(feature_name, gate_key)
467
- values = flipper.adapter.get(flipper[feature_name])
468
- values[gate_key]
469
- end
470
47
  end