split 0.7.2 → 0.7.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/.travis.yml +1 -0
- data/Appraisals +1 -5
- data/CHANGELOG.mdown +34 -2
- data/README.mdown +18 -5
- data/gemfiles/3.0.gemfile +1 -2
- data/gemfiles/3.0.gemfile.lock +59 -31
- data/gemfiles/3.1.gemfile +1 -2
- data/gemfiles/3.1.gemfile.lock +56 -31
- data/gemfiles/3.2.gemfile +1 -2
- data/gemfiles/4.0.gemfile +1 -2
- data/lib/split/dashboard/helpers.rb +4 -0
- data/lib/split/dashboard/views/_experiment.erb +1 -1
- data/lib/split/helper.rb +11 -3
- data/lib/split/version.rb +1 -1
- data/spec/algorithms/weighted_sample_spec.rb +4 -4
- data/spec/algorithms/whiplash_spec.rb +8 -8
- data/spec/alternative_spec.rb +51 -51
- data/spec/configuration_spec.rb +26 -26
- data/spec/dashboard_helpers_spec.rb +7 -7
- data/spec/dashboard_spec.rb +21 -20
- data/spec/experiment_spec.rb +63 -63
- data/spec/helper_spec.rb +164 -145
- data/spec/metric_spec.rb +3 -3
- data/spec/persistence/cookie_adapter_spec.rb +5 -5
- data/spec/persistence/redis_adapter_spec.rb +7 -7
- data/spec/persistence/session_adapter_spec.rb +4 -4
- data/spec/persistence_spec.rb +8 -8
- data/spec/trial_spec.rb +14 -14
- data/split.gemspec +3 -3
- metadata +8 -10
- data/gemfiles/3.2.gemfile.lock +0 -123
- data/gemfiles/4.0.gemfile.lock +0 -118
data/spec/helper_spec.rb
CHANGED
@@ -11,32 +11,32 @@ describe Split::Helper do
|
|
11
11
|
|
12
12
|
describe "ab_test" do
|
13
13
|
it "should not raise an error when passed strings for alternatives" do
|
14
|
-
lambda { ab_test('xyz', '1', '2', '3') }.
|
14
|
+
expect(lambda { ab_test('xyz', '1', '2', '3') }).not_to raise_error
|
15
15
|
end
|
16
16
|
|
17
17
|
it "should not raise an error when passed an array for alternatives" do
|
18
|
-
lambda { ab_test('xyz', ['1', '2', '3']) }.
|
18
|
+
expect(lambda { ab_test('xyz', ['1', '2', '3']) }).not_to raise_error
|
19
19
|
end
|
20
20
|
|
21
21
|
it "should raise the appropriate error when passed integers for alternatives" do
|
22
|
-
lambda { ab_test('xyz', 1, 2, 3) }.
|
22
|
+
expect(lambda { ab_test('xyz', 1, 2, 3) }).to raise_error
|
23
23
|
end
|
24
24
|
|
25
25
|
it "should raise the appropriate error when passed symbols for alternatives" do
|
26
|
-
lambda { ab_test('xyz', :a, :b, :c) }.
|
26
|
+
expect(lambda { ab_test('xyz', :a, :b, :c) }).to raise_error
|
27
27
|
end
|
28
28
|
|
29
29
|
it "should not raise error when passed an array for goals" do
|
30
|
-
lambda { ab_test({'link_color' => ["purchase", "refund"]}, 'blue', 'red') }.
|
30
|
+
expect(lambda { ab_test({'link_color' => ["purchase", "refund"]}, 'blue', 'red') }).not_to raise_error
|
31
31
|
end
|
32
32
|
|
33
33
|
it "should not raise error when passed just one goal" do
|
34
|
-
lambda { ab_test({'link_color' => "purchase"}, 'blue', 'red') }.
|
34
|
+
expect(lambda { ab_test({'link_color' => "purchase"}, 'blue', 'red') }).not_to raise_error
|
35
35
|
end
|
36
36
|
|
37
37
|
it "should assign a random alternative to a new user when there are an equal number of alternatives assigned" do
|
38
38
|
ab_test('link_color', 'blue', 'red')
|
39
|
-
['red', 'blue'].
|
39
|
+
expect(['red', 'blue']).to include(ab_user['link_color'])
|
40
40
|
end
|
41
41
|
|
42
42
|
it "should increment the participation counter after assignment to a new user" do
|
@@ -48,68 +48,86 @@ describe Split::Helper do
|
|
48
48
|
new_red_count = Split::Alternative.new('red', 'link_color').participant_count
|
49
49
|
new_blue_count = Split::Alternative.new('blue', 'link_color').participant_count
|
50
50
|
|
51
|
-
(new_red_count + new_blue_count).
|
51
|
+
expect((new_red_count + new_blue_count)).to eq(previous_red_count + previous_blue_count + 1)
|
52
52
|
end
|
53
53
|
|
54
54
|
it 'should not increment the counter for an experiment that the user is not participating in' do
|
55
55
|
ab_test('link_color', 'blue', 'red')
|
56
56
|
e = Split::Experiment.find_or_create('button_size', 'small', 'big')
|
57
|
-
lambda {
|
57
|
+
expect(lambda {
|
58
58
|
# User shouldn't participate in this second experiment
|
59
59
|
ab_test('button_size', 'small', 'big')
|
60
|
-
}.
|
60
|
+
}).not_to change { e.participant_count }
|
61
61
|
end
|
62
62
|
|
63
63
|
it 'should not increment the counter for an ended experiment' do
|
64
64
|
e = Split::Experiment.find_or_create('button_size', 'small', 'big')
|
65
65
|
e.winner = 'small'
|
66
|
-
lambda {
|
66
|
+
expect(lambda {
|
67
67
|
a = ab_test('button_size', 'small', 'big')
|
68
|
-
a.
|
69
|
-
}.
|
68
|
+
expect(a).to eq('small')
|
69
|
+
}).not_to change { e.participant_count }
|
70
70
|
end
|
71
71
|
|
72
72
|
it 'should not increment the counter for an not started experiment' do
|
73
|
-
Split.configuration.
|
73
|
+
expect(Split.configuration).to receive(:start_manually).and_return(true)
|
74
74
|
e = Split::Experiment.find_or_create('button_size', 'small', 'big')
|
75
|
-
lambda {
|
75
|
+
expect(lambda {
|
76
76
|
a = ab_test('button_size', 'small', 'big')
|
77
|
-
a.
|
78
|
-
}.
|
77
|
+
expect(a).to eq('small')
|
78
|
+
}).not_to change { e.participant_count }
|
79
79
|
end
|
80
80
|
|
81
81
|
it "should return the given alternative for an existing user" do
|
82
|
-
ab_test('link_color', 'blue', 'red').
|
82
|
+
expect(ab_test('link_color', 'blue', 'red')).to eq ab_test('link_color', 'blue', 'red')
|
83
83
|
end
|
84
84
|
|
85
85
|
it 'should always return the winner if one is present' do
|
86
86
|
experiment.winner = "orange"
|
87
87
|
|
88
|
-
ab_test('link_color', 'blue', 'red').
|
88
|
+
expect(ab_test('link_color', 'blue', 'red')).to eq('orange')
|
89
89
|
end
|
90
90
|
|
91
91
|
it "should allow the alternative to be force by passing it in the params" do
|
92
92
|
@params = {'link_color' => 'blue'}
|
93
93
|
alternative = ab_test('link_color', 'blue', 'red')
|
94
|
-
alternative.
|
94
|
+
expect(alternative).to eq('blue')
|
95
95
|
alternative = ab_test('link_color', {'blue' => 1}, 'red' => 5)
|
96
|
-
alternative.
|
96
|
+
expect(alternative).to eq('blue')
|
97
97
|
@params = {'link_color' => 'red'}
|
98
98
|
alternative = ab_test('link_color', 'blue', 'red')
|
99
|
-
alternative.
|
99
|
+
expect(alternative).to eq('red')
|
100
100
|
alternative = ab_test('link_color', {'blue' => 5}, 'red' => 1)
|
101
|
-
alternative.
|
101
|
+
expect(alternative).to eq('red')
|
102
102
|
end
|
103
103
|
|
104
104
|
it "should not allow an arbitrary alternative" do
|
105
105
|
@params = {'link_color' => 'pink'}
|
106
106
|
alternative = ab_test('link_color', 'blue')
|
107
|
-
alternative.
|
107
|
+
expect(alternative).to eq('blue')
|
108
108
|
end
|
109
109
|
|
110
110
|
it "should not store the split when a param forced alternative" do
|
111
111
|
@params = {'link_color' => 'blue'}
|
112
|
-
ab_user.
|
112
|
+
expect(ab_user).not_to receive(:[]=)
|
113
|
+
ab_test('link_color', 'blue', 'red')
|
114
|
+
end
|
115
|
+
|
116
|
+
it "SPLIT_DISABLE query parameter should also force the alternative (uses control)" do
|
117
|
+
@params = {'SPLIT_DISABLE' => 'true'}
|
118
|
+
alternative = ab_test('link_color', 'blue', 'red')
|
119
|
+
expect(alternative).to eq('blue')
|
120
|
+
alternative = ab_test('link_color', {'blue' => 1}, 'red' => 5)
|
121
|
+
expect(alternative).to eq('blue')
|
122
|
+
alternative = ab_test('link_color', 'red', 'blue')
|
123
|
+
expect(alternative).to eq('red')
|
124
|
+
alternative = ab_test('link_color', {'red' => 5}, 'blue' => 1)
|
125
|
+
expect(alternative).to eq('red')
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should not store the split when Split generically disabled" do
|
129
|
+
@params = {'SPLIT_DISABLE' => 'true'}
|
130
|
+
expect(ab_user).not_to receive(:[]=)
|
113
131
|
ab_test('link_color', 'blue', 'red')
|
114
132
|
end
|
115
133
|
|
@@ -118,7 +136,7 @@ describe Split::Helper do
|
|
118
136
|
|
119
137
|
it "should store the forced alternative" do
|
120
138
|
@params = {'link_color' => 'blue'}
|
121
|
-
ab_user.
|
139
|
+
expect(ab_user).to receive(:[]=).with('link_color', 'blue')
|
122
140
|
ab_test('link_color', 'blue', 'red')
|
123
141
|
end
|
124
142
|
end
|
@@ -126,7 +144,7 @@ describe Split::Helper do
|
|
126
144
|
context "when on_trial_choose is set" do
|
127
145
|
before { Split.configuration.on_trial_choose = :some_method }
|
128
146
|
it "should call the method" do
|
129
|
-
self.
|
147
|
+
expect(self).to receive(:some_method)
|
130
148
|
ab_test('link_color', 'blue', 'red')
|
131
149
|
end
|
132
150
|
end
|
@@ -134,30 +152,30 @@ describe Split::Helper do
|
|
134
152
|
it "should allow passing a block" do
|
135
153
|
alt = ab_test('link_color', 'blue', 'red')
|
136
154
|
ret = ab_test('link_color', 'blue', 'red') { |alternative| "shared/#{alternative}" }
|
137
|
-
ret.
|
155
|
+
expect(ret).to eq("shared/#{alt}")
|
138
156
|
end
|
139
157
|
|
140
158
|
it "should allow the share of visitors see an alternative to be specified" do
|
141
159
|
ab_test('link_color', {'blue' => 0.8}, {'red' => 20})
|
142
|
-
['red', 'blue'].
|
160
|
+
expect(['red', 'blue']).to include(ab_user['link_color'])
|
143
161
|
end
|
144
162
|
|
145
163
|
it "should allow alternative weighting interface as a single hash" do
|
146
164
|
ab_test('link_color', {'blue' => 0.01}, 'red' => 0.2)
|
147
165
|
experiment = Split::Experiment.find('link_color')
|
148
|
-
experiment.alternatives.map(&:name).
|
166
|
+
expect(experiment.alternatives.map(&:name)).to eq(['blue', 'red'])
|
149
167
|
# TODO: persist alternative weights
|
150
|
-
# experiment.alternatives.collect{|a| a.weight}.
|
168
|
+
# expect(experiment.alternatives.collect{|a| a.weight}).to eq([0.01, 0.2])
|
151
169
|
end
|
152
170
|
|
153
171
|
it "should only let a user participate in one experiment at a time" do
|
154
172
|
link_color = ab_test('link_color', 'blue', 'red')
|
155
173
|
ab_test('button_size', 'small', 'big')
|
156
|
-
ab_user.
|
174
|
+
expect(ab_user).to eq({'link_color' => link_color})
|
157
175
|
big = Split::Alternative.new('big', 'button_size')
|
158
|
-
big.participant_count.
|
176
|
+
expect(big.participant_count).to eq(0)
|
159
177
|
small = Split::Alternative.new('small', 'button_size')
|
160
|
-
small.participant_count.
|
178
|
+
expect(small.participant_count).to eq(0)
|
161
179
|
end
|
162
180
|
|
163
181
|
it "should let a user participate in many experiment with allow_multiple_experiments option" do
|
@@ -166,9 +184,9 @@ describe Split::Helper do
|
|
166
184
|
end
|
167
185
|
link_color = ab_test('link_color', 'blue', 'red')
|
168
186
|
button_size = ab_test('button_size', 'small', 'big')
|
169
|
-
ab_user.
|
187
|
+
expect(ab_user).to eq({'link_color' => link_color, 'button_size' => button_size})
|
170
188
|
button_size_alt = Split::Alternative.new(button_size, 'button_size')
|
171
|
-
button_size_alt.participant_count.
|
189
|
+
expect(button_size_alt.participant_count).to eq(1)
|
172
190
|
end
|
173
191
|
|
174
192
|
it "should not over-write a finished key when an experiment is on a later version" do
|
@@ -176,7 +194,7 @@ describe Split::Helper do
|
|
176
194
|
ab_user = { experiment.key => 'blue', experiment.finished_key => true }
|
177
195
|
finshed_session = ab_user.dup
|
178
196
|
ab_test('link_color', 'blue', 'red')
|
179
|
-
ab_user.
|
197
|
+
expect(ab_user).to eq(finshed_session)
|
180
198
|
end
|
181
199
|
end
|
182
200
|
|
@@ -192,18 +210,18 @@ describe Split::Helper do
|
|
192
210
|
it 'should increment the counter for the completed alternative' do
|
193
211
|
finished(@experiment_name)
|
194
212
|
new_completion_count = Split::Alternative.new(@alternative_name, @experiment_name).completed_count
|
195
|
-
new_completion_count.
|
213
|
+
expect(new_completion_count).to eq(@previous_completion_count + 1)
|
196
214
|
end
|
197
215
|
|
198
216
|
it "should set experiment's finished key if reset is false" do
|
199
217
|
finished(@experiment_name, {:reset => false})
|
200
|
-
ab_user.
|
218
|
+
expect(ab_user).to eq(@experiment.key => @alternative_name, @experiment.finished_key => true)
|
201
219
|
end
|
202
220
|
|
203
221
|
it 'should not increment the counter if reset is false and the experiment has been already finished' do
|
204
222
|
2.times { finished(@experiment_name, {:reset => false}) }
|
205
223
|
new_completion_count = Split::Alternative.new(@alternative_name, @experiment_name).completed_count
|
206
|
-
new_completion_count.
|
224
|
+
expect(new_completion_count).to eq(@previous_completion_count + 1)
|
207
225
|
end
|
208
226
|
|
209
227
|
it 'should not increment the counter for an experiment that the user is not participating in' do
|
@@ -213,69 +231,69 @@ describe Split::Helper do
|
|
213
231
|
# receive the control for button_size. As the user is not participating in
|
214
232
|
# the button size experiment, finishing it should not increase the
|
215
233
|
# completion count for that alternative.
|
216
|
-
lambda {
|
234
|
+
expect(lambda {
|
217
235
|
finished('button_size')
|
218
|
-
}.
|
236
|
+
}).not_to change { Split::Alternative.new('small', 'button_size').completed_count }
|
219
237
|
end
|
220
238
|
|
221
239
|
it 'should not increment the counter for an ended experiment' do
|
222
240
|
e = Split::Experiment.find_or_create('button_size', 'small', 'big')
|
223
241
|
e.winner = 'small'
|
224
242
|
a = ab_test('button_size', 'small', 'big')
|
225
|
-
a.
|
226
|
-
lambda {
|
243
|
+
expect(a).to eq('small')
|
244
|
+
expect(lambda {
|
227
245
|
finished('button_size')
|
228
|
-
}.
|
246
|
+
}).not_to change { Split::Alternative.new(a, 'button_size').completed_count }
|
229
247
|
end
|
230
248
|
|
231
249
|
it "should clear out the user's participation from their session" do
|
232
|
-
ab_user.
|
250
|
+
expect(ab_user).to eq(@experiment.key => @alternative_name)
|
233
251
|
finished(@experiment_name)
|
234
|
-
ab_user.
|
252
|
+
expect(ab_user).to eq({})
|
235
253
|
end
|
236
254
|
|
237
255
|
it "should not clear out the users session if reset is false" do
|
238
|
-
ab_user.
|
256
|
+
expect(ab_user).to eq(@experiment.key => @alternative_name)
|
239
257
|
finished(@experiment_name, {:reset => false})
|
240
|
-
ab_user.
|
258
|
+
expect(ab_user).to eq(@experiment.key => @alternative_name, @experiment.finished_key => true)
|
241
259
|
end
|
242
260
|
|
243
261
|
it "should reset the users session when experiment is not versioned" do
|
244
|
-
ab_user.
|
262
|
+
expect(ab_user).to eq(@experiment.key => @alternative_name)
|
245
263
|
finished(@experiment_name)
|
246
|
-
ab_user.
|
264
|
+
expect(ab_user).to eq({})
|
247
265
|
end
|
248
266
|
|
249
267
|
it "should reset the users session when experiment is versioned" do
|
250
268
|
@experiment.increment_version
|
251
269
|
@alternative_name = ab_test(@experiment_name, *@alternatives)
|
252
270
|
|
253
|
-
ab_user.
|
271
|
+
expect(ab_user).to eq(@experiment.key => @alternative_name)
|
254
272
|
finished(@experiment_name)
|
255
|
-
ab_user.
|
273
|
+
expect(ab_user).to eq({})
|
256
274
|
end
|
257
275
|
|
258
276
|
it "should do nothing where the experiment was not started by this user" do
|
259
277
|
ab_user = nil
|
260
|
-
lambda { finished('some_experiment_not_started_by_the_user') }.
|
278
|
+
expect(lambda { finished('some_experiment_not_started_by_the_user') }).not_to raise_exception
|
261
279
|
end
|
262
280
|
|
263
281
|
it 'should not be doing other tests when it has completed one that has :reset => false' do
|
264
282
|
ab_user[@experiment.key] = @alternative_name
|
265
283
|
ab_user[@experiment.finished_key] = true
|
266
|
-
doing_other_tests?(@experiment.key).
|
284
|
+
expect(doing_other_tests?(@experiment.key)).to be false
|
267
285
|
end
|
268
286
|
|
269
287
|
context "when on_trial_complete is set" do
|
270
288
|
before { Split.configuration.on_trial_complete = :some_method }
|
271
289
|
it "should call the method" do
|
272
|
-
self.
|
290
|
+
expect(self).to receive(:some_method)
|
273
291
|
finished(@experiment_name)
|
274
292
|
end
|
275
293
|
|
276
294
|
it "should not call the method without alternative" do
|
277
295
|
ab_user[@experiment.key] = nil
|
278
|
-
self.
|
296
|
+
expect(self).not_to receive(:some_method)
|
279
297
|
finished(@experiment_name)
|
280
298
|
end
|
281
299
|
end
|
@@ -293,25 +311,25 @@ describe Split::Helper do
|
|
293
311
|
experiment = Split::Experiment.find :my_experiment
|
294
312
|
|
295
313
|
finished :my_experiment
|
296
|
-
ab_user.
|
314
|
+
expect(ab_user).to eq(experiment.key => alternative, experiment.finished_key => true)
|
297
315
|
end
|
298
316
|
end
|
299
317
|
|
300
318
|
context "finished with metric name" do
|
301
319
|
before { Split.configuration.experiments = {} }
|
302
|
-
before { Split::Alternative.
|
320
|
+
before { expect(Split::Alternative).to receive(:new).at_least(1).times.and_call_original }
|
303
321
|
|
304
322
|
def should_finish_experiment(experiment_name, should_finish=true)
|
305
323
|
alts = Split.configuration.experiments[experiment_name][:alternatives]
|
306
324
|
experiment = Split::Experiment.find_or_create(experiment_name, *alts)
|
307
325
|
alt_name = ab_user[experiment.key] = alts.first
|
308
326
|
alt = double('alternative')
|
309
|
-
alt.
|
310
|
-
Split::Alternative.
|
327
|
+
expect(alt).to receive(:name).at_most(1).times.and_return(alt_name)
|
328
|
+
expect(Split::Alternative).to receive(:new).at_most(1).times.with(alt_name, experiment_name.to_s).and_return(alt)
|
311
329
|
if should_finish
|
312
|
-
alt.
|
330
|
+
expect(alt).to receive(:increment_completion).at_most(1).times
|
313
331
|
else
|
314
|
-
alt.
|
332
|
+
expect(alt).not_to receive(:increment_completion)
|
315
333
|
end
|
316
334
|
end
|
317
335
|
|
@@ -357,8 +375,8 @@ describe Split::Helper do
|
|
357
375
|
exp = Split::Experiment.find :my_exp
|
358
376
|
|
359
377
|
finished :my_metric
|
360
|
-
ab_user[exp.key].
|
361
|
-
ab_user[exp.finished_key].
|
378
|
+
expect(ab_user[exp.key]).to eq(alternative_name)
|
379
|
+
expect(ab_user[exp.finished_key]).to be_truthy
|
362
380
|
end
|
363
381
|
|
364
382
|
it "passes through options" do
|
@@ -372,8 +390,8 @@ describe Split::Helper do
|
|
372
390
|
exp = Split::Experiment.find :my_exp
|
373
391
|
|
374
392
|
finished :my_metric, :reset => false
|
375
|
-
ab_user[exp.key].
|
376
|
-
ab_user[exp.finished_key].
|
393
|
+
expect(ab_user[exp.key]).to eq(alternative_name)
|
394
|
+
expect(ab_user[exp.finished_key]).to be_truthy
|
377
395
|
end
|
378
396
|
end
|
379
397
|
|
@@ -382,12 +400,12 @@ describe Split::Helper do
|
|
382
400
|
alternative_name = ab_test('link_color', 'blue', 'red')
|
383
401
|
|
384
402
|
previous_convertion_rate = Split::Alternative.new(alternative_name, 'link_color').conversion_rate
|
385
|
-
previous_convertion_rate.
|
403
|
+
expect(previous_convertion_rate).to eq(0.0)
|
386
404
|
|
387
405
|
finished('link_color')
|
388
406
|
|
389
407
|
new_convertion_rate = Split::Alternative.new(alternative_name, 'link_color').conversion_rate
|
390
|
-
new_convertion_rate.
|
408
|
+
expect(new_convertion_rate).to eq(1.0)
|
391
409
|
end
|
392
410
|
end
|
393
411
|
|
@@ -399,7 +417,7 @@ describe Split::Helper do
|
|
399
417
|
describe 'ab_test' do
|
400
418
|
it 'should return the control' do
|
401
419
|
alternative = ab_test('link_color', 'blue', 'red')
|
402
|
-
alternative.
|
420
|
+
expect(alternative).to eq experiment.control.name
|
403
421
|
end
|
404
422
|
|
405
423
|
it "should not increment the participation count" do
|
@@ -412,7 +430,7 @@ describe Split::Helper do
|
|
412
430
|
new_red_count = Split::Alternative.new('red', 'link_color').participant_count
|
413
431
|
new_blue_count = Split::Alternative.new('blue', 'link_color').participant_count
|
414
432
|
|
415
|
-
(new_red_count + new_blue_count).
|
433
|
+
expect((new_red_count + new_blue_count)).to eq(previous_red_count + previous_blue_count)
|
416
434
|
end
|
417
435
|
end
|
418
436
|
|
@@ -426,7 +444,7 @@ describe Split::Helper do
|
|
426
444
|
|
427
445
|
new_completion_count = Split::Alternative.new(alternative_name, 'link_color').completed_count
|
428
446
|
|
429
|
-
new_completion_count.
|
447
|
+
expect(new_completion_count).to eq(previous_completion_count)
|
430
448
|
end
|
431
449
|
end
|
432
450
|
end
|
@@ -445,7 +463,7 @@ describe Split::Helper do
|
|
445
463
|
|
446
464
|
red_count = Split::Alternative.new('red', 'link_color').participant_count
|
447
465
|
blue_count = Split::Alternative.new('blue', 'link_color').participant_count
|
448
|
-
(red_count + blue_count).
|
466
|
+
expect((red_count + blue_count)).to be(0)
|
449
467
|
end
|
450
468
|
end
|
451
469
|
end
|
@@ -454,7 +472,7 @@ describe Split::Helper do
|
|
454
472
|
describe 'ab_test' do
|
455
473
|
it 'should return the control' do
|
456
474
|
alternative = ab_test('link_color', 'blue', 'red')
|
457
|
-
alternative.
|
475
|
+
expect(alternative).to eq experiment.control.name
|
458
476
|
end
|
459
477
|
|
460
478
|
it "should not increment the participation count" do
|
@@ -466,7 +484,7 @@ describe Split::Helper do
|
|
466
484
|
new_red_count = Split::Alternative.new('red', 'link_color').participant_count
|
467
485
|
new_blue_count = Split::Alternative.new('blue', 'link_color').participant_count
|
468
486
|
|
469
|
-
(new_red_count + new_blue_count).
|
487
|
+
expect((new_red_count + new_blue_count)).to eq(previous_red_count + previous_blue_count)
|
470
488
|
end
|
471
489
|
end
|
472
490
|
|
@@ -480,7 +498,7 @@ describe Split::Helper do
|
|
480
498
|
|
481
499
|
new_completion_count = Split::Alternative.new(alternative_name, 'link_color').completed_count
|
482
500
|
|
483
|
-
new_completion_count.
|
501
|
+
expect(new_completion_count).to eq(previous_completion_count)
|
484
502
|
end
|
485
503
|
end
|
486
504
|
end
|
@@ -524,75 +542,75 @@ describe Split::Helper do
|
|
524
542
|
describe 'versioned experiments' do
|
525
543
|
it "should use version zero if no version is present" do
|
526
544
|
alternative_name = ab_test('link_color', 'blue', 'red')
|
527
|
-
experiment.version.
|
528
|
-
ab_user.
|
545
|
+
expect(experiment.version).to eq(0)
|
546
|
+
expect(ab_user).to eq({'link_color' => alternative_name})
|
529
547
|
end
|
530
548
|
|
531
549
|
it "should save the version of the experiment to the session" do
|
532
550
|
experiment.reset
|
533
|
-
experiment.version.
|
551
|
+
expect(experiment.version).to eq(1)
|
534
552
|
alternative_name = ab_test('link_color', 'blue', 'red')
|
535
|
-
ab_user.
|
553
|
+
expect(ab_user).to eq({'link_color:1' => alternative_name})
|
536
554
|
end
|
537
555
|
|
538
556
|
it "should load the experiment even if the version is not 0" do
|
539
557
|
experiment.reset
|
540
|
-
experiment.version.
|
558
|
+
expect(experiment.version).to eq(1)
|
541
559
|
alternative_name = ab_test('link_color', 'blue', 'red')
|
542
|
-
ab_user.
|
560
|
+
expect(ab_user).to eq({'link_color:1' => alternative_name})
|
543
561
|
return_alternative_name = ab_test('link_color', 'blue', 'red')
|
544
|
-
return_alternative_name.
|
562
|
+
expect(return_alternative_name).to eq(alternative_name)
|
545
563
|
end
|
546
564
|
|
547
565
|
it "should reset the session of a user on an older version of the experiment" do
|
548
566
|
alternative_name = ab_test('link_color', 'blue', 'red')
|
549
|
-
ab_user.
|
567
|
+
expect(ab_user).to eq({'link_color' => alternative_name})
|
550
568
|
alternative = Split::Alternative.new(alternative_name, 'link_color')
|
551
|
-
alternative.participant_count.
|
569
|
+
expect(alternative.participant_count).to eq(1)
|
552
570
|
|
553
571
|
experiment.reset
|
554
|
-
experiment.version.
|
572
|
+
expect(experiment.version).to eq(1)
|
555
573
|
alternative = Split::Alternative.new(alternative_name, 'link_color')
|
556
|
-
alternative.participant_count.
|
574
|
+
expect(alternative.participant_count).to eq(0)
|
557
575
|
|
558
576
|
new_alternative_name = ab_test('link_color', 'blue', 'red')
|
559
|
-
ab_user['link_color:1'].
|
577
|
+
expect(ab_user['link_color:1']).to eq(new_alternative_name)
|
560
578
|
new_alternative = Split::Alternative.new(new_alternative_name, 'link_color')
|
561
|
-
new_alternative.participant_count.
|
579
|
+
expect(new_alternative.participant_count).to eq(1)
|
562
580
|
end
|
563
581
|
|
564
582
|
it "should cleanup old versions of experiments from the session" do
|
565
583
|
alternative_name = ab_test('link_color', 'blue', 'red')
|
566
|
-
ab_user.
|
584
|
+
expect(ab_user).to eq({'link_color' => alternative_name})
|
567
585
|
alternative = Split::Alternative.new(alternative_name, 'link_color')
|
568
|
-
alternative.participant_count.
|
586
|
+
expect(alternative.participant_count).to eq(1)
|
569
587
|
|
570
588
|
experiment.reset
|
571
|
-
experiment.version.
|
589
|
+
expect(experiment.version).to eq(1)
|
572
590
|
alternative = Split::Alternative.new(alternative_name, 'link_color')
|
573
|
-
alternative.participant_count.
|
591
|
+
expect(alternative.participant_count).to eq(0)
|
574
592
|
|
575
593
|
new_alternative_name = ab_test('link_color', 'blue', 'red')
|
576
|
-
ab_user.
|
594
|
+
expect(ab_user).to eq({'link_color:1' => new_alternative_name})
|
577
595
|
end
|
578
596
|
|
579
597
|
it "should only count completion of users on the current version" do
|
580
598
|
alternative_name = ab_test('link_color', 'blue', 'red')
|
581
|
-
ab_user.
|
599
|
+
expect(ab_user).to eq({'link_color' => alternative_name})
|
582
600
|
alternative = Split::Alternative.new(alternative_name, 'link_color')
|
583
601
|
|
584
602
|
experiment.reset
|
585
|
-
experiment.version.
|
603
|
+
expect(experiment.version).to eq(1)
|
586
604
|
|
587
605
|
finished('link_color')
|
588
606
|
alternative = Split::Alternative.new(alternative_name, 'link_color')
|
589
|
-
alternative.completed_count.
|
607
|
+
expect(alternative.completed_count).to eq(0)
|
590
608
|
end
|
591
609
|
end
|
592
610
|
|
593
611
|
context 'when redis is not available' do
|
594
612
|
before(:each) do
|
595
|
-
Split.
|
613
|
+
expect(Split).to receive(:redis).at_most(5).times.and_raise(Errno::ECONNREFUSED.new)
|
596
614
|
end
|
597
615
|
|
598
616
|
context 'and db_failover config option is turned off' do
|
@@ -604,13 +622,13 @@ describe Split::Helper do
|
|
604
622
|
|
605
623
|
describe 'ab_test' do
|
606
624
|
it 'should raise an exception' do
|
607
|
-
lambda { ab_test('link_color', 'blue', 'red') }.
|
625
|
+
expect(lambda { ab_test('link_color', 'blue', 'red') }).to raise_error
|
608
626
|
end
|
609
627
|
end
|
610
628
|
|
611
629
|
describe 'finished' do
|
612
630
|
it 'should raise an exception' do
|
613
|
-
lambda { finished('link_color') }.
|
631
|
+
expect(lambda { finished('link_color') }).to raise_error
|
614
632
|
end
|
615
633
|
end
|
616
634
|
|
@@ -622,12 +640,12 @@ describe Split::Helper do
|
|
622
640
|
end
|
623
641
|
|
624
642
|
it "should not attempt to connect to redis" do
|
625
|
-
lambda { ab_test('link_color', 'blue', 'red') }.
|
643
|
+
expect(lambda { ab_test('link_color', 'blue', 'red') }).not_to raise_error
|
626
644
|
end
|
627
645
|
|
628
646
|
it "should return control variable" do
|
629
|
-
ab_test('link_color', 'blue', 'red').
|
630
|
-
lambda { finished('link_color') }.
|
647
|
+
expect(ab_test('link_color', 'blue', 'red')).to eq('blue')
|
648
|
+
expect(lambda { finished('link_color') }).not_to raise_error
|
631
649
|
end
|
632
650
|
end
|
633
651
|
end
|
@@ -641,26 +659,27 @@ describe Split::Helper do
|
|
641
659
|
|
642
660
|
describe 'ab_test' do
|
643
661
|
it 'should not raise an exception' do
|
644
|
-
lambda { ab_test('link_color', 'blue', 'red') }.
|
662
|
+
expect(lambda { ab_test('link_color', 'blue', 'red') }).not_to raise_error
|
645
663
|
end
|
646
664
|
|
647
665
|
it 'should call db_failover_on_db_error proc with error as parameter' do
|
648
666
|
Split.configure do |config|
|
649
667
|
config.db_failover_on_db_error = proc do |error|
|
650
|
-
error.
|
668
|
+
expect(error).to be_a(Errno::ECONNREFUSED)
|
651
669
|
end
|
652
670
|
end
|
653
|
-
|
671
|
+
|
672
|
+
expect(Split.configuration.db_failover_on_db_error).to receive(:call)
|
654
673
|
ab_test('link_color', 'blue', 'red')
|
655
674
|
end
|
656
675
|
|
657
676
|
it 'should always use first alternative' do
|
658
|
-
ab_test('link_color', 'blue', 'red').
|
659
|
-
ab_test('link_color', {'blue' => 0.01}, 'red' => 0.2).
|
660
|
-
ab_test('link_color', {'blue' => 0.8}, {'red' => 20}).
|
661
|
-
ab_test('link_color', 'blue', 'red') do |alternative|
|
677
|
+
expect(ab_test('link_color', 'blue', 'red')).to eq('blue')
|
678
|
+
expect(ab_test('link_color', {'blue' => 0.01}, 'red' => 0.2)).to eq('blue')
|
679
|
+
expect(ab_test('link_color', {'blue' => 0.8}, {'red' => 20})).to eq('blue')
|
680
|
+
expect(ab_test('link_color', 'blue', 'red') do |alternative|
|
662
681
|
"shared/#{alternative}"
|
663
|
-
end.
|
682
|
+
end).to eq('shared/blue')
|
664
683
|
end
|
665
684
|
|
666
685
|
context 'and db_failover_allow_parameter_override config option is turned on' do
|
@@ -673,13 +692,13 @@ describe Split::Helper do
|
|
673
692
|
context 'and given an override parameter' do
|
674
693
|
it 'should use given override instead of the first alternative' do
|
675
694
|
@params = {'link_color' => 'red'}
|
676
|
-
ab_test('link_color', 'blue', 'red').
|
677
|
-
ab_test('link_color', 'blue', 'red', 'green').
|
678
|
-
ab_test('link_color', {'blue' => 0.01}, 'red' => 0.2).
|
679
|
-
ab_test('link_color', {'blue' => 0.8}, {'red' => 20}).
|
680
|
-
ab_test('link_color', 'blue', 'red') do |alternative|
|
695
|
+
expect(ab_test('link_color', 'blue', 'red')).to eq('red')
|
696
|
+
expect(ab_test('link_color', 'blue', 'red', 'green')).to eq('red')
|
697
|
+
expect(ab_test('link_color', {'blue' => 0.01}, 'red' => 0.2)).to eq('red')
|
698
|
+
expect(ab_test('link_color', {'blue' => 0.8}, {'red' => 20})).to eq('red')
|
699
|
+
expect(ab_test('link_color', 'blue', 'red') do |alternative|
|
681
700
|
"shared/#{alternative}"
|
682
|
-
end.
|
701
|
+
end).to eq('shared/red')
|
683
702
|
end
|
684
703
|
end
|
685
704
|
end
|
@@ -692,24 +711,24 @@ describe Split::Helper do
|
|
692
711
|
end
|
693
712
|
|
694
713
|
it "uses first alternative" do
|
695
|
-
ab_test(:link_color).
|
714
|
+
expect(ab_test(:link_color)).to eq("blue")
|
696
715
|
end
|
697
716
|
end
|
698
717
|
end
|
699
718
|
|
700
719
|
describe 'finished' do
|
701
720
|
it 'should not raise an exception' do
|
702
|
-
lambda { finished('link_color') }.
|
721
|
+
expect(lambda { finished('link_color') }).not_to raise_error
|
703
722
|
end
|
704
723
|
|
705
724
|
it 'should call db_failover_on_db_error proc with error as parameter' do
|
706
725
|
Split.configure do |config|
|
707
726
|
config.db_failover_on_db_error = proc do |error|
|
708
|
-
error.
|
727
|
+
expect(error).to be_a(Errno::ECONNREFUSED)
|
709
728
|
end
|
710
729
|
end
|
711
730
|
|
712
|
-
Split.configuration.db_failover_on_db_error.
|
731
|
+
expect(Split.configuration.db_failover_on_db_error).to receive(:call)
|
713
732
|
finished('link_color')
|
714
733
|
end
|
715
734
|
end
|
@@ -725,8 +744,8 @@ describe Split::Helper do
|
|
725
744
|
:goals => ["goal1", "goal2"]
|
726
745
|
}
|
727
746
|
ab_test :my_experiment
|
728
|
-
Split::Experiment.new(:my_experiment).alternatives.map(&:name).
|
729
|
-
Split::Experiment.new(:my_experiment).goals.
|
747
|
+
expect(Split::Experiment.new(:my_experiment).alternatives.map(&:name)).to eq([ "control_opt", "other_opt" ])
|
748
|
+
expect(Split::Experiment.new(:my_experiment).goals).to eq([ "goal1", "goal2" ])
|
730
749
|
end
|
731
750
|
|
732
751
|
it "can be called multiple times" do
|
@@ -736,9 +755,9 @@ describe Split::Helper do
|
|
736
755
|
}
|
737
756
|
5.times { ab_test :my_experiment }
|
738
757
|
experiment = Split::Experiment.new(:my_experiment)
|
739
|
-
experiment.alternatives.map(&:name).
|
740
|
-
experiment.goals.
|
741
|
-
experiment.participant_count.
|
758
|
+
expect(experiment.alternatives.map(&:name)).to eq([ "control_opt", "other_opt" ])
|
759
|
+
expect(experiment.goals).to eq([ "goal1", "goal2" ])
|
760
|
+
expect(experiment.participant_count).to eq(1)
|
742
761
|
end
|
743
762
|
|
744
763
|
it "accepts multiple goals" do
|
@@ -748,7 +767,7 @@ describe Split::Helper do
|
|
748
767
|
}
|
749
768
|
ab_test :my_experiment
|
750
769
|
experiment = Split::Experiment.new(:my_experiment)
|
751
|
-
experiment.goals.
|
770
|
+
expect(experiment.goals).to eq([ "goal1", "goal2", "goal3" ])
|
752
771
|
end
|
753
772
|
|
754
773
|
it "allow specifying goals to be optional" do
|
@@ -756,7 +775,7 @@ describe Split::Helper do
|
|
756
775
|
:alternatives => [ "control_opt", "other_opt" ]
|
757
776
|
}
|
758
777
|
experiment = Split::Experiment.new(:my_experiment)
|
759
|
-
experiment.goals.
|
778
|
+
expect(experiment.goals).to eq([])
|
760
779
|
end
|
761
780
|
|
762
781
|
it "accepts multiple alternatives" do
|
@@ -765,7 +784,7 @@ describe Split::Helper do
|
|
765
784
|
}
|
766
785
|
ab_test :my_experiment
|
767
786
|
experiment = Split::Experiment.new(:my_experiment)
|
768
|
-
experiment.alternatives.map(&:name).
|
787
|
+
expect(experiment.alternatives.map(&:name)).to eq([ "control_opt", "second_opt", "third_opt" ])
|
769
788
|
end
|
770
789
|
|
771
790
|
it "accepts probability on alternatives" do
|
@@ -778,7 +797,7 @@ describe Split::Helper do
|
|
778
797
|
}
|
779
798
|
ab_test :my_experiment
|
780
799
|
experiment = Split::Experiment.new(:my_experiment)
|
781
|
-
experiment.alternatives.collect{|a| [a.name, a.weight]}.
|
800
|
+
expect(experiment.alternatives.collect{|a| [a.name, a.weight]}).to eq([['control_opt', 0.67], ['second_opt', 0.1], ['third_opt', 0.23]])
|
782
801
|
end
|
783
802
|
|
784
803
|
it "accepts probability on some alternatives" do
|
@@ -793,8 +812,8 @@ describe Split::Helper do
|
|
793
812
|
ab_test :my_experiment
|
794
813
|
experiment = Split::Experiment.new(:my_experiment)
|
795
814
|
names_and_weights = experiment.alternatives.collect{|a| [a.name, a.weight]}
|
796
|
-
names_and_weights.
|
797
|
-
names_and_weights.inject(0){|sum, nw| sum + nw[1]}.
|
815
|
+
expect(names_and_weights).to eq([['control_opt', 0.34], ['second_opt', 0.215], ['third_opt', 0.23], ['fourth_opt', 0.215]])
|
816
|
+
expect(names_and_weights.inject(0){|sum, nw| sum + nw[1]}).to eq(1.0)
|
798
817
|
end
|
799
818
|
|
800
819
|
it "allows name param without probability" do
|
@@ -808,22 +827,22 @@ describe Split::Helper do
|
|
808
827
|
ab_test :my_experiment
|
809
828
|
experiment = Split::Experiment.new(:my_experiment)
|
810
829
|
names_and_weights = experiment.alternatives.collect{|a| [a.name, a.weight]}
|
811
|
-
names_and_weights.
|
812
|
-
names_and_weights.inject(0){|sum, nw| sum + nw[1]}.
|
830
|
+
expect(names_and_weights).to eq([['control_opt', 0.18], ['second_opt', 0.18], ['third_opt', 0.64]])
|
831
|
+
expect(names_and_weights.inject(0){|sum, nw| sum + nw[1]}).to eq(1.0)
|
813
832
|
end
|
814
833
|
|
815
834
|
it "fails gracefully if config is missing experiment" do
|
816
835
|
Split.configuration.experiments = { :other_experiment => { :foo => "Bar" } }
|
817
|
-
lambda { ab_test :my_experiment }.
|
836
|
+
expect(lambda { ab_test :my_experiment }).to raise_error
|
818
837
|
end
|
819
838
|
|
820
839
|
it "fails gracefully if config is missing" do
|
821
|
-
lambda { Split.configuration.experiments = nil }.
|
840
|
+
expect(lambda { Split.configuration.experiments = nil }).to raise_error
|
822
841
|
end
|
823
842
|
|
824
843
|
it "fails gracefully if config is missing alternatives" do
|
825
844
|
Split.configuration.experiments[:my_experiment] = { :foo => "Bar" }
|
826
|
-
lambda { ab_test :my_experiment }.
|
845
|
+
expect(lambda { ab_test :my_experiment }).to raise_error
|
827
846
|
end
|
828
847
|
end
|
829
848
|
|
@@ -834,7 +853,7 @@ describe Split::Helper do
|
|
834
853
|
finished('link_color2')
|
835
854
|
|
836
855
|
experiment2.alternatives.each do |alt|
|
837
|
-
alt.unfinished_count.
|
856
|
+
expect(alt.unfinished_count).to eq(0)
|
838
857
|
end
|
839
858
|
end
|
840
859
|
|
@@ -848,15 +867,15 @@ describe Split::Helper do
|
|
848
867
|
end
|
849
868
|
|
850
869
|
it "should normalize experiment" do
|
851
|
-
@experiment_name.
|
852
|
-
@goals.
|
870
|
+
expect(@experiment_name).to eq("link_color")
|
871
|
+
expect(@goals).to eq(["purchase", "refund"])
|
853
872
|
end
|
854
873
|
|
855
874
|
describe "ab_test" do
|
856
875
|
it "should allow experiment goals interface as a single hash" do
|
857
876
|
ab_test(@experiment, *@alternatives)
|
858
877
|
experiment = Split::Experiment.find('link_color')
|
859
|
-
experiment.goals.
|
878
|
+
expect(experiment.goals).to eq(['purchase', "refund"])
|
860
879
|
end
|
861
880
|
end
|
862
881
|
|
@@ -866,13 +885,13 @@ describe Split::Helper do
|
|
866
885
|
end
|
867
886
|
|
868
887
|
it "should increment the counter for the specified-goal completed alternative" do
|
869
|
-
lambda {
|
870
|
-
lambda {
|
888
|
+
expect(lambda {
|
889
|
+
expect(lambda {
|
871
890
|
finished({"link_color" => ["purchase"]})
|
872
|
-
}.
|
891
|
+
}).not_to change {
|
873
892
|
Split::Alternative.new(@alternative_name, @experiment_name).completed_count(@goal2)
|
874
893
|
}
|
875
|
-
}.
|
894
|
+
}).to change {
|
876
895
|
Split::Alternative.new(@alternative_name, @experiment_name).completed_count(@goal1)
|
877
896
|
}.by(1)
|
878
897
|
end
|