split 4.0.1 → 4.0.3
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/.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
|