flipper-ui 0.2.0.beta2 → 0.2.0.beta3

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 (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