detour 0.0.1 → 0.0.2
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 +7 -0
- data/.gitignore +2 -1
- data/.travis.yml +6 -2
- data/Gemfile +5 -0
- data/README.md +41 -132
- data/Rake.md +108 -0
- data/Rakefile +21 -1
- data/app/assets/fonts/glyphicons-halflings-regular.eot +0 -0
- data/app/assets/fonts/glyphicons-halflings-regular.svg +229 -0
- data/app/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/app/assets/fonts/glyphicons-halflings-regular.woff +0 -0
- data/app/assets/images/detour/.gitkeep +0 -0
- data/app/assets/javascripts/detour/application.js +16 -0
- data/app/assets/javascripts/detour/bootstrap.js +2006 -0
- data/app/assets/javascripts/detour/delete_feature.js +13 -0
- data/app/assets/javascripts/detour/delete_flag.js +13 -0
- data/app/assets/javascripts/detour/modals.js +3 -0
- data/app/assets/javascripts/detour/tooltips.js +3 -0
- data/app/assets/stylesheets/detour/application.css +14 -0
- data/app/assets/stylesheets/detour/bootstrap.css +7112 -0
- data/app/assets/stylesheets/detour/main.css +49 -0
- data/app/controllers/detour/application_controller.rb +12 -0
- data/app/controllers/detour/features_controller.rb +19 -0
- data/app/controllers/detour/flaggable_flags_controller.rb +90 -0
- data/app/controllers/detour/flags_controller.rb +18 -0
- data/app/helpers/detour/application_helper.rb +32 -0
- data/app/helpers/detour/flaggable_flags_helper.rb +5 -0
- data/app/helpers/detour/flags_helper.rb +7 -0
- data/app/models/detour/concerns/countable_flag.rb +19 -0
- data/app/models/detour/concerns/flag_actions.rb +141 -0
- data/app/models/detour/concerns/matchers.rb +73 -0
- data/app/models/detour/feature.rb +81 -0
- data/{lib → app/models}/detour/flag.rb +8 -2
- data/app/models/detour/flag_in_flag.rb +12 -0
- data/app/models/detour/group_flag.rb +13 -0
- data/{lib → app/models}/detour/opt_out_flag.rb +4 -2
- data/app/models/detour/percentage_flag.rb +9 -0
- data/app/views/detour/application/index.html.erb +0 -0
- data/app/views/detour/features/_errors.html.erb +11 -0
- data/app/views/detour/features/_success.html.erb +1 -0
- data/app/views/detour/features/error.js.erb +5 -0
- data/app/views/detour/features/success.js.erb +1 -0
- data/app/views/detour/flaggable_flags/_errors.html.erb +11 -0
- data/app/views/detour/flaggable_flags/_flaggable_flag.html.erb +11 -0
- data/app/views/detour/flaggable_flags/error.js.erb +5 -0
- data/app/views/detour/flaggable_flags/index.html.erb +34 -0
- data/app/views/detour/flaggable_flags/success.js.erb +1 -0
- data/app/views/detour/flags/_feature_form.html.erb +38 -0
- data/app/views/detour/flags/index.html.erb +76 -0
- data/app/views/detour/shared/_nav.html.erb +28 -0
- data/app/views/detour/shared/_spacer_cells.html.erb +3 -0
- data/app/views/layouts/detour/application.html.erb +29 -0
- data/config/routes.rb +16 -0
- data/detour.gemspec +15 -14
- data/lib/detour/acts_as_flaggable.rb +42 -3
- data/lib/detour/configuration.rb +35 -0
- data/lib/detour/engine.rb +5 -0
- data/lib/detour/flag_form.rb +87 -0
- data/lib/detour/version.rb +1 -1
- data/lib/detour.rb +10 -14
- data/lib/generators/templates/migration.rb +2 -0
- data/lib/tasks/detour.rake +16 -16
- data/script/rails +8 -0
- data/spec/controllers/detour/application_controller_spec.rb +15 -0
- data/spec/controllers/detour/features_controller_spec.rb +51 -0
- data/spec/controllers/detour/flaggable_flags_controller_spec.rb +100 -0
- data/spec/controllers/detour/flags_controller_spec.rb +77 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +7 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/user.rb +5 -0
- data/spec/dummy/app/models/widget.rb +5 -0
- data/spec/dummy/app/views/application/index.html.erb +22 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config/application.rb +65 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +19 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/detour.rb +36 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20131218015844_create_users.rb +10 -0
- data/spec/dummy/db/migrate/20131218023124_create_widgets.rb +9 -0
- data/spec/dummy/db/migrate/20131218055352_add_user_id_to_widgets.rb +6 -0
- data/spec/dummy/db/migrate/20131221052201_setup_detour.rb +32 -0
- data/spec/dummy/db/schema.rb +59 -0
- data/spec/dummy/db/seeds.rb +10 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/factories/feature.rb +5 -0
- data/spec/factories/flag_in_flag.rb +6 -0
- data/spec/factories/group_flag.rb +7 -0
- data/spec/factories/opt_out_flag.rb +6 -0
- data/spec/factories/percentage_flag.rb +7 -0
- data/spec/factories/user.rb +6 -0
- data/spec/factories/widget.rb +5 -0
- data/spec/features/features_spec.rb +70 -0
- data/spec/features/flag_in_flags_spec.rb +118 -0
- data/spec/features/group_flags_spec.rb +49 -0
- data/spec/features/home_page_spec.rb +11 -0
- data/spec/features/opt_out_flags_spec.rb +105 -0
- data/spec/features/percentage_flags_spec.rb +63 -0
- data/spec/integration/group_rollout_spec.rb +1 -1
- data/spec/lib/detour/acts_as_flaggable_spec.rb +45 -0
- data/spec/lib/detour/configuration_spec.rb +23 -0
- data/spec/lib/detour/flag_form_spec.rb +84 -0
- data/spec/lib/{active_record/rollout → detour}/flaggable_spec.rb +19 -19
- data/spec/lib/tasks/{detour_rake_spec.rb → detour_spec.rb} +54 -54
- data/spec/{lib/active_record/rollout → models/detour}/feature_spec.rb +93 -67
- data/spec/models/detour/flag_in_flag_spec.rb +38 -0
- data/spec/{lib/active_record/rollout → models/detour}/flag_spec.rb +1 -1
- data/spec/models/detour/opt_out_flag_spec.rb +38 -0
- data/spec/{lib/active_record/rollout → models/detour}/percentage_flag_spec.rb +1 -1
- data/spec/spec_helper.rb +41 -21
- data/spec/support/shared_contexts/rake.rb +4 -14
- metadata +278 -95
- data/lib/detour/feature.rb +0 -312
- data/lib/detour/flaggable_flag.rb +0 -10
- data/lib/detour/group_flag.rb +0 -8
- data/lib/detour/percentage_flag.rb +0 -11
- data/spec/lib/active_record/rollout/acts_as_flaggable_spec.rb +0 -31
- data/spec/lib/active_record/rollout/flaggable_flag_spec.rb +0 -9
- data/spec/lib/active_record/rollout/opt_out_flag_spec.rb +0 -9
- data/spec/support/schema.rb +0 -13
- /data/lib/generators/{active_record_rollout_generator.rb → detour_generator.rb} +0 -0
- /data/lib/generators/templates/{active_record_rollout.rb → detour.rb} +0 -0
- /data/spec/{lib/active_record/rollout → models/detour}/group_flag_spec.rb +0 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe "counting flaggable flags" do
|
|
4
|
+
let!(:flag) { create :flag_in_flag }
|
|
5
|
+
|
|
6
|
+
before do
|
|
7
|
+
visit "/detour/flags/users"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "displays the defined groups" do
|
|
11
|
+
within "tr#feature_#{flag.feature.id} td.flag-in-count" do
|
|
12
|
+
page.should have_content 1
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe "listing flag_in_flags" do
|
|
18
|
+
let!(:flag) { create :flag_in_flag }
|
|
19
|
+
|
|
20
|
+
before do
|
|
21
|
+
User.instance_variable_set "@detour_flaggable_find_by", :email
|
|
22
|
+
visit "/detour/flag-ins/#{flag.feature.name}/users"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "displays the flagged-in model's find-by" do
|
|
26
|
+
page.should have_content flag.flaggable.email
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe "creating flag-ins", js: true do
|
|
31
|
+
let(:user) { create :user }
|
|
32
|
+
let!(:feature) { create :feature }
|
|
33
|
+
|
|
34
|
+
before do
|
|
35
|
+
User.instance_variable_set "@detour_flaggable_find_by", :email
|
|
36
|
+
visit "/detour/flag-ins/#{feature.name}/users"
|
|
37
|
+
page.find("[data-target='#create-flaggable-flag']").click
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context "when creating multiple flag-ins" do
|
|
41
|
+
let(:user2) { create :user, email: "another_user@example.com" }
|
|
42
|
+
|
|
43
|
+
context "when successful" do
|
|
44
|
+
before do
|
|
45
|
+
fill_in "ids", with: [user.email, user2.email].join(",")
|
|
46
|
+
click_button "Create Flag-in"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "displays a success message" do
|
|
50
|
+
page.should have_content "Users #{user.email}, #{user2.email} have been flagged in to #{feature.name}"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context "when unsuccessful" do
|
|
55
|
+
before do
|
|
56
|
+
fill_in "ids", with: "#{user.email},foo"
|
|
57
|
+
click_button "Create Flag-in"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "displays error messages" do
|
|
61
|
+
page.should have_content "Couldn't find User with email = foo"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
context "when creating single flag-ins" do
|
|
67
|
+
context "when successful" do
|
|
68
|
+
before do
|
|
69
|
+
fill_in "ids", with: user.email
|
|
70
|
+
click_button "Create Flag-in"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "displays a success message" do
|
|
74
|
+
page.should have_content "User #{user.email} has been flagged in to #{feature.name}"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "renders the new flag-in" do
|
|
78
|
+
within "table" do
|
|
79
|
+
page.should have_content user.email
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
context "when unsuccessful" do
|
|
85
|
+
before do
|
|
86
|
+
fill_in "ids", with: "foo"
|
|
87
|
+
click_button "Create Flag-in"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "displays error messages" do
|
|
91
|
+
page.should have_content "Couldn't find User with email = foo"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe "destroying flag-ins", js: true do
|
|
98
|
+
let!(:flag) { create :flag_in_flag }
|
|
99
|
+
|
|
100
|
+
before do
|
|
101
|
+
visit "/detour/flag-ins/#{flag.feature.name}/users"
|
|
102
|
+
page.find(".delete-flag").click
|
|
103
|
+
click_link "Delete Flag-in"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "displays a flash message" do
|
|
107
|
+
page.should have_content "#{flag.feature.name} flag-in for User #{flag.flaggable.send flag.flaggable_type.constantize.detour_flaggable_find_by} has been deleted."
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "destroys the flag-in" do
|
|
111
|
+
expect { flag.reload }.to raise_error ActiveRecord::RecordNotFound
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
it "removes the flag from the list" do
|
|
116
|
+
page.should_not have_content flag.flaggable.email
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe "listing defined groups" do
|
|
4
|
+
before do
|
|
5
|
+
Detour.config.define_user_group :admins do |user|
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
visit "/detour/flags/users"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "displays the defined groups" do
|
|
12
|
+
page.should have_content "admins"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe "creating defined group flags" do
|
|
17
|
+
let!(:feature) { create :feature }
|
|
18
|
+
|
|
19
|
+
before do
|
|
20
|
+
Detour.config.define_user_group :admins do |user|
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
visit "/detour/flags/users"
|
|
24
|
+
check "features[#{feature.name}][users_group_flags_attributes[admins]][to_keep]"
|
|
25
|
+
click_button "Save Changes"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "creates the group flag" do
|
|
29
|
+
feature.reload.users_group_flags.first.group_name.should eq "admins"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "removing defined group flags" do
|
|
34
|
+
let(:feature) { create :feature }
|
|
35
|
+
let!(:group_flag) { create :group_flag, feature: feature, group_name: "admins" }
|
|
36
|
+
|
|
37
|
+
before do
|
|
38
|
+
Detour.config.define_user_group :admins do |user|
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
visit "/detour/flags/users"
|
|
42
|
+
uncheck "features[#{feature.name}][users_group_flags_attributes[admins]][to_keep]"
|
|
43
|
+
click_button "Save Changes"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "creates the group flag" do
|
|
47
|
+
feature.reload.users_group_flags.should be_empty
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe "counting opt out flags" do
|
|
4
|
+
let!(:flag) { create :opt_out_flag }
|
|
5
|
+
|
|
6
|
+
before do
|
|
7
|
+
visit "/detour/flags/users"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "displays the defined groups" do
|
|
11
|
+
within "tr#feature_#{flag.feature.id} td.opt-out-count" do
|
|
12
|
+
page.should have_content 1
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe "creating opt-outs", js: true do
|
|
18
|
+
let(:user) { create :user }
|
|
19
|
+
let!(:feature) { create :feature }
|
|
20
|
+
|
|
21
|
+
before do
|
|
22
|
+
User.instance_variable_set "@detour_flaggable_find_by", :email
|
|
23
|
+
visit "/detour/opt-outs/#{feature.name}/users"
|
|
24
|
+
page.find("[data-target='#create-flaggable-flag']").click
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
context "when creating multiple opt-outs" do
|
|
28
|
+
let(:user2) { create :user, email: "another_user@example.com" }
|
|
29
|
+
|
|
30
|
+
context "when successful" do
|
|
31
|
+
before do
|
|
32
|
+
fill_in "ids", with: [user.email, user2.email].join(",")
|
|
33
|
+
click_button "Create Opt-out"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "displays a success message" do
|
|
37
|
+
page.should have_content "Users #{user.email}, #{user2.email} have been opted out of #{feature.name}"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context "when unsuccessful" do
|
|
42
|
+
before do
|
|
43
|
+
fill_in "ids", with: "#{user.email},foo"
|
|
44
|
+
click_button "Create Opt-out"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "displays error messages" do
|
|
48
|
+
page.should have_content "Couldn't find User with email = foo"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
context "when creating single opt-outs" do
|
|
54
|
+
context "when successful" do
|
|
55
|
+
before do
|
|
56
|
+
fill_in "ids", with: user.email
|
|
57
|
+
click_button "Create Opt-out"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "displays a success message" do
|
|
61
|
+
page.should have_content "User #{user.email} has been opted out of #{feature.name}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "renders the new opt-out" do
|
|
65
|
+
within "table" do
|
|
66
|
+
page.should have_content user.email
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
context "when unsuccessful" do
|
|
72
|
+
before do
|
|
73
|
+
fill_in "ids", with: "foo"
|
|
74
|
+
click_button "Create Opt-out"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "displays error messages" do
|
|
78
|
+
page.should have_content "Couldn't find User with email = foo"
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
describe "destroying opt-outs", js: true do
|
|
85
|
+
let!(:flag) { create :opt_out_flag }
|
|
86
|
+
|
|
87
|
+
before do
|
|
88
|
+
visit "/detour/opt-outs/#{flag.feature.name}/users"
|
|
89
|
+
page.find(".delete-flag").click
|
|
90
|
+
click_link "Delete Opt-out"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "displays a flash message" do
|
|
94
|
+
page.should have_content "#{flag.feature.name} opt-out for User #{flag.flaggable.send flag.flaggable_type.constantize.detour_flaggable_find_by} has been deleted."
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "destroys the opt-out" do
|
|
98
|
+
expect { flag.reload }.to raise_error ActiveRecord::RecordNotFound
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
it "removes the flag from the list" do
|
|
103
|
+
page.should_not have_content flag.flaggable.email
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe "listing percentage flags for a type" do
|
|
4
|
+
let(:feature) { create :feature }
|
|
5
|
+
let!(:percentage_flag) { create :percentage_flag, feature: feature }
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
visit "/detour/flags/users"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "displays the percentage flag for the feature" do
|
|
12
|
+
page.find("#features_#{feature.name}_users_percentage_flag_attributes_percentage").value.to_i.should eq percentage_flag.percentage
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe "creating a percentage flag" do
|
|
17
|
+
let!(:feature) { create :feature }
|
|
18
|
+
|
|
19
|
+
before do
|
|
20
|
+
visit "/detour/flags/users"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
context "when successful" do
|
|
24
|
+
before do
|
|
25
|
+
fill_in "features[#{feature.name}][users_percentage_flag_attributes][percentage]", with: "50"
|
|
26
|
+
click_button "Save Changes"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "saves the new feature" do
|
|
30
|
+
feature.users_percentage_flag.percentage.should eq 50
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "displays a success message" do
|
|
34
|
+
page.should have_content "Your flags have been successfully updated."
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context "when unsuccessful" do
|
|
39
|
+
before do
|
|
40
|
+
fill_in "features[#{feature.name}][users_percentage_flag_attributes][percentage]", with: "foo"
|
|
41
|
+
click_button "Save Changes"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "displays error messages" do
|
|
45
|
+
page.should have_content "#{feature.name}: Users percentage flag percentage is not a number"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe "destroying a percentage flag" do
|
|
51
|
+
let(:feature) { create :feature }
|
|
52
|
+
let!(:percentage_flag) { create :percentage_flag, feature: feature }
|
|
53
|
+
|
|
54
|
+
before do
|
|
55
|
+
visit "/detour/flags/users"
|
|
56
|
+
fill_in "features[#{feature.name}][users_percentage_flag_attributes][percentage]", with: ""
|
|
57
|
+
click_button "Save Changes"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "destroys the percentage flag" do
|
|
61
|
+
feature.users_percentage_flag.should be_nil
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe Detour::ActsAsFlaggable do
|
|
4
|
+
subject { User.new }
|
|
5
|
+
|
|
6
|
+
it { should have_many :flag_in_flags }
|
|
7
|
+
it { should have_many :opt_out_flags }
|
|
8
|
+
it { should have_many(:features).through(:flag_in_flags) }
|
|
9
|
+
|
|
10
|
+
it "includes Detour::Flaggable" do
|
|
11
|
+
subject.class.ancestors.should include Detour::Flaggable
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe "#acts_as_flaggable" do
|
|
15
|
+
describe "Detour::Feature associations" do
|
|
16
|
+
subject { Detour::Feature.new }
|
|
17
|
+
it { should have_many(:users_group_flags).class_name("Detour::GroupFlag").dependent(:destroy) }
|
|
18
|
+
it { should allow_mass_assignment_of(:users_group_flags_attributes) }
|
|
19
|
+
it { should accept_nested_attributes_for(:users_group_flags) }
|
|
20
|
+
|
|
21
|
+
it { should have_one(:users_percentage_flag).class_name("Detour::PercentageFlag").dependent(:destroy) }
|
|
22
|
+
it { should allow_mass_assignment_of(:users_percentage_flag_attributes) }
|
|
23
|
+
it { should accept_nested_attributes_for(:users_percentage_flag) }
|
|
24
|
+
|
|
25
|
+
it { should have_many(:users_flag_ins).class_name("Detour::FlagInFlag").dependent(:destroy) }
|
|
26
|
+
it { should have_many(:users_opt_outs).class_name("Detour::OptOutFlag").dependent(:destroy) }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context "when given a :find_by parameter" do
|
|
30
|
+
class Foo < ActiveRecord::Base
|
|
31
|
+
acts_as_flaggable find_by: :email
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "sets the appropriate class variable on the class" do
|
|
35
|
+
Foo.instance_variable_get("@detour_flaggable_find_by").should eq :email
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context "when not given a :find_by parameter" do
|
|
40
|
+
it "uses the default :id value for flaggable_find_by" do
|
|
41
|
+
User.instance_variable_get("@detour_flaggable_find_by").should eq :id
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe Detour::Configuration do
|
|
4
|
+
describe ".define_group_for_class" do
|
|
5
|
+
let(:block) { Proc.new {} }
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
subject.send :define_group_for_class, "User", "user_id_1", &block
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "defines a group for the given class" do
|
|
12
|
+
subject.defined_groups["User"].should eq({ "user_id_1" => block })
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe ".define_{klass}_group" do
|
|
17
|
+
let(:block) { Proc.new {} }
|
|
18
|
+
it "defines a group for the given class" do
|
|
19
|
+
subject.should_receive(:define_group_for_class).with("User", :id_is_1)
|
|
20
|
+
subject.define_user_group :id_is_1, block
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe Detour::FlagForm do
|
|
4
|
+
subject { Detour::FlagForm.new("users") }
|
|
5
|
+
|
|
6
|
+
let!(:feature) { create :feature, name: "foo_feature" }
|
|
7
|
+
|
|
8
|
+
describe "#features" do
|
|
9
|
+
before do
|
|
10
|
+
Detour.config.grep_dirs = ["spec/dummy/app/**/*.{rb,erb}"]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "returns every feature including lines" do
|
|
14
|
+
subject.features.collect(&:name).should eq Detour::Feature.with_lines.collect(&:name)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "#group_names" do
|
|
19
|
+
before do
|
|
20
|
+
Detour.config.define_user_group :admins do |user|
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "returns the name of defined groups" do
|
|
25
|
+
subject.group_names.should eq ["admins"]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe "#update_attributes" do
|
|
30
|
+
let(:features_params) do
|
|
31
|
+
{
|
|
32
|
+
"foo_feature" => { users_percentage_flag_attributes: {} }
|
|
33
|
+
}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "updates the feature attributes" do
|
|
37
|
+
Detour::Feature.any_instance.should_receive :assign_attributes
|
|
38
|
+
Detour::Feature.any_instance.stub(:changed_for_autosave?) { true }
|
|
39
|
+
Detour::Feature.any_instance.should_receive :save
|
|
40
|
+
subject.update_attributes({ features: features_params })
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context "when successful" do
|
|
44
|
+
it "returns true" do
|
|
45
|
+
subject.update_attributes({ features: features_params }).should be_true
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context "when unsuccessful" do
|
|
50
|
+
it "returns nil" do
|
|
51
|
+
subject.update_attributes({ features: { "foo_feature" => { users_percentage_flag_attributes: { percentage: "foo" } } } }).should be_nil
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "uses a transaction" do
|
|
55
|
+
feature2 = create :feature, name: "foo_feature_2"
|
|
56
|
+
|
|
57
|
+
subject.update_attributes({ features: {
|
|
58
|
+
"foo_feature_2" => { users_percentage_flag_attributes: { percentage: 10 } },
|
|
59
|
+
"foo_feature" => { users_percentage_flag_attributes: { percentage: "foo" } }
|
|
60
|
+
} })
|
|
61
|
+
|
|
62
|
+
feature2.users_percentage_flag.should be_nil
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
context "when a percentage flag should be removed" do
|
|
67
|
+
let!(:percentage_flag) { create :percentage_flag, feature: feature }
|
|
68
|
+
|
|
69
|
+
let(:features_params) do
|
|
70
|
+
{
|
|
71
|
+
"foo_feature" => { users_percentage_flag_attributes: { percentage: "" } },
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
before do
|
|
76
|
+
subject.update_attributes({ features: features_params });
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "destroys the percentage flag" do
|
|
80
|
+
feature.reload.users_percentage_flag.should be_nil
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -24,29 +24,29 @@ describe Detour::Flaggable do
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
describe "#has_feature?" do
|
|
27
|
-
let(:user)
|
|
28
|
-
let(:feature) {
|
|
27
|
+
let(:user) { create :user }
|
|
28
|
+
let(:feature) { create :feature }
|
|
29
29
|
|
|
30
30
|
it "memoizes found features" do
|
|
31
31
|
Detour::Feature.stub(:find_by_name) { feature }
|
|
32
|
-
feature.
|
|
32
|
+
feature.flag_in_flags.create(flaggable: user)
|
|
33
33
|
|
|
34
34
|
feature.should_receive(:match?).with(user).and_return(true)
|
|
35
|
-
user.has_feature?(
|
|
35
|
+
user.has_feature?(feature.name)
|
|
36
36
|
|
|
37
37
|
feature.should_not_receive(:match?).with(user)
|
|
38
|
-
user.has_feature?(
|
|
38
|
+
user.has_feature?(feature.name)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
context "when given a block" do
|
|
42
42
|
context "and the user is flagged in" do
|
|
43
43
|
before do
|
|
44
|
-
feature.
|
|
44
|
+
feature.flag_in_flags.create(flaggable: user)
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
it "calls the block" do
|
|
48
48
|
foo = "foo"
|
|
49
|
-
user.has_feature?(
|
|
49
|
+
user.has_feature?(feature.name) { foo = "bar" }
|
|
50
50
|
foo.should eq "bar"
|
|
51
51
|
end
|
|
52
52
|
|
|
@@ -64,7 +64,7 @@ describe Detour::Flaggable do
|
|
|
64
64
|
context "when the block raises an exception" do
|
|
65
65
|
it "increments the failure_count of the feature" do
|
|
66
66
|
begin
|
|
67
|
-
user.has_feature?
|
|
67
|
+
user.has_feature? feature.name do
|
|
68
68
|
raise "This is an exception"
|
|
69
69
|
end
|
|
70
70
|
rescue
|
|
@@ -74,7 +74,7 @@ describe Detour::Flaggable do
|
|
|
74
74
|
|
|
75
75
|
it "raises the exception" do
|
|
76
76
|
expect do
|
|
77
|
-
user.has_feature?
|
|
77
|
+
user.has_feature? feature.name do
|
|
78
78
|
raise "This is an exception"
|
|
79
79
|
end
|
|
80
80
|
end.to raise_error "This is an exception"
|
|
@@ -85,7 +85,7 @@ describe Detour::Flaggable do
|
|
|
85
85
|
context "and the user is not flagged in" do
|
|
86
86
|
it "does not call the block" do
|
|
87
87
|
foo = "foo"
|
|
88
|
-
user.has_feature?(
|
|
88
|
+
user.has_feature?(feature.name) { foo = "bar" }
|
|
89
89
|
foo.should eq "foo"
|
|
90
90
|
end
|
|
91
91
|
end
|
|
@@ -93,30 +93,30 @@ describe Detour::Flaggable do
|
|
|
93
93
|
|
|
94
94
|
context "when the user is not flagged in" do
|
|
95
95
|
it "returns false" do
|
|
96
|
-
user.has_feature?(
|
|
96
|
+
user.has_feature?(feature.name).should be_false
|
|
97
97
|
end
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
context "when the user is flagged in" do
|
|
101
101
|
context "and the user is opted out" do
|
|
102
102
|
before do
|
|
103
|
-
feature.
|
|
103
|
+
feature.flag_in_flags.create(flaggable: user)
|
|
104
104
|
feature.opt_out_flags.create(flaggable: user)
|
|
105
105
|
end
|
|
106
106
|
|
|
107
107
|
it "returns false" do
|
|
108
|
-
user.has_feature?(
|
|
108
|
+
user.has_feature?(feature.name).should be_false
|
|
109
109
|
end
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
context "and the user is not opted out" do
|
|
113
113
|
context "and the user is flagged in individually" do
|
|
114
114
|
before do
|
|
115
|
-
feature.
|
|
115
|
+
feature.flag_in_flags.create(flaggable: user)
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
it "returns true" do
|
|
119
|
-
user.has_feature?(
|
|
119
|
+
user.has_feature?(feature.name).should be_true
|
|
120
120
|
end
|
|
121
121
|
end
|
|
122
122
|
|
|
@@ -126,21 +126,21 @@ describe Detour::Flaggable do
|
|
|
126
126
|
end
|
|
127
127
|
|
|
128
128
|
it "returns true" do
|
|
129
|
-
user.has_feature?(
|
|
129
|
+
user.has_feature?(feature.name).should be_true
|
|
130
130
|
end
|
|
131
131
|
end
|
|
132
132
|
|
|
133
133
|
context "and the user is flagged in via a group" do
|
|
134
134
|
before do
|
|
135
|
-
Detour
|
|
136
|
-
|
|
135
|
+
Detour.config.define_user_group "name_foo" do |_user|
|
|
136
|
+
_user.name == user.name
|
|
137
137
|
end
|
|
138
138
|
|
|
139
139
|
feature.group_flags.create(flaggable_type: "User", group_name: "name_foo")
|
|
140
140
|
end
|
|
141
141
|
|
|
142
142
|
it "returns true" do
|
|
143
|
-
user.has_feature?(
|
|
143
|
+
user.has_feature?(feature.name).should be_true
|
|
144
144
|
end
|
|
145
145
|
end
|
|
146
146
|
end
|