split 4.0.1 → 4.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +8 -3
- data/.rubocop.yml +2 -5
- data/CHANGELOG.md +38 -0
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +1 -1
- data/README.md +11 -3
- data/Rakefile +4 -5
- data/gemfiles/5.2.gemfile +1 -3
- data/gemfiles/6.0.gemfile +1 -3
- data/gemfiles/6.1.gemfile +1 -3
- data/gemfiles/7.0.gemfile +1 -3
- data/lib/split/algorithms/block_randomization.rb +5 -6
- data/lib/split/algorithms/whiplash.rb +16 -18
- data/lib/split/algorithms.rb +14 -0
- data/lib/split/alternative.rb +21 -22
- data/lib/split/cache.rb +0 -1
- data/lib/split/combined_experiments_helper.rb +4 -4
- data/lib/split/configuration.rb +83 -84
- data/lib/split/dashboard/helpers.rb +6 -7
- data/lib/split/dashboard/pagination_helpers.rb +53 -54
- data/lib/split/dashboard/public/style.css +5 -2
- data/lib/split/dashboard/views/_experiment.erb +2 -1
- data/lib/split/dashboard/views/index.erb +19 -4
- data/lib/split/dashboard.rb +29 -23
- data/lib/split/encapsulated_helper.rb +4 -6
- data/lib/split/experiment.rb +93 -88
- data/lib/split/experiment_catalog.rb +6 -5
- data/lib/split/extensions/string.rb +1 -1
- data/lib/split/goals_collection.rb +8 -10
- data/lib/split/helper.rb +20 -20
- data/lib/split/metric.rb +4 -5
- data/lib/split/persistence/cookie_adapter.rb +44 -47
- data/lib/split/persistence/dual_adapter.rb +7 -8
- data/lib/split/persistence/redis_adapter.rb +3 -4
- data/lib/split/persistence/session_adapter.rb +0 -2
- data/lib/split/persistence.rb +4 -4
- data/lib/split/redis_interface.rb +7 -1
- data/lib/split/trial.rb +23 -24
- data/lib/split/user.rb +12 -13
- data/lib/split/version.rb +1 -1
- data/lib/split/zscore.rb +1 -3
- data/lib/split.rb +26 -25
- data/spec/algorithms/block_randomization_spec.rb +6 -5
- data/spec/algorithms/weighted_sample_spec.rb +6 -5
- data/spec/algorithms/whiplash_spec.rb +4 -5
- data/spec/alternative_spec.rb +35 -36
- data/spec/cache_spec.rb +15 -19
- data/spec/combined_experiments_helper_spec.rb +18 -17
- data/spec/configuration_spec.rb +32 -38
- data/spec/dashboard/pagination_helpers_spec.rb +69 -67
- data/spec/dashboard/paginator_spec.rb +10 -9
- data/spec/dashboard_helpers_spec.rb +19 -18
- data/spec/dashboard_spec.rb +79 -35
- data/spec/encapsulated_helper_spec.rb +12 -14
- data/spec/experiment_catalog_spec.rb +14 -13
- data/spec/experiment_spec.rb +132 -123
- data/spec/goals_collection_spec.rb +17 -15
- data/spec/helper_spec.rb +415 -382
- data/spec/metric_spec.rb +14 -14
- data/spec/persistence/cookie_adapter_spec.rb +23 -8
- data/spec/persistence/dual_adapter_spec.rb +71 -71
- data/spec/persistence/redis_adapter_spec.rb +28 -29
- data/spec/persistence/session_adapter_spec.rb +2 -3
- data/spec/persistence_spec.rb +1 -2
- data/spec/redis_interface_spec.rb +26 -14
- data/spec/spec_helper.rb +16 -13
- data/spec/split_spec.rb +11 -11
- data/spec/support/cookies_mock.rb +1 -2
- data/spec/trial_spec.rb +61 -60
- data/spec/user_spec.rb +36 -36
- data/split.gemspec +21 -20
- metadata +25 -14
- data/.rubocop_todo.yml +0 -226
- data/Appraisals +0 -19
- data/gemfiles/5.0.gemfile +0 -9
- data/gemfiles/5.1.gemfile +0 -9
data/spec/helper_spec.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require "spec_helper"
|
3
4
|
|
4
5
|
# TODO change some of these tests to use Rack::Test
|
5
6
|
|
@@ -7,156 +8,156 @@ describe Split::Helper do
|
|
7
8
|
include Split::Helper
|
8
9
|
|
9
10
|
let(:experiment) {
|
10
|
-
Split::ExperimentCatalog.find_or_create(
|
11
|
+
Split::ExperimentCatalog.find_or_create("link_color", "blue", "red")
|
11
12
|
}
|
12
13
|
|
13
14
|
describe "ab_test" do
|
14
15
|
it "should not raise an error when passed strings for alternatives" do
|
15
|
-
expect
|
16
|
+
expect { ab_test("xyz", "1", "2", "3") }.not_to raise_error
|
16
17
|
end
|
17
18
|
|
18
19
|
it "should not raise an error when passed an array for alternatives" do
|
19
|
-
expect
|
20
|
+
expect { ab_test("xyz", ["1", "2", "3"]) }.not_to raise_error
|
20
21
|
end
|
21
22
|
|
22
23
|
it "should raise the appropriate error when passed integers for alternatives" do
|
23
|
-
expect
|
24
|
+
expect { ab_test("xyz", 1, 2, 3) }.to raise_error(ArgumentError)
|
24
25
|
end
|
25
26
|
|
26
27
|
it "should raise the appropriate error when passed symbols for alternatives" do
|
27
|
-
expect
|
28
|
+
expect { ab_test("xyz", :a, :b, :c) }.to raise_error(ArgumentError)
|
28
29
|
end
|
29
30
|
|
30
31
|
it "should not raise error when passed an array for goals" do
|
31
|
-
expect
|
32
|
+
expect { ab_test({ "link_color" => ["purchase", "refund"] }, "blue", "red") }.not_to raise_error
|
32
33
|
end
|
33
34
|
|
34
35
|
it "should not raise error when passed just one goal" do
|
35
|
-
expect
|
36
|
+
expect { ab_test({ "link_color" => "purchase" }, "blue", "red") }.not_to raise_error
|
36
37
|
end
|
37
38
|
|
38
39
|
it "raises an appropriate error when processing combined expirements" do
|
39
40
|
Split.configuration.experiments = {
|
40
|
-
:
|
41
|
-
:
|
42
|
-
:
|
43
|
-
:
|
41
|
+
combined_exp_1: {
|
42
|
+
alternatives: [ { name: "control", percent: 50 }, { name: "test-alt", percent: 50 } ],
|
43
|
+
metric: :my_metric,
|
44
|
+
combined_experiments: [:combined_exp_1_sub_1]
|
44
45
|
}
|
45
46
|
}
|
46
|
-
Split::ExperimentCatalog.find_or_create(
|
47
|
-
expect
|
47
|
+
Split::ExperimentCatalog.find_or_create("combined_exp_1")
|
48
|
+
expect { ab_test("combined_exp_1") }.to raise_error(Split::InvalidExperimentsFormatError)
|
48
49
|
end
|
49
50
|
|
50
51
|
it "should assign a random alternative to a new user when there are an equal number of alternatives assigned" do
|
51
|
-
ab_test(
|
52
|
-
expect([
|
52
|
+
ab_test("link_color", "blue", "red")
|
53
|
+
expect(["red", "blue"]).to include(ab_user["link_color"])
|
53
54
|
end
|
54
55
|
|
55
56
|
it "should increment the participation counter after assignment to a new user" do
|
56
|
-
previous_red_count = Split::Alternative.new(
|
57
|
-
previous_blue_count = Split::Alternative.new(
|
57
|
+
previous_red_count = Split::Alternative.new("red", "link_color").participant_count
|
58
|
+
previous_blue_count = Split::Alternative.new("blue", "link_color").participant_count
|
58
59
|
|
59
|
-
ab_test(
|
60
|
+
ab_test("link_color", "blue", "red")
|
60
61
|
|
61
|
-
new_red_count = Split::Alternative.new(
|
62
|
-
new_blue_count = Split::Alternative.new(
|
62
|
+
new_red_count = Split::Alternative.new("red", "link_color").participant_count
|
63
|
+
new_blue_count = Split::Alternative.new("blue", "link_color").participant_count
|
63
64
|
|
64
65
|
expect((new_red_count + new_blue_count)).to eq(previous_red_count + previous_blue_count + 1)
|
65
66
|
end
|
66
67
|
|
67
|
-
it
|
68
|
-
ab_test(
|
69
|
-
e = Split::ExperimentCatalog.find_or_create(
|
70
|
-
expect
|
68
|
+
it "should not increment the counter for an experiment that the user is not participating in" do
|
69
|
+
ab_test("link_color", "blue", "red")
|
70
|
+
e = Split::ExperimentCatalog.find_or_create("button_size", "small", "big")
|
71
|
+
expect {
|
71
72
|
# User shouldn't participate in this second experiment
|
72
|
-
ab_test(
|
73
|
-
}
|
73
|
+
ab_test("button_size", "small", "big")
|
74
|
+
}.not_to change { e.participant_count }
|
74
75
|
end
|
75
76
|
|
76
|
-
it
|
77
|
-
e = Split::ExperimentCatalog.find_or_create(
|
78
|
-
e.winner =
|
79
|
-
expect
|
80
|
-
a = ab_test(
|
81
|
-
expect(a).to eq(
|
82
|
-
}
|
77
|
+
it "should not increment the counter for an ended experiment" do
|
78
|
+
e = Split::ExperimentCatalog.find_or_create("button_size", "small", "big")
|
79
|
+
e.winner = "small"
|
80
|
+
expect {
|
81
|
+
a = ab_test("button_size", "small", "big")
|
82
|
+
expect(a).to eq("small")
|
83
|
+
}.not_to change { e.participant_count }
|
83
84
|
end
|
84
85
|
|
85
|
-
it
|
86
|
+
it "should not increment the counter for an not started experiment" do
|
86
87
|
expect(Split.configuration).to receive(:start_manually).and_return(true)
|
87
|
-
e = Split::ExperimentCatalog.find_or_create(
|
88
|
-
expect
|
89
|
-
a = ab_test(
|
90
|
-
expect(a).to eq(
|
91
|
-
}
|
88
|
+
e = Split::ExperimentCatalog.find_or_create("button_size", "small", "big")
|
89
|
+
expect {
|
90
|
+
a = ab_test("button_size", "small", "big")
|
91
|
+
expect(a).to eq("small")
|
92
|
+
}.not_to change { e.participant_count }
|
92
93
|
end
|
93
94
|
|
94
95
|
it "should return the given alternative for an existing user" do
|
95
|
-
expect(ab_test(
|
96
|
+
expect(ab_test("link_color", "blue", "red")).to eq ab_test("link_color", "blue", "red")
|
96
97
|
end
|
97
98
|
|
98
|
-
it
|
99
|
+
it "should always return the winner if one is present" do
|
99
100
|
experiment.winner = "orange"
|
100
101
|
|
101
|
-
expect(ab_test(
|
102
|
+
expect(ab_test("link_color", "blue", "red")).to eq("orange")
|
102
103
|
end
|
103
104
|
|
104
105
|
it "should allow the alternative to be forced by passing it in the params" do
|
105
106
|
# ?ab_test[link_color]=blue
|
106
|
-
@params = {
|
107
|
+
@params = { "ab_test" => { "link_color" => "blue" } }
|
107
108
|
|
108
|
-
alternative = ab_test(
|
109
|
-
expect(alternative).to eq(
|
109
|
+
alternative = ab_test("link_color", "blue", "red")
|
110
|
+
expect(alternative).to eq("blue")
|
110
111
|
|
111
|
-
alternative = ab_test(
|
112
|
-
expect(alternative).to eq(
|
112
|
+
alternative = ab_test("link_color", { "blue" => 1 }, "red" => 5)
|
113
|
+
expect(alternative).to eq("blue")
|
113
114
|
|
114
|
-
@params = {
|
115
|
+
@params = { "ab_test" => { "link_color" => "red" } }
|
115
116
|
|
116
|
-
alternative = ab_test(
|
117
|
-
expect(alternative).to eq(
|
117
|
+
alternative = ab_test("link_color", "blue", "red")
|
118
|
+
expect(alternative).to eq("red")
|
118
119
|
|
119
|
-
alternative = ab_test(
|
120
|
-
expect(alternative).to eq(
|
120
|
+
alternative = ab_test("link_color", { "blue" => 5 }, "red" => 1)
|
121
|
+
expect(alternative).to eq("red")
|
121
122
|
end
|
122
123
|
|
123
124
|
it "should not allow an arbitrary alternative" do
|
124
|
-
@params = {
|
125
|
-
alternative = ab_test(
|
126
|
-
expect(alternative).to eq(
|
125
|
+
@params = { "ab_test" => { "link_color" => "pink" } }
|
126
|
+
alternative = ab_test("link_color", "blue")
|
127
|
+
expect(alternative).to eq("blue")
|
127
128
|
end
|
128
129
|
|
129
130
|
it "should not store the split when a param forced alternative" do
|
130
|
-
@params = {
|
131
|
+
@params = { "ab_test" => { "link_color" => "blue" } }
|
131
132
|
expect(ab_user).not_to receive(:[]=)
|
132
|
-
ab_test(
|
133
|
+
ab_test("link_color", "blue", "red")
|
133
134
|
end
|
134
135
|
|
135
136
|
it "SPLIT_DISABLE query parameter should also force the alternative (uses control)" do
|
136
|
-
@params = {
|
137
|
-
alternative = ab_test(
|
138
|
-
expect(alternative).to eq(
|
139
|
-
alternative = ab_test(
|
140
|
-
expect(alternative).to eq(
|
141
|
-
alternative = ab_test(
|
142
|
-
expect(alternative).to eq(
|
143
|
-
alternative = ab_test(
|
144
|
-
expect(alternative).to eq(
|
137
|
+
@params = { "SPLIT_DISABLE" => "true" }
|
138
|
+
alternative = ab_test("link_color", "blue", "red")
|
139
|
+
expect(alternative).to eq("blue")
|
140
|
+
alternative = ab_test("link_color", { "blue" => 1 }, "red" => 5)
|
141
|
+
expect(alternative).to eq("blue")
|
142
|
+
alternative = ab_test("link_color", "red", "blue")
|
143
|
+
expect(alternative).to eq("red")
|
144
|
+
alternative = ab_test("link_color", { "red" => 5 }, "blue" => 1)
|
145
|
+
expect(alternative).to eq("red")
|
145
146
|
end
|
146
147
|
|
147
148
|
it "should not store the split when Split generically disabled" do
|
148
|
-
@params = {
|
149
|
+
@params = { "SPLIT_DISABLE" => "true" }
|
149
150
|
expect(ab_user).not_to receive(:[]=)
|
150
|
-
ab_test(
|
151
|
+
ab_test("link_color", "blue", "red")
|
151
152
|
end
|
152
153
|
|
153
154
|
context "when store_override is set" do
|
154
155
|
before { Split.configuration.store_override = true }
|
155
156
|
|
156
157
|
it "should store the forced alternative" do
|
157
|
-
@params = {
|
158
|
-
expect(ab_user).to receive(:[]=).with(
|
159
|
-
ab_test(
|
158
|
+
@params = { "ab_test" => { "link_color" => "blue" } }
|
159
|
+
expect(ab_user).to receive(:[]=).with("link_color", "blue")
|
160
|
+
ab_test("link_color", "blue", "red")
|
160
161
|
end
|
161
162
|
end
|
162
163
|
|
@@ -164,35 +165,35 @@ describe Split::Helper do
|
|
164
165
|
before { Split.configuration.on_trial_choose = :some_method }
|
165
166
|
it "should call the method" do
|
166
167
|
expect(self).to receive(:some_method)
|
167
|
-
ab_test(
|
168
|
+
ab_test("link_color", "blue", "red")
|
168
169
|
end
|
169
170
|
end
|
170
171
|
|
171
172
|
it "should allow passing a block" do
|
172
|
-
alt = ab_test(
|
173
|
-
ret = ab_test(
|
173
|
+
alt = ab_test("link_color", "blue", "red")
|
174
|
+
ret = ab_test("link_color", "blue", "red") { |alternative| "shared/#{alternative}" }
|
174
175
|
expect(ret).to eq("shared/#{alt}")
|
175
176
|
end
|
176
177
|
|
177
178
|
it "should allow the share of visitors see an alternative to be specified" do
|
178
|
-
ab_test(
|
179
|
-
expect([
|
179
|
+
ab_test("link_color", { "blue" => 0.8 }, { "red" => 20 })
|
180
|
+
expect(["red", "blue"]).to include(ab_user["link_color"])
|
180
181
|
end
|
181
182
|
|
182
183
|
it "should allow alternative weighting interface as a single hash" do
|
183
|
-
ab_test(
|
184
|
-
experiment = Split::ExperimentCatalog.find(
|
185
|
-
expect(experiment.alternatives.map(&:name)).to eq([
|
186
|
-
expect(experiment.alternatives.collect{|a| a.weight}).to match_array([0.01, 0.2])
|
184
|
+
ab_test("link_color", { "blue" => 0.01 }, "red" => 0.2)
|
185
|
+
experiment = Split::ExperimentCatalog.find("link_color")
|
186
|
+
expect(experiment.alternatives.map(&:name)).to eq(["blue", "red"])
|
187
|
+
expect(experiment.alternatives.collect { |a| a.weight }).to match_array([0.01, 0.2])
|
187
188
|
end
|
188
189
|
|
189
190
|
it "should only let a user participate in one experiment at a time" do
|
190
|
-
link_color = ab_test(
|
191
|
-
ab_test(
|
192
|
-
expect(ab_user[
|
193
|
-
big = Split::Alternative.new(
|
191
|
+
link_color = ab_test("link_color", "blue", "red")
|
192
|
+
ab_test("button_size", "small", "big")
|
193
|
+
expect(ab_user["link_color"]).to eq(link_color)
|
194
|
+
big = Split::Alternative.new("big", "button_size")
|
194
195
|
expect(big.participant_count).to eq(0)
|
195
|
-
small = Split::Alternative.new(
|
196
|
+
small = Split::Alternative.new("small", "button_size")
|
196
197
|
expect(small.participant_count).to eq(0)
|
197
198
|
end
|
198
199
|
|
@@ -200,179 +201,177 @@ describe Split::Helper do
|
|
200
201
|
Split.configure do |config|
|
201
202
|
config.allow_multiple_experiments = true
|
202
203
|
end
|
203
|
-
link_color = ab_test(
|
204
|
-
button_size = ab_test(
|
205
|
-
expect(ab_user[
|
206
|
-
expect(ab_user[
|
207
|
-
button_size_alt = Split::Alternative.new(button_size,
|
204
|
+
link_color = ab_test("link_color", "blue", "red")
|
205
|
+
button_size = ab_test("button_size", "small", "big")
|
206
|
+
expect(ab_user["link_color"]).to eq(link_color)
|
207
|
+
expect(ab_user["button_size"]).to eq(button_size)
|
208
|
+
button_size_alt = Split::Alternative.new(button_size, "button_size")
|
208
209
|
expect(button_size_alt.participant_count).to eq(1)
|
209
210
|
end
|
210
211
|
|
211
212
|
context "with allow_multiple_experiments = 'control'" do
|
212
213
|
it "should let a user participate in many experiment with one non-'control' alternative" do
|
213
214
|
Split.configure do |config|
|
214
|
-
config.allow_multiple_experiments =
|
215
|
+
config.allow_multiple_experiments = "control"
|
215
216
|
end
|
216
217
|
groups = 100.times.map do |n|
|
217
|
-
ab_test("test#{n}".to_sym, {
|
218
|
+
ab_test("test#{n}".to_sym, { "control" => (100 - n) }, { "test#{n}-alt" => n })
|
218
219
|
end
|
219
220
|
|
220
221
|
experiments = ab_user.active_experiments
|
221
222
|
expect(experiments.size).to be > 1
|
222
223
|
|
223
|
-
count_control = experiments.values.count { |g| g ==
|
224
|
+
count_control = experiments.values.count { |g| g == "control" }
|
224
225
|
expect(count_control).to eq(experiments.size - 1)
|
225
226
|
|
226
|
-
count_alts = groups.count { |g| g !=
|
227
|
+
count_alts = groups.count { |g| g != "control" }
|
227
228
|
expect(count_alts).to eq(1)
|
228
229
|
end
|
229
230
|
|
230
231
|
context "when user already has experiment" do
|
231
|
-
let(:mock_user){ Split::User.new(self, {
|
232
|
+
let(:mock_user) { Split::User.new(self, { "test_0" => "test-alt" }) }
|
232
233
|
|
233
234
|
before do
|
234
235
|
Split.configure do |config|
|
235
|
-
config.allow_multiple_experiments =
|
236
|
+
config.allow_multiple_experiments = "control"
|
236
237
|
end
|
237
238
|
|
238
|
-
Split::ExperimentCatalog.find_or_initialize(
|
239
|
-
Split::ExperimentCatalog.find_or_initialize(
|
239
|
+
Split::ExperimentCatalog.find_or_initialize("test_0", "control", "test-alt").save
|
240
|
+
Split::ExperimentCatalog.find_or_initialize("test_1", "control", "test-alt").save
|
240
241
|
end
|
241
242
|
|
242
243
|
it "should restore previously selected alternative" do
|
243
244
|
expect(ab_user.active_experiments.size).to eq 1
|
244
|
-
expect(ab_test(:test_0, {
|
245
|
-
expect(ab_test(:test_0, {
|
245
|
+
expect(ab_test(:test_0, { "control" => 100 }, { "test-alt" => 1 })).to eq "test-alt"
|
246
|
+
expect(ab_test(:test_0, { "control" => 1 }, { "test-alt" => 100 })).to eq "test-alt"
|
246
247
|
end
|
247
248
|
|
248
249
|
it "should select the correct alternatives after experiment resets" do
|
249
250
|
experiment = Split::ExperimentCatalog.find(:test_0)
|
250
251
|
experiment.reset
|
251
|
-
mock_user[experiment.key] =
|
252
|
+
mock_user[experiment.key] = "test-alt"
|
252
253
|
|
253
254
|
expect(ab_user.active_experiments.size).to eq 1
|
254
|
-
expect(ab_test(:test_0, {
|
255
|
-
expect(ab_test(:test_0, {
|
255
|
+
expect(ab_test(:test_0, { "control" => 100 }, { "test-alt" => 1 })).to eq "test-alt"
|
256
|
+
expect(ab_test(:test_0, { "control" => 0 }, { "test-alt" => 100 })).to eq "test-alt"
|
256
257
|
end
|
257
258
|
|
258
259
|
it "lets override existing choice" do
|
259
260
|
pending "this requires user store reset on first call not depending on whelther it is current trial"
|
260
|
-
@params = {
|
261
|
+
@params = { "ab_test" => { "test_1" => "test-alt" } }
|
261
262
|
|
262
|
-
expect(ab_test(:test_0, {
|
263
|
-
expect(ab_test(:test_1, {
|
263
|
+
expect(ab_test(:test_0, { "control" => 0 }, { "test-alt" => 100 })).to eq "control"
|
264
|
+
expect(ab_test(:test_1, { "control" => 100 }, { "test-alt" => 1 })).to eq "test-alt"
|
264
265
|
end
|
265
|
-
|
266
266
|
end
|
267
|
-
|
268
267
|
end
|
269
268
|
|
270
269
|
it "should not over-write a finished key when an experiment is on a later version" do
|
271
270
|
experiment.increment_version
|
272
|
-
ab_user = { experiment.key =>
|
271
|
+
ab_user = { experiment.key => "blue", experiment.finished_key => true }
|
273
272
|
finished_session = ab_user.dup
|
274
|
-
ab_test(
|
273
|
+
ab_test("link_color", "blue", "red")
|
275
274
|
expect(ab_user).to eq(finished_session)
|
276
275
|
end
|
277
276
|
end
|
278
277
|
|
279
|
-
describe
|
280
|
-
context
|
278
|
+
describe "metadata" do
|
279
|
+
context "is defined" do
|
281
280
|
before do
|
282
281
|
Split.configuration.experiments = {
|
283
|
-
:
|
284
|
-
:
|
285
|
-
:
|
286
|
-
:
|
282
|
+
my_experiment: {
|
283
|
+
alternatives: ["one", "two"],
|
284
|
+
resettable: false,
|
285
|
+
metadata: { "one" => "Meta1", "two" => "Meta2" }
|
287
286
|
}
|
288
287
|
}
|
289
288
|
end
|
290
289
|
|
291
|
-
it
|
292
|
-
@params = {
|
293
|
-
expect(ab_test(
|
294
|
-
expect(ab_test(
|
290
|
+
it "should be passed to helper block" do
|
291
|
+
@params = { "ab_test" => { "my_experiment" => "two" } }
|
292
|
+
expect(ab_test("my_experiment")).to eq "two"
|
293
|
+
expect(ab_test("my_experiment") do |alternative, meta|
|
295
294
|
meta
|
296
|
-
end).to eq(
|
295
|
+
end).to eq("Meta2")
|
297
296
|
end
|
298
297
|
|
299
|
-
it
|
298
|
+
it "should pass control metadata helper block if library disabled" do
|
300
299
|
Split.configure do |config|
|
301
300
|
config.enabled = false
|
302
301
|
end
|
303
302
|
|
304
|
-
expect(ab_test(
|
305
|
-
expect(ab_test(
|
303
|
+
expect(ab_test("my_experiment")).to eq "one"
|
304
|
+
expect(ab_test("my_experiment") do |_, meta|
|
306
305
|
meta
|
307
|
-
end).to eq(
|
306
|
+
end).to eq("Meta1")
|
308
307
|
end
|
309
308
|
end
|
310
309
|
|
311
|
-
context
|
310
|
+
context "is not defined" do
|
312
311
|
before do
|
313
312
|
Split.configuration.experiments = {
|
314
|
-
:
|
315
|
-
:
|
316
|
-
:
|
317
|
-
:
|
313
|
+
my_experiment: {
|
314
|
+
alternatives: ["one", "two"],
|
315
|
+
resettable: false,
|
316
|
+
metadata: nil
|
318
317
|
}
|
319
318
|
}
|
320
319
|
end
|
321
320
|
|
322
|
-
it
|
323
|
-
expect(ab_test(
|
321
|
+
it "should be passed to helper block" do
|
322
|
+
expect(ab_test("my_experiment") do |alternative, meta|
|
324
323
|
meta
|
325
324
|
end).to eq({})
|
326
325
|
end
|
327
326
|
|
328
|
-
it
|
327
|
+
it "should pass control metadata helper block if library disabled" do
|
329
328
|
Split.configure do |config|
|
330
329
|
config.enabled = false
|
331
330
|
end
|
332
331
|
|
333
|
-
expect(ab_test(
|
332
|
+
expect(ab_test("my_experiment") do |_, meta|
|
334
333
|
meta
|
335
334
|
end).to eq({})
|
336
335
|
end
|
337
336
|
end
|
338
337
|
end
|
339
338
|
|
340
|
-
describe
|
341
|
-
context
|
339
|
+
describe "ab_finished" do
|
340
|
+
context "for an experiment that the user participates in" do
|
342
341
|
before(:each) do
|
343
|
-
@experiment_name =
|
344
|
-
@alternatives = [
|
342
|
+
@experiment_name = "link_color"
|
343
|
+
@alternatives = ["blue", "red"]
|
345
344
|
@experiment = Split::ExperimentCatalog.find_or_create(@experiment_name, *@alternatives)
|
346
345
|
@alternative_name = ab_test(@experiment_name, *@alternatives)
|
347
346
|
@previous_completion_count = Split::Alternative.new(@alternative_name, @experiment_name).completed_count
|
348
347
|
end
|
349
348
|
|
350
|
-
it
|
349
|
+
it "should increment the counter for the completed alternative" do
|
351
350
|
ab_finished(@experiment_name)
|
352
351
|
new_completion_count = Split::Alternative.new(@alternative_name, @experiment_name).completed_count
|
353
352
|
expect(new_completion_count).to eq(@previous_completion_count + 1)
|
354
353
|
end
|
355
354
|
|
356
355
|
it "should set experiment's finished key if reset is false" do
|
357
|
-
ab_finished(@experiment_name, {:
|
356
|
+
ab_finished(@experiment_name, { reset: false })
|
358
357
|
expect(ab_user[@experiment.key]).to eq(@alternative_name)
|
359
358
|
expect(ab_user[@experiment.finished_key]).to eq(true)
|
360
359
|
end
|
361
360
|
|
362
|
-
it
|
363
|
-
2.times { ab_finished(@experiment_name, {:
|
361
|
+
it "should not increment the counter if reset is false and the experiment has been already finished" do
|
362
|
+
2.times { ab_finished(@experiment_name, { reset: false }) }
|
364
363
|
new_completion_count = Split::Alternative.new(@alternative_name, @experiment_name).completed_count
|
365
364
|
expect(new_completion_count).to eq(@previous_completion_count + 1)
|
366
365
|
end
|
367
366
|
|
368
|
-
it
|
369
|
-
e = Split::ExperimentCatalog.find_or_create(
|
370
|
-
e.winner =
|
371
|
-
a = ab_test(
|
372
|
-
expect(a).to eq(
|
373
|
-
expect
|
374
|
-
ab_finished(
|
375
|
-
}
|
367
|
+
it "should not increment the counter for an ended experiment" do
|
368
|
+
e = Split::ExperimentCatalog.find_or_create("button_size", "small", "big")
|
369
|
+
e.winner = "small"
|
370
|
+
a = ab_test("button_size", "small", "big")
|
371
|
+
expect(a).to eq("small")
|
372
|
+
expect {
|
373
|
+
ab_finished("button_size")
|
374
|
+
}.not_to change { Split::Alternative.new(a, "button_size").completed_count }
|
376
375
|
end
|
377
376
|
|
378
377
|
it "should clear out the user's participation from their session" do
|
@@ -383,7 +382,7 @@ describe Split::Helper do
|
|
383
382
|
|
384
383
|
it "should not clear out the users session if reset is false" do
|
385
384
|
expect(ab_user[@experiment.key]).to eq(@alternative_name)
|
386
|
-
ab_finished(@experiment_name, {:
|
385
|
+
ab_finished(@experiment_name, { reset: false })
|
387
386
|
expect(ab_user[@experiment.key]).to eq(@alternative_name)
|
388
387
|
expect(ab_user[@experiment.finished_key]).to eq(true)
|
389
388
|
end
|
@@ -418,46 +417,46 @@ describe Split::Helper do
|
|
418
417
|
end
|
419
418
|
end
|
420
419
|
|
421
|
-
context
|
420
|
+
context "for an experiment that the user is excluded from" do
|
422
421
|
before do
|
423
|
-
alternative = ab_test(
|
424
|
-
expect(Split::Alternative.new(alternative,
|
425
|
-
alternative = ab_test(
|
426
|
-
expect(Split::Alternative.new(alternative,
|
422
|
+
alternative = ab_test("link_color", "blue", "red")
|
423
|
+
expect(Split::Alternative.new(alternative, "link_color").participant_count).to eq(1)
|
424
|
+
alternative = ab_test("button_size", "small", "big")
|
425
|
+
expect(Split::Alternative.new(alternative, "button_size").participant_count).to eq(0)
|
427
426
|
end
|
428
427
|
|
429
|
-
it
|
428
|
+
it "should not increment the completed counter" do
|
430
429
|
# So, user should be participating in the link_color experiment and
|
431
430
|
# receive the control for button_size. As the user is not participating in
|
432
431
|
# the button size experiment, finishing it should not increase the
|
433
432
|
# completion count for that alternative.
|
434
|
-
expect
|
435
|
-
ab_finished(
|
436
|
-
}
|
433
|
+
expect {
|
434
|
+
ab_finished("button_size")
|
435
|
+
}.not_to change { Split::Alternative.new("small", "button_size").completed_count }
|
437
436
|
end
|
438
437
|
end
|
439
438
|
|
440
|
-
context
|
439
|
+
context "for an experiment that the user does not participate in" do
|
441
440
|
before do
|
442
|
-
Split::ExperimentCatalog.find_or_create(:not_started_experiment,
|
441
|
+
Split::ExperimentCatalog.find_or_create(:not_started_experiment, "control", "alt")
|
443
442
|
end
|
444
|
-
it
|
443
|
+
it "should not raise an exception" do
|
445
444
|
expect { ab_finished(:not_started_experiment) }.not_to raise_exception
|
446
445
|
end
|
447
446
|
|
448
|
-
it
|
449
|
-
expect { ab_finished(:not_started_experiment, reset: false) }.not_to change { ab_user.keys}.from([])
|
447
|
+
it "should not change the user state when reset is false" do
|
448
|
+
expect { ab_finished(:not_started_experiment, reset: false) }.not_to change { ab_user.keys }.from([])
|
450
449
|
end
|
451
450
|
|
452
|
-
it
|
451
|
+
it "should not change the user state when reset is true" do
|
453
452
|
expect(self).not_to receive(:reset!)
|
454
453
|
ab_finished(:not_started_experiment)
|
455
454
|
end
|
456
455
|
|
457
|
-
it
|
456
|
+
it "should not increment the completed counter" do
|
458
457
|
ab_finished(:not_started_experiment)
|
459
|
-
expect(Split::Alternative.new(
|
460
|
-
expect(Split::Alternative.new(
|
458
|
+
expect(Split::Alternative.new("control", :not_started_experiment).completed_count).to eq(0)
|
459
|
+
expect(Split::Alternative.new("alt", :not_started_experiment).completed_count).to eq(0)
|
461
460
|
end
|
462
461
|
end
|
463
462
|
end
|
@@ -465,9 +464,9 @@ describe Split::Helper do
|
|
465
464
|
context "finished with config" do
|
466
465
|
it "passes reset option" do
|
467
466
|
Split.configuration.experiments = {
|
468
|
-
:
|
469
|
-
:
|
470
|
-
:
|
467
|
+
my_experiment: {
|
468
|
+
alternatives: ["one", "two"],
|
469
|
+
resettable: false,
|
471
470
|
}
|
472
471
|
}
|
473
472
|
alternative = ab_test(:my_experiment)
|
@@ -483,11 +482,11 @@ describe Split::Helper do
|
|
483
482
|
before { Split.configuration.experiments = {} }
|
484
483
|
before { expect(Split::Alternative).to receive(:new).at_least(1).times.and_call_original }
|
485
484
|
|
486
|
-
def should_finish_experiment(experiment_name, should_finish=true)
|
485
|
+
def should_finish_experiment(experiment_name, should_finish = true)
|
487
486
|
alts = Split.configuration.experiments[experiment_name][:alternatives]
|
488
487
|
experiment = Split::ExperimentCatalog.find_or_create(experiment_name, *alts)
|
489
488
|
alt_name = ab_user[experiment.key] = alts.first
|
490
|
-
alt = double(
|
489
|
+
alt = double("alternative")
|
491
490
|
expect(alt).to receive(:name).at_most(1).times.and_return(alt_name)
|
492
491
|
expect(Split::Alternative).to receive(:new).at_most(1).times.with(alt_name, experiment_name.to_s).and_return(alt)
|
493
492
|
if should_finish
|
@@ -499,8 +498,8 @@ describe Split::Helper do
|
|
499
498
|
|
500
499
|
it "completes the test" do
|
501
500
|
Split.configuration.experiments[:my_experiment] = {
|
502
|
-
:
|
503
|
-
:
|
501
|
+
alternatives: [ "control_opt", "other_opt" ],
|
502
|
+
metric: :my_metric
|
504
503
|
}
|
505
504
|
should_finish_experiment :my_experiment
|
506
505
|
ab_finished :my_metric
|
@@ -508,17 +507,17 @@ describe Split::Helper do
|
|
508
507
|
|
509
508
|
it "completes all relevant tests" do
|
510
509
|
Split.configuration.experiments = {
|
511
|
-
:
|
512
|
-
:
|
513
|
-
:
|
510
|
+
exp_1: {
|
511
|
+
alternatives: [ "1-1", "1-2" ],
|
512
|
+
metric: :my_metric
|
514
513
|
},
|
515
|
-
:
|
516
|
-
:
|
517
|
-
:
|
514
|
+
exp_2: {
|
515
|
+
alternatives: [ "2-1", "2-2" ],
|
516
|
+
metric: :another_metric
|
518
517
|
},
|
519
|
-
:
|
520
|
-
:
|
521
|
-
:
|
518
|
+
exp_3: {
|
519
|
+
alternatives: [ "3-1", "3-2" ],
|
520
|
+
metric: :my_metric
|
522
521
|
},
|
523
522
|
}
|
524
523
|
should_finish_experiment :exp_1
|
@@ -529,10 +528,10 @@ describe Split::Helper do
|
|
529
528
|
|
530
529
|
it "passes reset option" do
|
531
530
|
Split.configuration.experiments = {
|
532
|
-
:
|
533
|
-
:
|
534
|
-
:
|
535
|
-
:
|
531
|
+
my_exp: {
|
532
|
+
alternatives: ["one", "two"],
|
533
|
+
metric: :my_metric,
|
534
|
+
resettable: false,
|
536
535
|
}
|
537
536
|
}
|
538
537
|
alternative_name = ab_test(:my_exp)
|
@@ -545,199 +544,233 @@ describe Split::Helper do
|
|
545
544
|
|
546
545
|
it "passes through options" do
|
547
546
|
Split.configuration.experiments = {
|
548
|
-
:
|
549
|
-
:
|
550
|
-
:
|
547
|
+
my_exp: {
|
548
|
+
alternatives: ["one", "two"],
|
549
|
+
metric: :my_metric,
|
551
550
|
}
|
552
551
|
}
|
553
552
|
alternative_name = ab_test(:my_exp)
|
554
553
|
exp = Split::ExperimentCatalog.find :my_exp
|
555
554
|
|
556
|
-
ab_finished :my_metric, :
|
555
|
+
ab_finished :my_metric, reset: false
|
557
556
|
expect(ab_user[exp.key]).to eq(alternative_name)
|
558
557
|
expect(ab_user[exp.finished_key]).to be_truthy
|
559
558
|
end
|
560
559
|
end
|
561
560
|
|
562
|
-
describe 'conversions' do
|
563
|
-
it 'should return a conversion rate for an alternative' do
|
564
|
-
alternative_name = ab_test('link_color', 'blue', 'red')
|
565
561
|
|
566
|
-
|
562
|
+
describe "ab_record_extra_info" do
|
563
|
+
context "for an experiment that the user participates in" do
|
564
|
+
before(:each) do
|
565
|
+
@experiment_name = "link_color"
|
566
|
+
@alternatives = ["blue", "red"]
|
567
|
+
@experiment = Split::ExperimentCatalog.find_or_create(@experiment_name, *@alternatives)
|
568
|
+
@alternative_name = ab_test(@experiment_name, *@alternatives)
|
569
|
+
end
|
570
|
+
|
571
|
+
it "records extra data for a given experiment" do
|
572
|
+
alternative = Split::Alternative.new(@alternative_name, "link_color")
|
573
|
+
|
574
|
+
ab_record_extra_info(@experiment_name, "some_data", 10)
|
575
|
+
|
576
|
+
expect(alternative.extra_info).to eql({ "some_data" => 10 })
|
577
|
+
end
|
578
|
+
|
579
|
+
it "records extra data for a given experiment" do
|
580
|
+
alternative = Split::Alternative.new(@alternative_name, "link_color")
|
581
|
+
|
582
|
+
ab_record_extra_info(@experiment_name, "some_data")
|
583
|
+
|
584
|
+
expect(alternative.extra_info).to eql({ "some_data" => 1 })
|
585
|
+
end
|
586
|
+
|
587
|
+
it "records extra data for a given experiment" do
|
588
|
+
alternative = Split::Alternative.new(@alternative_name, "link_color")
|
589
|
+
|
590
|
+
ab_record_extra_info(@experiment_name, "some_data", nil)
|
591
|
+
|
592
|
+
expect(alternative.extra_info).to eql({})
|
593
|
+
end
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
describe "conversions" do
|
598
|
+
it "should return a conversion rate for an alternative" do
|
599
|
+
alternative_name = ab_test("link_color", "blue", "red")
|
600
|
+
|
601
|
+
previous_convertion_rate = Split::Alternative.new(alternative_name, "link_color").conversion_rate
|
567
602
|
expect(previous_convertion_rate).to eq(0.0)
|
568
603
|
|
569
|
-
ab_finished(
|
604
|
+
ab_finished("link_color")
|
570
605
|
|
571
|
-
new_convertion_rate = Split::Alternative.new(alternative_name,
|
606
|
+
new_convertion_rate = Split::Alternative.new(alternative_name, "link_color").conversion_rate
|
572
607
|
expect(new_convertion_rate).to eq(1.0)
|
573
608
|
end
|
574
609
|
end
|
575
610
|
|
576
|
-
describe
|
577
|
-
it
|
578
|
-
alternative = ab_test(
|
611
|
+
describe "active experiments" do
|
612
|
+
it "should show an active test" do
|
613
|
+
alternative = ab_test("def", "4", "5", "6")
|
579
614
|
expect(active_experiments.count).to eq 1
|
580
615
|
expect(active_experiments.first[0]).to eq "def"
|
581
616
|
expect(active_experiments.first[1]).to eq alternative
|
582
617
|
end
|
583
618
|
|
584
|
-
it
|
585
|
-
alternative = ab_test(
|
586
|
-
ab_finished(
|
619
|
+
it "should show a finished test" do
|
620
|
+
alternative = ab_test("def", "4", "5", "6")
|
621
|
+
ab_finished("def", { reset: false })
|
587
622
|
expect(active_experiments.count).to eq 1
|
588
623
|
expect(active_experiments.first[0]).to eq "def"
|
589
624
|
expect(active_experiments.first[1]).to eq alternative
|
590
625
|
end
|
591
626
|
|
592
|
-
it
|
627
|
+
it "should show an active test when an experiment is on a later version" do
|
593
628
|
experiment.reset
|
594
629
|
expect(experiment.version).to eq(1)
|
595
|
-
ab_test(
|
630
|
+
ab_test("link_color", "blue", "red")
|
596
631
|
expect(active_experiments.count).to eq 1
|
597
632
|
expect(active_experiments.first[0]).to eq "link_color"
|
598
633
|
end
|
599
634
|
|
600
|
-
it
|
635
|
+
it "should show versioned tests properly" do
|
601
636
|
10.times { experiment.reset }
|
602
637
|
|
603
|
-
alternative = ab_test(experiment.name,
|
638
|
+
alternative = ab_test(experiment.name, "blue", "red")
|
604
639
|
ab_finished(experiment.name, reset: false)
|
605
640
|
|
606
641
|
expect(experiment.version).to eq(10)
|
607
642
|
expect(active_experiments.count).to eq 1
|
608
|
-
expect(active_experiments).to eq({
|
643
|
+
expect(active_experiments).to eq({ "link_color" => alternative })
|
609
644
|
end
|
610
645
|
|
611
|
-
it
|
646
|
+
it "should show multiple tests" do
|
612
647
|
Split.configure do |config|
|
613
648
|
config.allow_multiple_experiments = true
|
614
649
|
end
|
615
|
-
alternative = ab_test(
|
616
|
-
another_alternative = ab_test(
|
650
|
+
alternative = ab_test("def", "4", "5", "6")
|
651
|
+
another_alternative = ab_test("ghi", "7", "8", "9")
|
617
652
|
expect(active_experiments.count).to eq 2
|
618
|
-
expect(active_experiments[
|
619
|
-
expect(active_experiments[
|
653
|
+
expect(active_experiments["def"]).to eq alternative
|
654
|
+
expect(active_experiments["ghi"]).to eq another_alternative
|
620
655
|
end
|
621
656
|
|
622
|
-
it
|
657
|
+
it "should not show tests with winners" do
|
623
658
|
Split.configure do |config|
|
624
659
|
config.allow_multiple_experiments = true
|
625
660
|
end
|
626
|
-
e = Split::ExperimentCatalog.find_or_create(
|
627
|
-
e.winner =
|
628
|
-
ab_test(
|
629
|
-
another_alternative = ab_test(
|
661
|
+
e = Split::ExperimentCatalog.find_or_create("def", "4", "5", "6")
|
662
|
+
e.winner = "4"
|
663
|
+
ab_test("def", "4", "5", "6")
|
664
|
+
another_alternative = ab_test("ghi", "7", "8", "9")
|
630
665
|
expect(active_experiments.count).to eq 1
|
631
666
|
expect(active_experiments.first[0]).to eq "ghi"
|
632
667
|
expect(active_experiments.first[1]).to eq another_alternative
|
633
668
|
end
|
634
669
|
end
|
635
670
|
|
636
|
-
describe
|
671
|
+
describe "when user is a robot" do
|
637
672
|
before(:each) do
|
638
|
-
@request = OpenStruct.new(:
|
673
|
+
@request = OpenStruct.new(user_agent: "Googlebot/2.1 (+http://www.google.com/bot.html)")
|
639
674
|
end
|
640
675
|
|
641
|
-
describe
|
642
|
-
it
|
643
|
-
alternative = ab_test(
|
676
|
+
describe "ab_test" do
|
677
|
+
it "should return the control" do
|
678
|
+
alternative = ab_test("link_color", "blue", "red")
|
644
679
|
expect(alternative).to eq experiment.control.name
|
645
680
|
end
|
646
681
|
|
647
|
-
it
|
648
|
-
ab_test(
|
649
|
-
expect(Split::Experiment.new(
|
682
|
+
it "should not create a experiment" do
|
683
|
+
ab_test("link_color", "blue", "red")
|
684
|
+
expect(Split::Experiment.new("link_color")).to be_a_new_record
|
650
685
|
end
|
651
686
|
|
652
687
|
it "should not increment the participation count" do
|
688
|
+
previous_red_count = Split::Alternative.new("red", "link_color").participant_count
|
689
|
+
previous_blue_count = Split::Alternative.new("blue", "link_color").participant_count
|
653
690
|
|
654
|
-
|
655
|
-
previous_blue_count = Split::Alternative.new('blue', 'link_color').participant_count
|
656
|
-
|
657
|
-
ab_test('link_color', 'blue', 'red')
|
691
|
+
ab_test("link_color", "blue", "red")
|
658
692
|
|
659
|
-
new_red_count = Split::Alternative.new(
|
660
|
-
new_blue_count = Split::Alternative.new(
|
693
|
+
new_red_count = Split::Alternative.new("red", "link_color").participant_count
|
694
|
+
new_blue_count = Split::Alternative.new("blue", "link_color").participant_count
|
661
695
|
|
662
696
|
expect((new_red_count + new_blue_count)).to eq(previous_red_count + previous_blue_count)
|
663
697
|
end
|
664
698
|
end
|
665
699
|
|
666
|
-
describe
|
700
|
+
describe "finished" do
|
667
701
|
it "should not increment the completed count" do
|
668
|
-
alternative_name = ab_test(
|
702
|
+
alternative_name = ab_test("link_color", "blue", "red")
|
669
703
|
|
670
|
-
previous_completion_count = Split::Alternative.new(alternative_name,
|
704
|
+
previous_completion_count = Split::Alternative.new(alternative_name, "link_color").completed_count
|
671
705
|
|
672
|
-
ab_finished(
|
706
|
+
ab_finished("link_color")
|
673
707
|
|
674
|
-
new_completion_count = Split::Alternative.new(alternative_name,
|
708
|
+
new_completion_count = Split::Alternative.new(alternative_name, "link_color").completed_count
|
675
709
|
|
676
710
|
expect(new_completion_count).to eq(previous_completion_count)
|
677
711
|
end
|
678
712
|
end
|
679
713
|
end
|
680
714
|
|
681
|
-
describe
|
715
|
+
describe "when providing custom ignore logic" do
|
682
716
|
context "using a proc to configure custom logic" do
|
683
|
-
|
684
717
|
before(:each) do
|
685
718
|
Split.configure do |c|
|
686
|
-
c.ignore_filter = proc{|request| true } # ignore everything
|
719
|
+
c.ignore_filter = proc { |request| true } # ignore everything
|
687
720
|
end
|
688
721
|
end
|
689
722
|
|
690
723
|
it "ignores the ab_test" do
|
691
|
-
ab_test(
|
724
|
+
ab_test("link_color", "blue", "red")
|
692
725
|
|
693
|
-
red_count = Split::Alternative.new(
|
694
|
-
blue_count = Split::Alternative.new(
|
726
|
+
red_count = Split::Alternative.new("red", "link_color").participant_count
|
727
|
+
blue_count = Split::Alternative.new("blue", "link_color").participant_count
|
695
728
|
expect((red_count + blue_count)).to be(0)
|
696
729
|
end
|
697
730
|
end
|
698
731
|
end
|
699
732
|
|
700
733
|
shared_examples_for "a disabled test" do
|
701
|
-
describe
|
702
|
-
it
|
703
|
-
alternative = ab_test(
|
734
|
+
describe "ab_test" do
|
735
|
+
it "should return the control" do
|
736
|
+
alternative = ab_test("link_color", "blue", "red")
|
704
737
|
expect(alternative).to eq experiment.control.name
|
705
738
|
end
|
706
739
|
|
707
740
|
it "should not increment the participation count" do
|
708
|
-
previous_red_count = Split::Alternative.new(
|
709
|
-
previous_blue_count = Split::Alternative.new(
|
741
|
+
previous_red_count = Split::Alternative.new("red", "link_color").participant_count
|
742
|
+
previous_blue_count = Split::Alternative.new("blue", "link_color").participant_count
|
710
743
|
|
711
|
-
ab_test(
|
744
|
+
ab_test("link_color", "blue", "red")
|
712
745
|
|
713
|
-
new_red_count = Split::Alternative.new(
|
714
|
-
new_blue_count = Split::Alternative.new(
|
746
|
+
new_red_count = Split::Alternative.new("red", "link_color").participant_count
|
747
|
+
new_blue_count = Split::Alternative.new("blue", "link_color").participant_count
|
715
748
|
|
716
749
|
expect((new_red_count + new_blue_count)).to eq(previous_red_count + previous_blue_count)
|
717
750
|
end
|
718
751
|
end
|
719
752
|
|
720
|
-
describe
|
753
|
+
describe "finished" do
|
721
754
|
it "should not increment the completed count" do
|
722
|
-
alternative_name = ab_test(
|
755
|
+
alternative_name = ab_test("link_color", "blue", "red")
|
723
756
|
|
724
|
-
previous_completion_count = Split::Alternative.new(alternative_name,
|
757
|
+
previous_completion_count = Split::Alternative.new(alternative_name, "link_color").completed_count
|
725
758
|
|
726
|
-
ab_finished(
|
759
|
+
ab_finished("link_color")
|
727
760
|
|
728
|
-
new_completion_count = Split::Alternative.new(alternative_name,
|
761
|
+
new_completion_count = Split::Alternative.new(alternative_name, "link_color").completed_count
|
729
762
|
|
730
763
|
expect(new_completion_count).to eq(previous_completion_count)
|
731
764
|
end
|
732
765
|
end
|
733
766
|
end
|
734
767
|
|
735
|
-
describe
|
768
|
+
describe "when ip address is ignored" do
|
736
769
|
context "individually" do
|
737
770
|
before(:each) do
|
738
|
-
@request = OpenStruct.new(:
|
771
|
+
@request = OpenStruct.new(ip: "81.19.48.130")
|
739
772
|
Split.configure do |c|
|
740
|
-
c.ignore_ip_addresses <<
|
773
|
+
c.ignore_ip_addresses << "81.19.48.130"
|
741
774
|
end
|
742
775
|
end
|
743
776
|
|
@@ -746,7 +779,7 @@ describe Split::Helper do
|
|
746
779
|
|
747
780
|
context "for a range" do
|
748
781
|
before(:each) do
|
749
|
-
@request = OpenStruct.new(:
|
782
|
+
@request = OpenStruct.new(ip: "81.19.48.129")
|
750
783
|
Split.configure do |c|
|
751
784
|
c.ignore_ip_addresses << /81\.19\.48\.[0-9]+/
|
752
785
|
end
|
@@ -757,9 +790,9 @@ describe Split::Helper do
|
|
757
790
|
|
758
791
|
context "using both a range and a specific value" do
|
759
792
|
before(:each) do
|
760
|
-
@request = OpenStruct.new(:
|
793
|
+
@request = OpenStruct.new(ip: "81.19.48.128")
|
761
794
|
Split.configure do |c|
|
762
|
-
c.ignore_ip_addresses <<
|
795
|
+
c.ignore_ip_addresses << "81.19.48.130"
|
763
796
|
c.ignore_ip_addresses << /81\.19\.48\.[0-9]+/
|
764
797
|
end
|
765
798
|
end
|
@@ -769,119 +802,119 @@ describe Split::Helper do
|
|
769
802
|
|
770
803
|
context "when ignored other address" do
|
771
804
|
before do
|
772
|
-
@request = OpenStruct.new(:
|
805
|
+
@request = OpenStruct.new(ip: "1.1.1.1")
|
773
806
|
Split.configure do |c|
|
774
|
-
c.ignore_ip_addresses <<
|
807
|
+
c.ignore_ip_addresses << "81.19.48.130"
|
775
808
|
end
|
776
809
|
end
|
777
810
|
|
778
811
|
it "works as usual" do
|
779
|
-
alternative_name = ab_test(
|
780
|
-
expect{
|
781
|
-
ab_finished(
|
782
|
-
}.to change(Split::Alternative.new(alternative_name,
|
812
|
+
alternative_name = ab_test("link_color", "red", "blue")
|
813
|
+
expect {
|
814
|
+
ab_finished("link_color")
|
815
|
+
}.to change(Split::Alternative.new(alternative_name, "link_color"), :completed_count).by(1)
|
783
816
|
end
|
784
817
|
end
|
785
818
|
end
|
786
819
|
|
787
|
-
describe
|
820
|
+
describe "when user is previewing" do
|
788
821
|
before(:each) do
|
789
|
-
@request = OpenStruct.new(headers: {
|
822
|
+
@request = OpenStruct.new(headers: { "x-purpose" => "preview" })
|
790
823
|
end
|
791
824
|
|
792
825
|
it_behaves_like "a disabled test"
|
793
826
|
end
|
794
827
|
|
795
|
-
describe
|
828
|
+
describe "versioned experiments" do
|
796
829
|
it "should use version zero if no version is present" do
|
797
|
-
alternative_name = ab_test(
|
830
|
+
alternative_name = ab_test("link_color", "blue", "red")
|
798
831
|
expect(experiment.version).to eq(0)
|
799
|
-
expect(ab_user[
|
832
|
+
expect(ab_user["link_color"]).to eq(alternative_name)
|
800
833
|
end
|
801
834
|
|
802
835
|
it "should save the version of the experiment to the session" do
|
803
836
|
experiment.reset
|
804
837
|
expect(experiment.version).to eq(1)
|
805
|
-
alternative_name = ab_test(
|
806
|
-
expect(ab_user[
|
838
|
+
alternative_name = ab_test("link_color", "blue", "red")
|
839
|
+
expect(ab_user["link_color:1"]).to eq(alternative_name)
|
807
840
|
end
|
808
841
|
|
809
842
|
it "should load the experiment even if the version is not 0" do
|
810
843
|
experiment.reset
|
811
844
|
expect(experiment.version).to eq(1)
|
812
|
-
alternative_name = ab_test(
|
813
|
-
expect(ab_user[
|
814
|
-
return_alternative_name = ab_test(
|
845
|
+
alternative_name = ab_test("link_color", "blue", "red")
|
846
|
+
expect(ab_user["link_color:1"]).to eq(alternative_name)
|
847
|
+
return_alternative_name = ab_test("link_color", "blue", "red")
|
815
848
|
expect(return_alternative_name).to eq(alternative_name)
|
816
849
|
end
|
817
850
|
|
818
851
|
it "should reset the session of a user on an older version of the experiment" do
|
819
|
-
alternative_name = ab_test(
|
820
|
-
expect(ab_user[
|
821
|
-
alternative = Split::Alternative.new(alternative_name,
|
852
|
+
alternative_name = ab_test("link_color", "blue", "red")
|
853
|
+
expect(ab_user["link_color"]).to eq(alternative_name)
|
854
|
+
alternative = Split::Alternative.new(alternative_name, "link_color")
|
822
855
|
expect(alternative.participant_count).to eq(1)
|
823
856
|
|
824
857
|
experiment.reset
|
825
858
|
expect(experiment.version).to eq(1)
|
826
|
-
alternative = Split::Alternative.new(alternative_name,
|
859
|
+
alternative = Split::Alternative.new(alternative_name, "link_color")
|
827
860
|
expect(alternative.participant_count).to eq(0)
|
828
861
|
|
829
|
-
new_alternative_name = ab_test(
|
830
|
-
expect(ab_user[
|
831
|
-
new_alternative = Split::Alternative.new(new_alternative_name,
|
862
|
+
new_alternative_name = ab_test("link_color", "blue", "red")
|
863
|
+
expect(ab_user["link_color:1"]).to eq(new_alternative_name)
|
864
|
+
new_alternative = Split::Alternative.new(new_alternative_name, "link_color")
|
832
865
|
expect(new_alternative.participant_count).to eq(1)
|
833
866
|
end
|
834
867
|
|
835
868
|
it "should cleanup old versions of experiments from the session" do
|
836
|
-
alternative_name = ab_test(
|
837
|
-
expect(ab_user[
|
838
|
-
alternative = Split::Alternative.new(alternative_name,
|
869
|
+
alternative_name = ab_test("link_color", "blue", "red")
|
870
|
+
expect(ab_user["link_color"]).to eq(alternative_name)
|
871
|
+
alternative = Split::Alternative.new(alternative_name, "link_color")
|
839
872
|
expect(alternative.participant_count).to eq(1)
|
840
873
|
|
841
874
|
experiment.reset
|
842
875
|
expect(experiment.version).to eq(1)
|
843
|
-
alternative = Split::Alternative.new(alternative_name,
|
876
|
+
alternative = Split::Alternative.new(alternative_name, "link_color")
|
844
877
|
expect(alternative.participant_count).to eq(0)
|
845
878
|
|
846
|
-
new_alternative_name = ab_test(
|
847
|
-
expect(ab_user[
|
879
|
+
new_alternative_name = ab_test("link_color", "blue", "red")
|
880
|
+
expect(ab_user["link_color:1"]).to eq(new_alternative_name)
|
848
881
|
end
|
849
882
|
|
850
883
|
it "should only count completion of users on the current version" do
|
851
|
-
alternative_name = ab_test(
|
852
|
-
expect(ab_user[
|
853
|
-
|
884
|
+
alternative_name = ab_test("link_color", "blue", "red")
|
885
|
+
expect(ab_user["link_color"]).to eq(alternative_name)
|
886
|
+
Split::Alternative.new(alternative_name, "link_color")
|
854
887
|
|
855
888
|
experiment.reset
|
856
889
|
expect(experiment.version).to eq(1)
|
857
890
|
|
858
|
-
ab_finished(
|
859
|
-
alternative = Split::Alternative.new(alternative_name,
|
891
|
+
ab_finished("link_color")
|
892
|
+
alternative = Split::Alternative.new(alternative_name, "link_color")
|
860
893
|
expect(alternative.completed_count).to eq(0)
|
861
894
|
end
|
862
895
|
end
|
863
896
|
|
864
|
-
context
|
897
|
+
context "when redis is not available" do
|
865
898
|
before(:each) do
|
866
899
|
expect(Split).to receive(:redis).at_most(5).times.and_raise(Errno::ECONNREFUSED.new)
|
867
900
|
end
|
868
901
|
|
869
|
-
context
|
902
|
+
context "and db_failover config option is turned off" do
|
870
903
|
before(:each) do
|
871
904
|
Split.configure do |config|
|
872
905
|
config.db_failover = false
|
873
906
|
end
|
874
907
|
end
|
875
908
|
|
876
|
-
describe
|
877
|
-
it
|
878
|
-
expect
|
909
|
+
describe "ab_test" do
|
910
|
+
it "should raise an exception" do
|
911
|
+
expect { ab_test("link_color", "blue", "red") }.to raise_error(Errno::ECONNREFUSED)
|
879
912
|
end
|
880
913
|
end
|
881
914
|
|
882
|
-
describe
|
883
|
-
it
|
884
|
-
expect
|
915
|
+
describe "finished" do
|
916
|
+
it "should raise an exception" do
|
917
|
+
expect { ab_finished("link_color") }.to raise_error(Errno::ECONNREFUSED)
|
885
918
|
end
|
886
919
|
end
|
887
920
|
|
@@ -893,29 +926,29 @@ describe Split::Helper do
|
|
893
926
|
end
|
894
927
|
|
895
928
|
it "should not attempt to connect to redis" do
|
896
|
-
expect
|
929
|
+
expect { ab_test("link_color", "blue", "red") }.not_to raise_error
|
897
930
|
end
|
898
931
|
|
899
932
|
it "should return control variable" do
|
900
|
-
expect(ab_test(
|
901
|
-
expect
|
933
|
+
expect(ab_test("link_color", "blue", "red")).to eq("blue")
|
934
|
+
expect { ab_finished("link_color") }.not_to raise_error
|
902
935
|
end
|
903
936
|
end
|
904
937
|
end
|
905
938
|
|
906
|
-
context
|
939
|
+
context "and db_failover config option is turned on" do
|
907
940
|
before(:each) do
|
908
941
|
Split.configure do |config|
|
909
942
|
config.db_failover = true
|
910
943
|
end
|
911
944
|
end
|
912
945
|
|
913
|
-
describe
|
914
|
-
it
|
915
|
-
expect
|
946
|
+
describe "ab_test" do
|
947
|
+
it "should not raise an exception" do
|
948
|
+
expect { ab_test("link_color", "blue", "red") }.not_to raise_error
|
916
949
|
end
|
917
950
|
|
918
|
-
it
|
951
|
+
it "should call db_failover_on_db_error proc with error as parameter" do
|
919
952
|
Split.configure do |config|
|
920
953
|
config.db_failover_on_db_error = proc do |error|
|
921
954
|
expect(error).to be_a(Errno::ECONNREFUSED)
|
@@ -923,43 +956,43 @@ describe Split::Helper do
|
|
923
956
|
end
|
924
957
|
|
925
958
|
expect(Split.configuration.db_failover_on_db_error).to receive(:call).and_call_original
|
926
|
-
ab_test(
|
959
|
+
ab_test("link_color", "blue", "red")
|
927
960
|
end
|
928
961
|
|
929
|
-
it
|
930
|
-
expect(ab_test(
|
931
|
-
expect(ab_test(
|
932
|
-
expect(ab_test(
|
933
|
-
expect(ab_test(
|
962
|
+
it "should always use first alternative" do
|
963
|
+
expect(ab_test("link_color", "blue", "red")).to eq("blue")
|
964
|
+
expect(ab_test("link_color", { "blue" => 0.01 }, "red" => 0.2)).to eq("blue")
|
965
|
+
expect(ab_test("link_color", { "blue" => 0.8 }, { "red" => 20 })).to eq("blue")
|
966
|
+
expect(ab_test("link_color", "blue", "red") do |alternative|
|
934
967
|
"shared/#{alternative}"
|
935
|
-
end).to eq(
|
968
|
+
end).to eq("shared/blue")
|
936
969
|
end
|
937
970
|
|
938
|
-
context
|
971
|
+
context "and db_failover_allow_parameter_override config option is turned on" do
|
939
972
|
before(:each) do
|
940
973
|
Split.configure do |config|
|
941
974
|
config.db_failover_allow_parameter_override = true
|
942
975
|
end
|
943
976
|
end
|
944
977
|
|
945
|
-
context
|
946
|
-
it
|
947
|
-
@params = {
|
948
|
-
expect(ab_test(
|
949
|
-
expect(ab_test(
|
950
|
-
expect(ab_test(
|
951
|
-
expect(ab_test(
|
952
|
-
expect(ab_test(
|
978
|
+
context "and given an override parameter" do
|
979
|
+
it "should use given override instead of the first alternative" do
|
980
|
+
@params = { "ab_test" => { "link_color" => "red" } }
|
981
|
+
expect(ab_test("link_color", "blue", "red")).to eq("red")
|
982
|
+
expect(ab_test("link_color", "blue", "red", "green")).to eq("red")
|
983
|
+
expect(ab_test("link_color", { "blue" => 0.01 }, "red" => 0.2)).to eq("red")
|
984
|
+
expect(ab_test("link_color", { "blue" => 0.8 }, { "red" => 20 })).to eq("red")
|
985
|
+
expect(ab_test("link_color", "blue", "red") do |alternative|
|
953
986
|
"shared/#{alternative}"
|
954
|
-
end).to eq(
|
987
|
+
end).to eq("shared/red")
|
955
988
|
end
|
956
989
|
end
|
957
990
|
end
|
958
991
|
|
959
|
-
context
|
992
|
+
context "and preloaded config given" do
|
960
993
|
before do
|
961
994
|
Split.configuration.experiments[:link_color] = {
|
962
|
-
:
|
995
|
+
alternatives: [ "blue", "red" ],
|
963
996
|
}
|
964
997
|
end
|
965
998
|
|
@@ -969,12 +1002,12 @@ describe Split::Helper do
|
|
969
1002
|
end
|
970
1003
|
end
|
971
1004
|
|
972
|
-
describe
|
973
|
-
it
|
974
|
-
expect
|
1005
|
+
describe "finished" do
|
1006
|
+
it "should not raise an exception" do
|
1007
|
+
expect { ab_finished("link_color") }.not_to raise_error
|
975
1008
|
end
|
976
1009
|
|
977
|
-
it
|
1010
|
+
it "should call db_failover_on_db_error proc with error as parameter" do
|
978
1011
|
Split.configure do |config|
|
979
1012
|
config.db_failover_on_db_error = proc do |error|
|
980
1013
|
expect(error).to be_a(Errno::ECONNREFUSED)
|
@@ -982,19 +1015,19 @@ describe Split::Helper do
|
|
982
1015
|
end
|
983
1016
|
|
984
1017
|
expect(Split.configuration.db_failover_on_db_error).to receive(:call).and_call_original
|
985
|
-
ab_finished(
|
1018
|
+
ab_finished("link_color")
|
986
1019
|
end
|
987
1020
|
end
|
988
1021
|
end
|
989
1022
|
end
|
990
1023
|
|
991
1024
|
context "with preloaded config" do
|
992
|
-
before { Split.configuration.experiments = {}}
|
1025
|
+
before { Split.configuration.experiments = {} }
|
993
1026
|
|
994
1027
|
it "pulls options from config file" do
|
995
1028
|
Split.configuration.experiments[:my_experiment] = {
|
996
|
-
:
|
997
|
-
:
|
1029
|
+
alternatives: [ "control_opt", "other_opt" ],
|
1030
|
+
goals: ["goal1", "goal2"]
|
998
1031
|
}
|
999
1032
|
ab_test :my_experiment
|
1000
1033
|
expect(Split::Experiment.new(:my_experiment).alternatives.map(&:name)).to eq([ "control_opt", "other_opt" ])
|
@@ -1003,8 +1036,8 @@ describe Split::Helper do
|
|
1003
1036
|
|
1004
1037
|
it "can be called multiple times" do
|
1005
1038
|
Split.configuration.experiments[:my_experiment] = {
|
1006
|
-
:
|
1007
|
-
:
|
1039
|
+
alternatives: [ "control_opt", "other_opt" ],
|
1040
|
+
goals: ["goal1", "goal2"]
|
1008
1041
|
}
|
1009
1042
|
5.times { ab_test :my_experiment }
|
1010
1043
|
experiment = Split::Experiment.new(:my_experiment)
|
@@ -1015,8 +1048,8 @@ describe Split::Helper do
|
|
1015
1048
|
|
1016
1049
|
it "accepts multiple goals" do
|
1017
1050
|
Split.configuration.experiments[:my_experiment] = {
|
1018
|
-
:
|
1019
|
-
:
|
1051
|
+
alternatives: [ "control_opt", "other_opt" ],
|
1052
|
+
goals: [ "goal1", "goal2", "goal3" ]
|
1020
1053
|
}
|
1021
1054
|
ab_test :my_experiment
|
1022
1055
|
experiment = Split::Experiment.new(:my_experiment)
|
@@ -1025,7 +1058,7 @@ describe Split::Helper do
|
|
1025
1058
|
|
1026
1059
|
it "allow specifying goals to be optional" do
|
1027
1060
|
Split.configuration.experiments[:my_experiment] = {
|
1028
|
-
:
|
1061
|
+
alternatives: [ "control_opt", "other_opt" ]
|
1029
1062
|
}
|
1030
1063
|
experiment = Split::Experiment.new(:my_experiment)
|
1031
1064
|
expect(experiment.goals).to eq([])
|
@@ -1033,7 +1066,7 @@ describe Split::Helper do
|
|
1033
1066
|
|
1034
1067
|
it "accepts multiple alternatives" do
|
1035
1068
|
Split.configuration.experiments[:my_experiment] = {
|
1036
|
-
:
|
1069
|
+
alternatives: [ "control_opt", "second_opt", "third_opt" ],
|
1037
1070
|
}
|
1038
1071
|
ab_test :my_experiment
|
1039
1072
|
experiment = Split::Experiment.new(:my_experiment)
|
@@ -1042,68 +1075,68 @@ describe Split::Helper do
|
|
1042
1075
|
|
1043
1076
|
it "accepts probability on alternatives" do
|
1044
1077
|
Split.configuration.experiments[:my_experiment] = {
|
1045
|
-
:
|
1046
|
-
{ :
|
1047
|
-
{ :
|
1048
|
-
{ :
|
1078
|
+
alternatives: [
|
1079
|
+
{ name: "control_opt", percent: 67 },
|
1080
|
+
{ name: "second_opt", percent: 10 },
|
1081
|
+
{ name: "third_opt", percent: 23 },
|
1049
1082
|
],
|
1050
1083
|
}
|
1051
1084
|
ab_test :my_experiment
|
1052
1085
|
experiment = Split::Experiment.new(:my_experiment)
|
1053
|
-
expect(experiment.alternatives.collect{|a| [a.name, a.weight]}).to eq([[
|
1086
|
+
expect(experiment.alternatives.collect { |a| [a.name, a.weight] }).to eq([["control_opt", 0.67], ["second_opt", 0.1], ["third_opt", 0.23]])
|
1054
1087
|
end
|
1055
1088
|
|
1056
1089
|
it "accepts probability on some alternatives" do
|
1057
1090
|
Split.configuration.experiments[:my_experiment] = {
|
1058
|
-
:
|
1059
|
-
{ :
|
1091
|
+
alternatives: [
|
1092
|
+
{ name: "control_opt", percent: 34 },
|
1060
1093
|
"second_opt",
|
1061
|
-
{ :
|
1094
|
+
{ name: "third_opt", percent: 23 },
|
1062
1095
|
"fourth_opt",
|
1063
1096
|
],
|
1064
1097
|
}
|
1065
1098
|
ab_test :my_experiment
|
1066
1099
|
experiment = Split::Experiment.new(:my_experiment)
|
1067
|
-
names_and_weights = experiment.alternatives.collect{|a| [a.name, a.weight]}
|
1068
|
-
expect(names_and_weights).to eq([[
|
1069
|
-
expect(names_and_weights.inject(0){|sum, nw| sum + nw[1]}).to eq(1.0)
|
1100
|
+
names_and_weights = experiment.alternatives.collect { |a| [a.name, a.weight] }
|
1101
|
+
expect(names_and_weights).to eq([["control_opt", 0.34], ["second_opt", 0.215], ["third_opt", 0.23], ["fourth_opt", 0.215]])
|
1102
|
+
expect(names_and_weights.inject(0) { |sum, nw| sum + nw[1] }).to eq(1.0)
|
1070
1103
|
end
|
1071
1104
|
|
1072
1105
|
it "allows name param without probability" do
|
1073
1106
|
Split.configuration.experiments[:my_experiment] = {
|
1074
|
-
:
|
1075
|
-
{ :
|
1107
|
+
alternatives: [
|
1108
|
+
{ name: "control_opt" },
|
1076
1109
|
"second_opt",
|
1077
|
-
{ :
|
1110
|
+
{ name: "third_opt", percent: 64 },
|
1078
1111
|
],
|
1079
1112
|
}
|
1080
1113
|
ab_test :my_experiment
|
1081
1114
|
experiment = Split::Experiment.new(:my_experiment)
|
1082
|
-
names_and_weights = experiment.alternatives.collect{|a| [a.name, a.weight]}
|
1083
|
-
expect(names_and_weights).to eq([[
|
1084
|
-
expect(names_and_weights.inject(0){|sum, nw| sum + nw[1]}).to eq(1.0)
|
1115
|
+
names_and_weights = experiment.alternatives.collect { |a| [a.name, a.weight] }
|
1116
|
+
expect(names_and_weights).to eq([["control_opt", 0.18], ["second_opt", 0.18], ["third_opt", 0.64]])
|
1117
|
+
expect(names_and_weights.inject(0) { |sum, nw| sum + nw[1] }).to eq(1.0)
|
1085
1118
|
end
|
1086
1119
|
|
1087
1120
|
it "fails gracefully if config is missing experiment" do
|
1088
|
-
Split.configuration.experiments = { :
|
1089
|
-
expect
|
1121
|
+
Split.configuration.experiments = { other_experiment: { foo: "Bar" } }
|
1122
|
+
expect { ab_test :my_experiment }.to raise_error(Split::ExperimentNotFound)
|
1090
1123
|
end
|
1091
1124
|
|
1092
1125
|
it "fails gracefully if config is missing" do
|
1093
|
-
expect
|
1126
|
+
expect { Split.configuration.experiments = nil }.to raise_error(Split::InvalidExperimentsFormatError)
|
1094
1127
|
end
|
1095
1128
|
|
1096
1129
|
it "fails gracefully if config is missing alternatives" do
|
1097
|
-
Split.configuration.experiments[:my_experiment] = { :
|
1098
|
-
expect
|
1130
|
+
Split.configuration.experiments[:my_experiment] = { foo: "Bar" }
|
1131
|
+
expect { ab_test :my_experiment }.to raise_error(NoMethodError)
|
1099
1132
|
end
|
1100
1133
|
end
|
1101
1134
|
|
1102
|
-
it
|
1103
|
-
experiment2 = Split::ExperimentCatalog.find_or_create(
|
1104
|
-
ab_test(
|
1105
|
-
ab_test(
|
1106
|
-
ab_finished(
|
1135
|
+
it "should handle multiple experiments correctly" do
|
1136
|
+
experiment2 = Split::ExperimentCatalog.find_or_create("link_color2", "blue", "red")
|
1137
|
+
ab_test("link_color", "blue", "red")
|
1138
|
+
ab_test("link_color2", "blue", "red")
|
1139
|
+
ab_finished("link_color2")
|
1107
1140
|
|
1108
1141
|
experiment2.alternatives.each do |alt|
|
1109
1142
|
expect(alt.unfinished_count).to eq(0)
|
@@ -1112,8 +1145,8 @@ describe Split::Helper do
|
|
1112
1145
|
|
1113
1146
|
context "with goals" do
|
1114
1147
|
before do
|
1115
|
-
@experiment = {
|
1116
|
-
@alternatives = [
|
1148
|
+
@experiment = { "link_color" => ["purchase", "refund"] }
|
1149
|
+
@alternatives = ["blue", "red"]
|
1117
1150
|
@experiment_name, @goals = normalize_metric(@experiment)
|
1118
1151
|
@goal1 = @goals[0]
|
1119
1152
|
@goal2 = @goals[1]
|
@@ -1127,8 +1160,8 @@ describe Split::Helper do
|
|
1127
1160
|
describe "ab_test" do
|
1128
1161
|
it "should allow experiment goals interface as a single hash" do
|
1129
1162
|
ab_test(@experiment, *@alternatives)
|
1130
|
-
experiment = Split::ExperimentCatalog.find(
|
1131
|
-
expect(experiment.goals).to eq([
|
1163
|
+
experiment = Split::ExperimentCatalog.find("link_color")
|
1164
|
+
expect(experiment.goals).to eq(["purchase", "refund"])
|
1132
1165
|
end
|
1133
1166
|
end
|
1134
1167
|
|
@@ -1138,9 +1171,9 @@ describe Split::Helper do
|
|
1138
1171
|
end
|
1139
1172
|
|
1140
1173
|
it "should increment the counter for the specified-goal completed alternative" do
|
1141
|
-
expect{ ab_finished({"link_color" => ["purchase"]}) }
|
1142
|
-
.to change{ Split::Alternative.new(@alternative_name, @experiment_name).completed_count(@goal2) }.by(0)
|
1143
|
-
.and change{ Split::Alternative.new(@alternative_name, @experiment_name).completed_count(@goal1) }.by(1)
|
1174
|
+
expect { ab_finished({ "link_color" => ["purchase"] }) }
|
1175
|
+
.to change { Split::Alternative.new(@alternative_name, @experiment_name).completed_count(@goal2) }.by(0)
|
1176
|
+
.and change { Split::Alternative.new(@alternative_name, @experiment_name).completed_count(@goal1) }.by(1)
|
1144
1177
|
end
|
1145
1178
|
end
|
1146
1179
|
end
|