split 3.3.2 → 3.4.0
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/.eslintrc +1 -1
- data/.github/ISSUE_TEMPLATE/bug_report.md +24 -0
- data/.rspec +1 -0
- data/.rubocop.yml +6 -1155
- data/.rubocop_todo.yml +679 -0
- data/.travis.yml +8 -14
- data/Appraisals +1 -1
- data/CHANGELOG.md +22 -0
- data/CODE_OF_CONDUCT.md +3 -3
- data/Gemfile +1 -0
- data/README.md +15 -13
- data/Rakefile +1 -0
- data/gemfiles/6.0.gemfile +1 -1
- data/lib/split/algorithms/block_randomization.rb +1 -0
- data/lib/split/alternative.rb +3 -3
- data/lib/split/combined_experiments_helper.rb +1 -1
- data/lib/split/configuration.rb +5 -2
- data/lib/split/dashboard.rb +4 -1
- data/lib/split/dashboard/pagination_helpers.rb +2 -3
- data/lib/split/dashboard/views/layout.erb +1 -1
- data/lib/split/engine.rb +6 -4
- data/lib/split/experiment.rb +29 -18
- data/lib/split/goals_collection.rb +1 -0
- data/lib/split/helper.rb +2 -1
- data/lib/split/persistence/dual_adapter.rb +54 -12
- data/lib/split/redis_interface.rb +1 -0
- data/lib/split/trial.rb +1 -1
- data/lib/split/user.rb +5 -1
- data/lib/split/version.rb +2 -2
- data/spec/dashboard/pagination_helpers_spec.rb +3 -1
- data/spec/dashboard_helpers_spec.rb +2 -2
- data/spec/dashboard_spec.rb +37 -16
- data/spec/encapsulated_helper_spec.rb +1 -1
- data/spec/experiment_spec.rb +44 -5
- data/spec/helper_spec.rb +118 -80
- data/spec/persistence/dual_adapter_spec.rb +160 -68
- data/spec/user_spec.rb +11 -0
- data/split.gemspec +1 -2
- metadata +6 -4
data/lib/split/helper.rb
CHANGED
@@ -44,6 +44,7 @@ module Split
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def finish_experiment(experiment, options = {:reset => true})
|
47
|
+
return false if active_experiments[experiment.name].nil?
|
47
48
|
return true if experiment.has_winner?
|
48
49
|
should_reset = experiment.resettable? && options[:reset]
|
49
50
|
if ab_user[experiment.finished_key] && !should_reset
|
@@ -79,7 +80,7 @@ module Split
|
|
79
80
|
|
80
81
|
def ab_record_extra_info(metric_descriptor, key, value = 1)
|
81
82
|
return if exclude_visitor? || Split.configuration.disabled?
|
82
|
-
metric_descriptor,
|
83
|
+
metric_descriptor, _ = normalize_metric(metric_descriptor)
|
83
84
|
experiments = Metric.possible_experiments(metric_descriptor)
|
84
85
|
|
85
86
|
if experiments.any?
|
@@ -1,12 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'forwardable'
|
4
|
-
|
5
3
|
module Split
|
6
4
|
module Persistence
|
7
5
|
class DualAdapter
|
8
|
-
|
9
|
-
|
6
|
+
def self.with_config(options={})
|
7
|
+
self.config.merge!(options)
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.config
|
12
|
+
@config ||= {}
|
13
|
+
end
|
10
14
|
|
11
15
|
def initialize(context)
|
12
16
|
if logged_in = self.class.config[:logged_in]
|
@@ -22,22 +26,60 @@ module Split
|
|
22
26
|
raise "Please configure :logged_out_adapter"
|
23
27
|
end
|
24
28
|
|
25
|
-
|
26
|
-
|
29
|
+
@fallback_to_logged_out_adapter =
|
30
|
+
self.class.config[:fallback_to_logged_out_adapter] || false
|
31
|
+
@logged_in = logged_in.call(context)
|
32
|
+
@logged_in_adapter = logged_in_adapter.new(context)
|
33
|
+
@logged_out_adapter = logged_out_adapter.new(context)
|
34
|
+
@active_adapter = @logged_in ? @logged_in_adapter : @logged_out_adapter
|
35
|
+
end
|
36
|
+
|
37
|
+
def keys
|
38
|
+
if @fallback_to_logged_out_adapter
|
39
|
+
(@logged_in_adapter.keys + @logged_out_adapter.keys).uniq
|
27
40
|
else
|
28
|
-
@
|
41
|
+
@active_adapter.keys
|
29
42
|
end
|
30
43
|
end
|
31
44
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
45
|
+
def [](key)
|
46
|
+
if @fallback_to_logged_out_adapter
|
47
|
+
@logged_in && @logged_in_adapter[key] || @logged_out_adapter[key]
|
48
|
+
else
|
49
|
+
@active_adapter[key]
|
50
|
+
end
|
35
51
|
end
|
36
52
|
|
37
|
-
def
|
38
|
-
@
|
53
|
+
def []=(key, value)
|
54
|
+
if @fallback_to_logged_out_adapter
|
55
|
+
@logged_in_adapter[key] = value if @logged_in
|
56
|
+
old_value = @logged_out_adapter[key]
|
57
|
+
@logged_out_adapter[key] = value
|
58
|
+
|
59
|
+
decrement_participation(key, old_value) if decrement_participation?(old_value, value)
|
60
|
+
else
|
61
|
+
@active_adapter[key] = value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def delete(key)
|
66
|
+
if @fallback_to_logged_out_adapter
|
67
|
+
@logged_in_adapter.delete(key)
|
68
|
+
@logged_out_adapter.delete(key)
|
69
|
+
else
|
70
|
+
@active_adapter.delete(key)
|
71
|
+
end
|
39
72
|
end
|
40
73
|
|
74
|
+
private
|
75
|
+
|
76
|
+
def decrement_participation?(old_value, value)
|
77
|
+
!old_value.nil? && !value.nil? && old_value != value
|
78
|
+
end
|
79
|
+
|
80
|
+
def decrement_participation(key, value)
|
81
|
+
Split.redis.hincrby("#{key}:#{value}", 'participant_count', -1)
|
82
|
+
end
|
41
83
|
end
|
42
84
|
end
|
43
85
|
end
|
data/lib/split/trial.rb
CHANGED
data/lib/split/user.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'forwardable'
|
2
3
|
|
3
4
|
module Split
|
@@ -8,9 +9,11 @@ module Split
|
|
8
9
|
|
9
10
|
def initialize(context, adapter=nil)
|
10
11
|
@user = adapter || Split::Persistence.adapter.new(context)
|
12
|
+
@cleaned_up = false
|
11
13
|
end
|
12
14
|
|
13
15
|
def cleanup_old_experiments!
|
16
|
+
return if @cleaned_up
|
14
17
|
keys_without_finished(user.keys).each do |key|
|
15
18
|
experiment = ExperimentCatalog.find key_without_version(key)
|
16
19
|
if experiment.nil? || experiment.has_winner? || experiment.start_time.nil?
|
@@ -18,6 +21,7 @@ module Split
|
|
18
21
|
user.delete Experiment.finished_key(key)
|
19
22
|
end
|
20
23
|
end
|
24
|
+
@cleaned_up = true
|
21
25
|
end
|
22
26
|
|
23
27
|
def max_experiments_reached?(experiment_key)
|
@@ -38,7 +42,7 @@ module Split
|
|
38
42
|
|
39
43
|
def active_experiments
|
40
44
|
experiment_pairs = {}
|
41
|
-
user.keys.each do |key|
|
45
|
+
keys_without_finished(user.keys).each do |key|
|
42
46
|
Metric.possible_experiments(key_without_version(key)).each do |experiment|
|
43
47
|
if !experiment.has_winner?
|
44
48
|
experiment_pairs[key_without_version(key)] = user[key]
|
data/lib/split/version.rb
CHANGED
@@ -10,7 +10,9 @@ describe Split::DashboardPaginationHelpers do
|
|
10
10
|
context 'when params empty' do
|
11
11
|
let(:params) { Hash[] }
|
12
12
|
|
13
|
-
it 'returns 10' do
|
13
|
+
it 'returns the default (10)' do
|
14
|
+
default_per_page = Split.configuration.dashboard_pagination_default_per_page
|
15
|
+
expect(pagination_per).to eql default_per_page
|
14
16
|
expect(pagination_per).to eql 10
|
15
17
|
end
|
16
18
|
end
|
@@ -27,11 +27,11 @@ describe Split::DashboardHelpers do
|
|
27
27
|
|
28
28
|
describe '#round' do
|
29
29
|
it 'can round number strings' do
|
30
|
-
expect(round('3.1415')).to eq BigDecimal
|
30
|
+
expect(round('3.1415')).to eq BigDecimal('3.14')
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'can round number strings for precsion' do
|
34
|
-
expect(round('3.1415', 1)).to eq BigDecimal
|
34
|
+
expect(round('3.1415', 1)).to eq BigDecimal('3.1')
|
35
35
|
end
|
36
36
|
|
37
37
|
it 'can handle invalid number strings' do
|
data/spec/dashboard_spec.rb
CHANGED
@@ -29,6 +29,10 @@ describe Split::Dashboard do
|
|
29
29
|
let(:red_link) { link("red") }
|
30
30
|
let(:blue_link) { link("blue") }
|
31
31
|
|
32
|
+
before(:each) do
|
33
|
+
Split.configuration.beta_probability_simulations = 1
|
34
|
+
end
|
35
|
+
|
32
36
|
it "should respond to /" do
|
33
37
|
get '/'
|
34
38
|
expect(last_response).to be_ok
|
@@ -74,17 +78,39 @@ describe Split::Dashboard do
|
|
74
78
|
end
|
75
79
|
|
76
80
|
describe "force alternative" do
|
77
|
-
|
78
|
-
|
79
|
-
|
81
|
+
context "initial version" do
|
82
|
+
let!(:user) do
|
83
|
+
Split::User.new(@app, { experiment.name => 'red' })
|
84
|
+
end
|
80
85
|
|
81
|
-
|
82
|
-
|
86
|
+
before do
|
87
|
+
allow(Split::User).to receive(:new).and_return(user)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should set current user's alternative" do
|
91
|
+
blue_link.participant_count = 7
|
92
|
+
post "/force_alternative?experiment=#{experiment.name}", alternative: "blue"
|
93
|
+
expect(user[experiment.key]).to eq("blue")
|
94
|
+
expect(blue_link.participant_count).to eq(8)
|
95
|
+
end
|
83
96
|
end
|
84
97
|
|
85
|
-
|
86
|
-
|
87
|
-
|
98
|
+
context "incremented version" do
|
99
|
+
let!(:user) do
|
100
|
+
experiment.increment_version
|
101
|
+
Split::User.new(@app, { "#{experiment.name}:#{experiment.version}" => 'red' })
|
102
|
+
end
|
103
|
+
|
104
|
+
before do
|
105
|
+
allow(Split::User).to receive(:new).and_return(user)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should set current user's alternative" do
|
109
|
+
blue_link.participant_count = 7
|
110
|
+
post "/force_alternative?experiment=#{experiment.name}", alternative: "blue"
|
111
|
+
expect(user[experiment.key]).to eq("blue")
|
112
|
+
expect(blue_link.participant_count).to eq(8)
|
113
|
+
end
|
88
114
|
end
|
89
115
|
end
|
90
116
|
|
@@ -120,7 +146,7 @@ describe Split::Dashboard do
|
|
120
146
|
it "removes winner" do
|
121
147
|
post "/reopen?experiment=#{experiment.name}"
|
122
148
|
|
123
|
-
expect(experiment).to_not have_winner
|
149
|
+
expect(Split::ExperimentCatalog.find(experiment.name)).to_not have_winner
|
124
150
|
end
|
125
151
|
|
126
152
|
it "keeps existing stats" do
|
@@ -167,19 +193,14 @@ describe Split::Dashboard do
|
|
167
193
|
end
|
168
194
|
|
169
195
|
it "should display the start date" do
|
170
|
-
|
171
|
-
expect(Time).to receive(:now).at_least(:once).and_return(experiment_start_time)
|
172
|
-
experiment
|
196
|
+
experiment.start
|
173
197
|
|
174
198
|
get '/'
|
175
199
|
|
176
|
-
expect(last_response.body).to include(
|
200
|
+
expect(last_response.body).to include("<small>#{experiment.start_time.strftime('%Y-%m-%d')}</small>")
|
177
201
|
end
|
178
202
|
|
179
203
|
it "should handle experiments without a start date" do
|
180
|
-
experiment_start_time = Time.parse('2011-07-07')
|
181
|
-
expect(Time).to receive(:now).at_least(:once).and_return(experiment_start_time)
|
182
|
-
|
183
204
|
Split.redis.hdel(:experiment_start_times, experiment.name)
|
184
205
|
|
185
206
|
get '/'
|
data/spec/experiment_spec.rb
CHANGED
@@ -35,6 +35,12 @@ describe Split::Experiment do
|
|
35
35
|
expect(experiment.resettable).to be_truthy
|
36
36
|
end
|
37
37
|
|
38
|
+
it "should be resettable when loading from configuration" do
|
39
|
+
allow(Split.configuration).to receive(:experiment_for).with('some_experiment') { { alternatives: %w(a b) } }
|
40
|
+
|
41
|
+
expect(Split::Experiment.new('some_experiment')).to be_resettable
|
42
|
+
end
|
43
|
+
|
38
44
|
it "should save to redis" do
|
39
45
|
experiment.save
|
40
46
|
expect(Split.redis.exists('basket_text')).to be true
|
@@ -86,7 +92,7 @@ describe Split::Experiment do
|
|
86
92
|
experiment.save
|
87
93
|
experiment.save
|
88
94
|
expect(Split.redis.exists('basket_text')).to be true
|
89
|
-
expect(Split.redis.lrange('basket_text', 0, -1)).to eq(['Basket', "Cart"])
|
95
|
+
expect(Split.redis.lrange('basket_text', 0, -1)).to eq(['{"Basket":1}', '{"Cart":1}'])
|
90
96
|
end
|
91
97
|
|
92
98
|
describe 'new record?' do
|
@@ -213,12 +219,41 @@ describe Split::Experiment do
|
|
213
219
|
it "should have no winner initially" do
|
214
220
|
expect(experiment.winner).to be_nil
|
215
221
|
end
|
222
|
+
end
|
216
223
|
|
224
|
+
describe 'winner=' do
|
217
225
|
it "should allow you to specify a winner" do
|
218
226
|
experiment.save
|
219
227
|
experiment.winner = 'red'
|
220
228
|
expect(experiment.winner.name).to eq('red')
|
221
229
|
end
|
230
|
+
|
231
|
+
context 'when has_winner state is memoized' do
|
232
|
+
before { expect(experiment).to_not have_winner }
|
233
|
+
|
234
|
+
it 'should keep has_winner state consistent' do
|
235
|
+
experiment.winner = 'red'
|
236
|
+
expect(experiment).to have_winner
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe 'reset_winner' do
|
242
|
+
before { experiment.winner = 'green' }
|
243
|
+
|
244
|
+
it 'should reset the winner' do
|
245
|
+
experiment.reset_winner
|
246
|
+
expect(experiment.winner).to be_nil
|
247
|
+
end
|
248
|
+
|
249
|
+
context 'when has_winner state is memoized' do
|
250
|
+
before { expect(experiment).to have_winner }
|
251
|
+
|
252
|
+
it 'should keep has_winner state consistent' do
|
253
|
+
experiment.reset_winner
|
254
|
+
expect(experiment).to_not have_winner
|
255
|
+
end
|
256
|
+
end
|
222
257
|
end
|
223
258
|
|
224
259
|
describe 'has_winner?' do
|
@@ -235,6 +270,12 @@ describe Split::Experiment do
|
|
235
270
|
expect(experiment).to_not have_winner
|
236
271
|
end
|
237
272
|
end
|
273
|
+
|
274
|
+
it 'memoizes has_winner state' do
|
275
|
+
expect(experiment).to receive(:winner).once
|
276
|
+
expect(experiment).to_not have_winner
|
277
|
+
expect(experiment).to_not have_winner
|
278
|
+
end
|
238
279
|
end
|
239
280
|
|
240
281
|
describe 'reset' do
|
@@ -414,9 +455,7 @@ describe Split::Experiment do
|
|
414
455
|
}
|
415
456
|
|
416
457
|
context "saving experiment" do
|
417
|
-
|
418
|
-
Split::ExperimentCatalog.find_or_create({'link_color' => ["purchase", "refund"]}, 'blue', 'red', 'green')
|
419
|
-
end
|
458
|
+
let(:same_but_different_goals) { Split::ExperimentCatalog.find_or_create({'link_color' => ["purchase", "refund"]}, 'blue', 'red', 'green') }
|
420
459
|
|
421
460
|
before { experiment.save }
|
422
461
|
|
@@ -425,7 +464,7 @@ describe Split::Experiment do
|
|
425
464
|
end
|
426
465
|
|
427
466
|
it "should reset an experiment if it is loaded with different goals" do
|
428
|
-
|
467
|
+
same_but_different_goals
|
429
468
|
expect(Split::ExperimentCatalog.find("link_color").goals).to eq(["purchase", "refund"])
|
430
469
|
end
|
431
470
|
|
data/spec/helper_spec.rb
CHANGED
@@ -183,8 +183,7 @@ describe Split::Helper do
|
|
183
183
|
ab_test('link_color', {'blue' => 0.01}, 'red' => 0.2)
|
184
184
|
experiment = Split::ExperimentCatalog.find('link_color')
|
185
185
|
expect(experiment.alternatives.map(&:name)).to eq(['blue', 'red'])
|
186
|
-
|
187
|
-
# expect(experiment.alternatives.collect{|a| a.weight}).to eq([0.01, 0.2])
|
186
|
+
expect(experiment.alternatives.collect{|a| a.weight}).to match_array([0.01, 0.2])
|
188
187
|
end
|
189
188
|
|
190
189
|
it "should only let a user participate in one experiment at a time" do
|
@@ -297,98 +296,126 @@ describe Split::Helper do
|
|
297
296
|
end
|
298
297
|
|
299
298
|
describe 'ab_finished' do
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
299
|
+
context 'for an experiment that the user participates in' do
|
300
|
+
before(:each) do
|
301
|
+
@experiment_name = 'link_color'
|
302
|
+
@alternatives = ['blue', 'red']
|
303
|
+
@experiment = Split::ExperimentCatalog.find_or_create(@experiment_name, *@alternatives)
|
304
|
+
@alternative_name = ab_test(@experiment_name, *@alternatives)
|
305
|
+
@previous_completion_count = Split::Alternative.new(@alternative_name, @experiment_name).completed_count
|
306
|
+
end
|
307
307
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
308
|
+
it 'should increment the counter for the completed alternative' do
|
309
|
+
ab_finished(@experiment_name)
|
310
|
+
new_completion_count = Split::Alternative.new(@alternative_name, @experiment_name).completed_count
|
311
|
+
expect(new_completion_count).to eq(@previous_completion_count + 1)
|
312
|
+
end
|
313
313
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
314
|
+
it "should set experiment's finished key if reset is false" do
|
315
|
+
ab_finished(@experiment_name, {:reset => false})
|
316
|
+
expect(ab_user[@experiment.key]).to eq(@alternative_name)
|
317
|
+
expect(ab_user[@experiment.finished_key]).to eq(true)
|
318
|
+
end
|
319
319
|
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
320
|
+
it 'should not increment the counter if reset is false and the experiment has been already finished' do
|
321
|
+
2.times { ab_finished(@experiment_name, {:reset => false}) }
|
322
|
+
new_completion_count = Split::Alternative.new(@alternative_name, @experiment_name).completed_count
|
323
|
+
expect(new_completion_count).to eq(@previous_completion_count + 1)
|
324
|
+
end
|
325
325
|
|
326
|
-
|
327
|
-
|
326
|
+
it 'should not increment the counter for an ended experiment' do
|
327
|
+
e = Split::ExperimentCatalog.find_or_create('button_size', 'small', 'big')
|
328
|
+
e.winner = 'small'
|
329
|
+
a = ab_test('button_size', 'small', 'big')
|
330
|
+
expect(a).to eq('small')
|
331
|
+
expect(lambda {
|
332
|
+
ab_finished('button_size')
|
333
|
+
}).not_to change { Split::Alternative.new(a, 'button_size').completed_count }
|
334
|
+
end
|
328
335
|
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
ab_finished('button_size')
|
335
|
-
}).not_to change { Split::Alternative.new('small', 'button_size').completed_count }
|
336
|
-
end
|
336
|
+
it "should clear out the user's participation from their session" do
|
337
|
+
expect(ab_user[@experiment.key]).to eq(@alternative_name)
|
338
|
+
ab_finished(@experiment_name)
|
339
|
+
expect(ab_user.keys).to be_empty
|
340
|
+
end
|
337
341
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
ab_finished('button_size')
|
345
|
-
}).not_to change { Split::Alternative.new(a, 'button_size').completed_count }
|
346
|
-
end
|
342
|
+
it "should not clear out the users session if reset is false" do
|
343
|
+
expect(ab_user[@experiment.key]).to eq(@alternative_name)
|
344
|
+
ab_finished(@experiment_name, {:reset => false})
|
345
|
+
expect(ab_user[@experiment.key]).to eq(@alternative_name)
|
346
|
+
expect(ab_user[@experiment.finished_key]).to eq(true)
|
347
|
+
end
|
347
348
|
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
349
|
+
it "should reset the users session when experiment is not versioned" do
|
350
|
+
expect(ab_user[@experiment.key]).to eq(@alternative_name)
|
351
|
+
ab_finished(@experiment_name)
|
352
|
+
expect(ab_user.keys).to be_empty
|
353
|
+
end
|
353
354
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
expect(ab_user[@experiment.key]).to eq(@alternative_name)
|
358
|
-
expect(ab_user[@experiment.finished_key]).to eq(true)
|
359
|
-
end
|
355
|
+
it "should reset the users session when experiment is versioned" do
|
356
|
+
@experiment.increment_version
|
357
|
+
@alternative_name = ab_test(@experiment_name, *@alternatives)
|
360
358
|
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
end
|
359
|
+
expect(ab_user[@experiment.key]).to eq(@alternative_name)
|
360
|
+
ab_finished(@experiment_name)
|
361
|
+
expect(ab_user.keys).to be_empty
|
362
|
+
end
|
366
363
|
|
367
|
-
|
368
|
-
|
369
|
-
|
364
|
+
context "when on_trial_complete is set" do
|
365
|
+
before { Split.configuration.on_trial_complete = :some_method }
|
366
|
+
it "should call the method" do
|
367
|
+
expect(self).to receive(:some_method)
|
368
|
+
ab_finished(@experiment_name)
|
369
|
+
end
|
370
370
|
|
371
|
-
|
372
|
-
|
373
|
-
|
371
|
+
it "should not call the method without alternative" do
|
372
|
+
ab_user[@experiment.key] = nil
|
373
|
+
expect(self).not_to receive(:some_method)
|
374
|
+
ab_finished(@experiment_name)
|
375
|
+
end
|
376
|
+
end
|
374
377
|
end
|
375
378
|
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
+
context 'for an experiment that the user is excluded from' do
|
380
|
+
before do
|
381
|
+
alternative = ab_test('link_color', 'blue', 'red')
|
382
|
+
expect(Split::Alternative.new(alternative, 'link_color').participant_count).to eq(1)
|
383
|
+
alternative = ab_test('button_size', 'small', 'big')
|
384
|
+
expect(Split::Alternative.new(alternative, 'button_size').participant_count).to eq(0)
|
385
|
+
end
|
386
|
+
|
387
|
+
it 'should not increment the completed counter' do
|
388
|
+
# So, user should be participating in the link_color experiment and
|
389
|
+
# receive the control for button_size. As the user is not participating in
|
390
|
+
# the button size experiment, finishing it should not increase the
|
391
|
+
# completion count for that alternative.
|
392
|
+
expect(lambda {
|
393
|
+
ab_finished('button_size')
|
394
|
+
}).not_to change { Split::Alternative.new('small', 'button_size').completed_count }
|
395
|
+
end
|
379
396
|
end
|
380
397
|
|
381
|
-
context
|
382
|
-
before
|
383
|
-
|
384
|
-
|
385
|
-
|
398
|
+
context 'for an experiment that the user does not participate in' do
|
399
|
+
before do
|
400
|
+
Split::ExperimentCatalog.find_or_create(:not_started_experiment, 'control', 'alt')
|
401
|
+
end
|
402
|
+
it 'should not raise an exception' do
|
403
|
+
expect { ab_finished(:not_started_experiment) }.not_to raise_exception
|
386
404
|
end
|
387
405
|
|
388
|
-
it
|
389
|
-
ab_user[
|
390
|
-
|
391
|
-
|
406
|
+
it 'should not change the user state when reset is false' do
|
407
|
+
expect { ab_finished(:not_started_experiment, reset: false) }.not_to change { ab_user.keys}.from([])
|
408
|
+
end
|
409
|
+
|
410
|
+
it 'should not change the user state when reset is true' do
|
411
|
+
expect(self).not_to receive(:reset!)
|
412
|
+
ab_finished(:not_started_experiment)
|
413
|
+
end
|
414
|
+
|
415
|
+
it 'should not increment the completed counter' do
|
416
|
+
ab_finished(:not_started_experiment)
|
417
|
+
expect(Split::Alternative.new('control', :not_started_experiment).completed_count).to eq(0)
|
418
|
+
expect(Split::Alternative.new('alt', :not_started_experiment).completed_count).to eq(0)
|
392
419
|
end
|
393
420
|
end
|
394
421
|
end
|
@@ -528,6 +555,17 @@ describe Split::Helper do
|
|
528
555
|
expect(active_experiments.first[0]).to eq "link_color"
|
529
556
|
end
|
530
557
|
|
558
|
+
it 'should show versioned tests properly' do
|
559
|
+
10.times { experiment.reset }
|
560
|
+
|
561
|
+
alternative = ab_test(experiment.name, 'blue', 'red')
|
562
|
+
ab_finished(experiment.name, reset: false)
|
563
|
+
|
564
|
+
expect(experiment.version).to eq(10)
|
565
|
+
expect(active_experiments.count).to eq 1
|
566
|
+
expect(active_experiments).to eq({'link_color' => alternative })
|
567
|
+
end
|
568
|
+
|
531
569
|
it 'should show multiple tests' do
|
532
570
|
Split.configure do |config|
|
533
571
|
config.allow_multiple_experiments = true
|
@@ -545,7 +583,7 @@ describe Split::Helper do
|
|
545
583
|
end
|
546
584
|
e = Split::ExperimentCatalog.find_or_create('def', '4', '5', '6')
|
547
585
|
e.winner = '4'
|
548
|
-
|
586
|
+
ab_test('def', '4', '5', '6')
|
549
587
|
another_alternative = ab_test('ghi', '7', '8', '9')
|
550
588
|
expect(active_experiments.count).to eq 1
|
551
589
|
expect(active_experiments.first[0]).to eq "ghi"
|
@@ -1021,8 +1059,8 @@ describe Split::Helper do
|
|
1021
1059
|
|
1022
1060
|
it 'should handle multiple experiments correctly' do
|
1023
1061
|
experiment2 = Split::ExperimentCatalog.find_or_create('link_color2', 'blue', 'red')
|
1024
|
-
|
1025
|
-
|
1062
|
+
ab_test('link_color', 'blue', 'red')
|
1063
|
+
ab_test('link_color2', 'blue', 'red')
|
1026
1064
|
ab_finished('link_color2')
|
1027
1065
|
|
1028
1066
|
experiment2.alternatives.each do |alt|
|