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.
- checksums.yaml +4 -4
- data/Gemfile +12 -11
- data/README.md +5 -7
- data/examples/basic.ru +27 -26
- data/flipper-ui.gemspec +5 -3
- data/lib/flipper-ui.rb +1 -0
- data/lib/flipper/ui.rb +11 -2
- data/lib/flipper/ui/action.rb +45 -4
- data/lib/flipper/ui/actions/actors_gate.rb +48 -0
- data/lib/flipper/ui/actions/add_feature.rb +20 -0
- data/lib/flipper/ui/actions/boolean_gate.rb +26 -0
- data/lib/flipper/ui/actions/feature.rb +32 -0
- data/lib/flipper/ui/actions/features.rb +23 -3
- data/lib/flipper/ui/actions/file.rb +1 -1
- data/lib/flipper/ui/actions/gate.rb +11 -117
- data/lib/flipper/ui/actions/groups_gate.rb +43 -0
- data/lib/flipper/ui/actions/{index.rb → home.rb} +3 -3
- data/lib/flipper/ui/actions/percentage_of_actors_gate.rb +27 -0
- data/lib/flipper/ui/actions/percentage_of_time_gate.rb +27 -0
- data/lib/flipper/ui/actor.rb +13 -0
- data/lib/flipper/ui/assets/javascripts/application.coffee +0 -305
- data/lib/flipper/ui/assets/stylesheets/_bootstrap-compass.scss +9 -0
- data/lib/flipper/ui/assets/stylesheets/_bootstrap-mincer.scss +19 -0
- data/lib/flipper/ui/assets/stylesheets/_bootstrap-sprockets.scss +9 -0
- data/lib/flipper/ui/assets/stylesheets/_bootstrap.scss +50 -0
- data/lib/flipper/ui/assets/stylesheets/application.scss +33 -216
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_alerts.scss +73 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_badges.scss +68 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_breadcrumbs.scss +26 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_button-groups.scss +243 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_buttons.scss +160 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_carousel.scss +269 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_close.scss +36 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_code.scss +69 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_component-animations.scss +37 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_dropdowns.scss +214 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_forms.scss +578 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_glyphicons.scss +305 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_grid.scss +84 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_input-groups.scss +166 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_jumbotron.scss +50 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_labels.scss +66 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_list-group.scss +124 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_media.scss +61 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_mixins.scss +39 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_modals.scss +150 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_navbar.scss +662 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_navs.scss +242 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_normalize.scss +427 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_pager.scss +54 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_pagination.scss +88 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_panels.scss +265 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_popovers.scss +135 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_print.scss +107 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_progress-bars.scss +87 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_responsive-embed.scss +35 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_responsive-utilities.scss +177 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_scaffolding.scss +162 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_tables.scss +234 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_theme.scss +273 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_thumbnails.scss +38 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_tooltip.scss +102 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_type.scss +298 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_utilities.scss +55 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_variables.scss +866 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/_wells.scss +29 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_alerts.scss +14 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_background-variant.scss +11 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_border-radius.scss +18 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_buttons.scss +52 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_center-block.scss +7 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_clearfix.scss +22 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_forms.scss +88 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_gradients.scss +58 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_grid-framework.scss +81 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_grid.scss +122 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_hide-text.scss +21 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_image.scss +33 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_labels.scss +12 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_list-group.scss +31 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_nav-divider.scss +10 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_nav-vertical-align.scss +9 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_opacity.scss +8 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_pagination.scss +23 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_panels.scss +24 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_progress-bar.scss +10 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_reset-filter.scss +8 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_resize.scss +6 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_responsive-visibility.scss +21 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_size.scss +10 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_tab-focus.scss +9 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_table-row.scss +28 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_text-emphasis.scss +11 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_text-overflow.scss +8 -0
- data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_vendor-prefixes.scss +222 -0
- data/lib/flipper/ui/assets/stylesheets/primer/.scss-lint.yml +446 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_alerts.scss +106 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_avatars.scss +36 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_base.scss +40 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_blankslate.scss +96 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_buttons.scss +404 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_counter.scss +10 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_filter-list.scss +68 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_flex-table.scss +20 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_forms.scss +756 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_layout.scss +69 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_menu.scss +113 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_mixins.scss +53 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_normalize.scss +425 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_states.scss +32 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_tabnav.scss +65 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_tooltips.scss +255 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_truncate.scss +27 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_type.scss +92 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_utility.scss +73 -0
- data/lib/flipper/ui/assets/stylesheets/primer/_variables.scss +34 -0
- data/lib/flipper/ui/assets/stylesheets/primer/primer.scss +39 -0
- data/lib/flipper/ui/decorators/feature.rb +37 -4
- data/lib/flipper/ui/middleware.rb +12 -3
- data/lib/flipper/ui/public/css/application.css +2563 -144
- data/lib/flipper/ui/public/css/primer.css +1 -0
- data/lib/flipper/ui/public/css/primer/primer.css +1933 -0
- data/lib/flipper/ui/public/css/scss/primer.css +1933 -0
- data/lib/flipper/ui/public/fonts/bootstrap/glyphicons-halflings-regular.eot +0 -0
- data/lib/flipper/ui/public/fonts/bootstrap/glyphicons-halflings-regular.svg +288 -0
- data/lib/flipper/ui/public/fonts/bootstrap/glyphicons-halflings-regular.ttf +0 -0
- data/lib/flipper/ui/public/fonts/bootstrap/glyphicons-halflings-regular.woff +0 -0
- data/lib/flipper/ui/public/fonts/bootstrap/glyphicons-halflings-regular.woff2 +0 -0
- data/lib/flipper/ui/public/js/application.js +0 -539
- data/lib/flipper/ui/public/js/bootstrap-sprockets.js +12 -0
- data/lib/flipper/ui/public/js/bootstrap.js +2317 -0
- data/lib/flipper/ui/public/js/bootstrap.min.js +7 -0
- data/lib/flipper/ui/public/js/bootstrap/affix.js +162 -0
- data/lib/flipper/ui/public/js/bootstrap/alert.js +94 -0
- data/lib/flipper/ui/public/js/bootstrap/button.js +116 -0
- data/lib/flipper/ui/public/js/bootstrap/carousel.js +237 -0
- data/lib/flipper/ui/public/js/bootstrap/collapse.js +211 -0
- data/lib/flipper/ui/public/js/bootstrap/dropdown.js +161 -0
- data/lib/flipper/ui/public/js/bootstrap/modal.js +339 -0
- data/lib/flipper/ui/public/js/bootstrap/popover.js +108 -0
- data/lib/flipper/ui/public/js/bootstrap/scrollspy.js +172 -0
- data/lib/flipper/ui/public/js/bootstrap/tab.js +153 -0
- data/lib/flipper/ui/public/js/bootstrap/tooltip.js +476 -0
- data/lib/flipper/ui/public/js/bootstrap/transition.js +59 -0
- data/lib/flipper/ui/public/octicons/LICENSE.txt +9 -0
- data/lib/flipper/ui/public/octicons/README.md +1 -0
- data/lib/flipper/ui/public/octicons/octicons-local.ttf +0 -0
- data/lib/flipper/ui/public/octicons/octicons.css +236 -0
- data/lib/flipper/ui/public/octicons/octicons.eot +0 -0
- data/lib/flipper/ui/public/octicons/octicons.less +235 -0
- data/lib/flipper/ui/public/octicons/octicons.svg +200 -0
- data/lib/flipper/ui/public/octicons/octicons.ttf +0 -0
- data/lib/flipper/ui/public/octicons/octicons.woff +0 -0
- data/lib/flipper/ui/public/octicons/sprockets-octicons.scss +232 -0
- data/lib/flipper/ui/util.rb +4 -0
- data/lib/flipper/ui/version.rb +1 -1
- data/lib/flipper/ui/views/add_actor.erb +22 -0
- data/lib/flipper/ui/views/add_feature.erb +18 -0
- data/lib/flipper/ui/views/add_group.erb +31 -0
- data/lib/flipper/ui/views/feature.erb +209 -0
- data/lib/flipper/ui/views/features.erb +46 -0
- data/lib/flipper/ui/views/layout.erb +31 -149
- data/script/release +15 -0
- data/spec/flipper/ui/actions/actors_gate_spec.rb +68 -0
- data/spec/flipper/ui/actions/add_feature_spec.rb +17 -0
- data/spec/flipper/ui/actions/boolean_gate_spec.rb +41 -0
- data/spec/flipper/ui/actions/feature_spec.rb +59 -0
- data/spec/flipper/ui/actions/features_spec.rb +37 -0
- data/spec/flipper/ui/actions/file_spec.rb +43 -0
- data/spec/flipper/ui/actions/gate_spec.rb +24 -0
- data/spec/flipper/ui/actions/groups_gate_spec.rb +80 -0
- data/spec/flipper/ui/actions/home_spec.rb +16 -0
- data/spec/flipper/ui/actions/percentage_of_actors_gate_spec.rb +40 -0
- data/spec/flipper/ui/actions/percentage_of_time_gate_spec.rb +39 -0
- data/spec/flipper/ui/decorators/feature_spec.rb +38 -1
- data/spec/flipper/ui/decorators/gate_spec.rb +1 -1
- data/spec/flipper/ui_spec.rb +18 -441
- data/spec/helper.rb +22 -7
- metadata +199 -52
- data/examples/flipper.html +0 -14
- data/examples/flipper.png +0 -0
- data/lib/flipper/ui/assets/javascripts/spine/ajax.coffee +0 -223
- data/lib/flipper/ui/assets/javascripts/spine/list.coffee +0 -43
- data/lib/flipper/ui/assets/javascripts/spine/local.coffee +0 -16
- data/lib/flipper/ui/assets/javascripts/spine/manager.coffee +0 -83
- data/lib/flipper/ui/assets/javascripts/spine/relation.coffee +0 -148
- data/lib/flipper/ui/assets/javascripts/spine/route.coffee +0 -146
- data/lib/flipper/ui/assets/javascripts/spine/spine.coffee +0 -542
- data/lib/flipper/ui/assets/javascripts/spine/version +0 -1
- data/lib/flipper/ui/public/css/images/animated-overlay.gif +0 -0
- data/lib/flipper/ui/public/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
- data/lib/flipper/ui/public/css/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
- data/lib/flipper/ui/public/css/images/ui-bg_flat_10_000000_40x100.png +0 -0
- data/lib/flipper/ui/public/css/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
- data/lib/flipper/ui/public/css/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
- data/lib/flipper/ui/public/css/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/flipper/ui/public/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
- data/lib/flipper/ui/public/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
- data/lib/flipper/ui/public/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
- data/lib/flipper/ui/public/css/images/ui-icons_222222_256x240.png +0 -0
- data/lib/flipper/ui/public/css/images/ui-icons_228ef1_256x240.png +0 -0
- data/lib/flipper/ui/public/css/images/ui-icons_ef8c08_256x240.png +0 -0
- data/lib/flipper/ui/public/css/images/ui-icons_ffd27a_256x240.png +0 -0
- data/lib/flipper/ui/public/css/images/ui-icons_ffffff_256x240.png +0 -0
- data/lib/flipper/ui/public/css/jquery-ui-1.10.3.slider.min.css +0 -5
- data/lib/flipper/ui/public/js/handlebars.js +0 -1992
- data/lib/flipper/ui/public/js/jquery-ui-1.10.3.slider.min.js +0 -6
- data/lib/flipper/ui/public/js/jquery.js +0 -9555
- data/lib/flipper/ui/public/js/jquery.min.js +0 -4
- data/lib/flipper/ui/public/js/jquery.min.map +0 -1
- data/lib/flipper/ui/public/js/spine/ajax.js +0 -320
- data/lib/flipper/ui/public/js/spine/list.js +0 -72
- data/lib/flipper/ui/public/js/spine/local.js +0 -29
- data/lib/flipper/ui/public/js/spine/manager.js +0 -157
- data/lib/flipper/ui/public/js/spine/relation.js +0 -260
- data/lib/flipper/ui/public/js/spine/route.js +0 -223
- data/lib/flipper/ui/public/js/spine/spine.js +0 -927
- 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) {
|
|
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) {
|
|
8
|
+
let(:flipper) { build_flipper }
|
|
9
9
|
let(:feature) { flipper[:some_awesome_feature] }
|
|
10
10
|
let(:gate) { feature.gate(:boolean) }
|
|
11
11
|
|
data/spec/flipper/ui_spec.rb
CHANGED
|
@@ -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(:
|
|
11
|
-
let(:
|
|
9
|
+
let(:flipper) { build_flipper }
|
|
10
|
+
let(:app) { build_app(flipper) }
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
24
|
-
|
|
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
|
-
|
|
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 "
|
|
135
|
-
|
|
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 "
|
|
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 "
|
|
448
|
-
|
|
449
|
-
|
|
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
|
-
|
|
40
|
+
describe "Request method unsupported by action" do
|
|
458
41
|
it "raises error" do
|
|
459
42
|
expect {
|
|
460
|
-
|
|
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
|