split 3.3.2 → 4.0.5
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/FUNDING.yml +1 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +24 -0
- data/.github/dependabot.yml +7 -0
- data/.github/workflows/ci.yml +63 -0
- data/.rspec +1 -0
- data/.rubocop.yml +67 -1043
- data/CHANGELOG.md +121 -0
- data/CODE_OF_CONDUCT.md +3 -3
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +6 -1
- data/README.md +51 -21
- data/Rakefile +6 -5
- data/lib/split/algorithms/block_randomization.rb +7 -6
- data/lib/split/algorithms/weighted_sample.rb +2 -1
- data/lib/split/algorithms/whiplash.rb +17 -18
- data/lib/split/algorithms.rb +14 -0
- data/lib/split/alternative.rb +25 -25
- data/lib/split/cache.rb +27 -0
- data/lib/split/combined_experiments_helper.rb +5 -4
- data/lib/split/configuration.rb +94 -96
- data/lib/split/dashboard/helpers.rb +7 -7
- data/lib/split/dashboard/pagination_helpers.rb +56 -57
- data/lib/split/dashboard/paginator.rb +1 -0
- data/lib/split/dashboard/public/dashboard.js +10 -0
- data/lib/split/dashboard/public/style.css +10 -2
- data/lib/split/dashboard/views/_controls.erb +13 -0
- data/lib/split/dashboard/views/_experiment.erb +2 -1
- data/lib/split/dashboard/views/index.erb +19 -4
- data/lib/split/dashboard/views/layout.erb +1 -1
- data/lib/split/dashboard.rb +46 -21
- data/lib/split/encapsulated_helper.rb +15 -8
- data/lib/split/engine.rb +7 -4
- data/lib/split/exceptions.rb +1 -0
- data/lib/split/experiment.rb +160 -122
- data/lib/split/experiment_catalog.rb +7 -8
- data/lib/split/extensions/string.rb +2 -1
- data/lib/split/goals_collection.rb +10 -10
- data/lib/split/helper.rb +52 -24
- data/lib/split/metric.rb +6 -6
- data/lib/split/persistence/cookie_adapter.rb +47 -44
- data/lib/split/persistence/dual_adapter.rb +53 -12
- data/lib/split/persistence/redis_adapter.rb +8 -4
- data/lib/split/persistence/session_adapter.rb +1 -2
- data/lib/split/persistence.rb +8 -6
- data/lib/split/redis_interface.rb +16 -29
- data/lib/split/trial.rb +44 -35
- data/lib/split/user.rb +30 -15
- data/lib/split/version.rb +2 -4
- data/lib/split/zscore.rb +2 -3
- data/lib/split.rb +35 -28
- 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 +84 -0
- data/spec/combined_experiments_helper_spec.rb +18 -17
- data/spec/configuration_spec.rb +41 -45
- data/spec/dashboard/pagination_helpers_spec.rb +71 -67
- data/spec/dashboard/paginator_spec.rb +10 -9
- data/spec/dashboard_helpers_spec.rb +19 -18
- data/spec/dashboard_spec.rb +153 -48
- data/spec/encapsulated_helper_spec.rb +47 -23
- data/spec/experiment_catalog_spec.rb +14 -13
- data/spec/experiment_spec.rb +224 -111
- data/spec/goals_collection_spec.rb +18 -16
- data/spec/helper_spec.rb +531 -424
- data/spec/metric_spec.rb +14 -14
- data/spec/persistence/cookie_adapter_spec.rb +26 -11
- data/spec/persistence/dual_adapter_spec.rb +158 -66
- data/spec/persistence/redis_adapter_spec.rb +35 -27
- data/spec/persistence/session_adapter_spec.rb +2 -3
- data/spec/persistence_spec.rb +1 -2
- data/spec/redis_interface_spec.rb +25 -82
- data/spec/spec_helper.rb +38 -24
- data/spec/split_spec.rb +11 -11
- data/spec/support/cookies_mock.rb +1 -2
- data/spec/trial_spec.rb +102 -75
- data/spec/user_spec.rb +69 -27
- data/split.gemspec +26 -23
- metadata +68 -42
- data/.travis.yml +0 -66
- data/Appraisals +0 -19
- data/gemfiles/4.2.gemfile +0 -9
- data/gemfiles/5.0.gemfile +0 -9
- data/gemfiles/5.1.gemfile +0 -9
- data/gemfiles/5.2.gemfile +0 -9
- data/gemfiles/6.0.gemfile +0 -9
data/spec/cache_spec.rb
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
describe Split::Cache do
|
|
6
|
+
let(:namespace) { :test_namespace }
|
|
7
|
+
let(:key) { :test_key }
|
|
8
|
+
let(:now) { 1606189017 }
|
|
9
|
+
|
|
10
|
+
before { allow(Time).to receive(:now).and_return(now) }
|
|
11
|
+
|
|
12
|
+
describe "clear" do
|
|
13
|
+
before { Split.configuration.cache = true }
|
|
14
|
+
|
|
15
|
+
it "clears the cache" do
|
|
16
|
+
expect(Time).to receive(:now).and_return(now).exactly(2).times
|
|
17
|
+
Split::Cache.fetch(namespace, key) { Time.now }
|
|
18
|
+
Split::Cache.clear
|
|
19
|
+
Split::Cache.fetch(namespace, key) { Time.now }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe "clear_key" do
|
|
24
|
+
before { Split.configuration.cache = true }
|
|
25
|
+
|
|
26
|
+
it "clears the cache" do
|
|
27
|
+
expect(Time).to receive(:now).and_return(now).exactly(3).times
|
|
28
|
+
Split::Cache.fetch(namespace, :key1) { Time.now }
|
|
29
|
+
Split::Cache.fetch(namespace, :key2) { Time.now }
|
|
30
|
+
Split::Cache.clear_key(:key1)
|
|
31
|
+
|
|
32
|
+
Split::Cache.fetch(namespace, :key1) { Time.now }
|
|
33
|
+
Split::Cache.fetch(namespace, :key2) { Time.now }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe "fetch" do
|
|
38
|
+
subject { Split::Cache.fetch(namespace, key) { Time.now } }
|
|
39
|
+
|
|
40
|
+
context "when cache disabled" do
|
|
41
|
+
before { Split.configuration.cache = false }
|
|
42
|
+
|
|
43
|
+
it "returns the yield" do
|
|
44
|
+
expect(subject).to eql(now)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "yields every time" do
|
|
48
|
+
expect(Time).to receive(:now).and_return(now).exactly(2).times
|
|
49
|
+
Split::Cache.fetch(namespace, key) { Time.now }
|
|
50
|
+
Split::Cache.fetch(namespace, key) { Time.now }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context "when cache enabled" do
|
|
55
|
+
before { Split.configuration.cache = true }
|
|
56
|
+
|
|
57
|
+
it "returns the yield" do
|
|
58
|
+
expect(subject).to eql(now)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "yields once" do
|
|
62
|
+
expect(Time).to receive(:now).and_return(now).once
|
|
63
|
+
Split::Cache.fetch(namespace, key) { Time.now }
|
|
64
|
+
Split::Cache.fetch(namespace, key) { Time.now }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "honors namespace" do
|
|
68
|
+
expect(Split::Cache.fetch(:a, key) { :a }).to eql(:a)
|
|
69
|
+
expect(Split::Cache.fetch(:b, key) { :b }).to eql(:b)
|
|
70
|
+
|
|
71
|
+
expect(Split::Cache.fetch(:a, key) { :a }).to eql(:a)
|
|
72
|
+
expect(Split::Cache.fetch(:b, key) { :b }).to eql(:b)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "honors key" do
|
|
76
|
+
expect(Split::Cache.fetch(namespace, :a) { :a }).to eql(:a)
|
|
77
|
+
expect(Split::Cache.fetch(namespace, :b) { :b }).to eql(:b)
|
|
78
|
+
|
|
79
|
+
expect(Split::Cache.fetch(namespace, :a) { :a }).to eql(:a)
|
|
80
|
+
expect(Split::Cache.fetch(namespace, :b) { :b }).to eql(:b)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -1,57 +1,58 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
require "split/combined_experiments_helper"
|
|
4
5
|
|
|
5
6
|
describe Split::CombinedExperimentsHelper do
|
|
6
7
|
include Split::CombinedExperimentsHelper
|
|
7
8
|
|
|
8
|
-
describe
|
|
9
|
+
describe "ab_combined_test" do
|
|
9
10
|
let!(:config_enabled) { true }
|
|
10
|
-
let!(:combined_experiments) { [:exp_1_click, :exp_1_scroll ]}
|
|
11
|
+
let!(:combined_experiments) { [:exp_1_click, :exp_1_scroll ] }
|
|
11
12
|
let!(:allow_multiple_experiments) { true }
|
|
12
13
|
|
|
13
14
|
before do
|
|
14
15
|
Split.configuration.experiments = {
|
|
15
|
-
:
|
|
16
|
-
:
|
|
17
|
-
:
|
|
18
|
-
:
|
|
16
|
+
combined_exp_1: {
|
|
17
|
+
alternatives: [ { "control"=> 0.5 }, { "test-alt"=> 0.5 } ],
|
|
18
|
+
metric: :my_metric,
|
|
19
|
+
combined_experiments: combined_experiments
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
Split.configuration.enabled = config_enabled
|
|
22
23
|
Split.configuration.allow_multiple_experiments = allow_multiple_experiments
|
|
23
24
|
end
|
|
24
25
|
|
|
25
|
-
context
|
|
26
|
+
context "without config enabled" do
|
|
26
27
|
let!(:config_enabled) { false }
|
|
27
28
|
|
|
28
29
|
it "raises an error" do
|
|
29
|
-
expect
|
|
30
|
+
expect { ab_combined_test :combined_exp_1 }.to raise_error(Split::InvalidExperimentsFormatError)
|
|
30
31
|
end
|
|
31
32
|
end
|
|
32
33
|
|
|
33
|
-
context
|
|
34
|
+
context "multiple experiments disabled" do
|
|
34
35
|
let!(:allow_multiple_experiments) { false }
|
|
35
36
|
|
|
36
37
|
it "raises an error if multiple experiments is disabled" do
|
|
37
|
-
expect
|
|
38
|
+
expect { ab_combined_test :combined_exp_1 }.to raise_error(Split::InvalidExperimentsFormatError)
|
|
38
39
|
end
|
|
39
40
|
end
|
|
40
41
|
|
|
41
|
-
context
|
|
42
|
+
context "without combined experiments" do
|
|
42
43
|
let!(:combined_experiments) { nil }
|
|
43
44
|
|
|
44
45
|
it "raises an error" do
|
|
45
|
-
expect
|
|
46
|
+
expect { ab_combined_test :combined_exp_1 }.to raise_error(Split::InvalidExperimentsFormatError)
|
|
46
47
|
end
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
it "uses same alternative for all sub experiments and returns the alternative" do
|
|
50
51
|
allow(self).to receive(:get_alternative) { "test-alt" }
|
|
51
|
-
expect(self).to receive(:ab_test).with(:exp_1_click, {"control"=>0.5}, {"test-alt"=>0.5}) { "test-alt" }
|
|
52
|
-
expect(self).to receive(:ab_test).with(:exp_1_scroll, [{"control" => 0, "test-alt" => 1}])
|
|
52
|
+
expect(self).to receive(:ab_test).with(:exp_1_click, { "control"=>0.5 }, { "test-alt"=>0.5 }) { "test-alt" }
|
|
53
|
+
expect(self).to receive(:ab_test).with(:exp_1_scroll, [{ "control" => 0, "test-alt" => 1 }])
|
|
53
54
|
|
|
54
|
-
expect(ab_combined_test(
|
|
55
|
+
expect(ab_combined_test("combined_exp_1")).to eq("test-alt")
|
|
55
56
|
end
|
|
56
57
|
end
|
|
57
58
|
end
|
data/spec/configuration_spec.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require 'spec_helper'
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
require "spec_helper"
|
|
5
4
|
|
|
5
|
+
describe Split::Configuration do
|
|
6
6
|
before(:each) { @config = Split::Configuration.new }
|
|
7
7
|
|
|
8
8
|
it "should provide a default value for ignore_ip_addresses" do
|
|
@@ -58,17 +58,15 @@ describe Split::Configuration do
|
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
it "should load a metric" do
|
|
61
|
-
@config.experiments = {:
|
|
62
|
-
{:alternatives=>["control_opt", "other_opt"], :metric=>:my_metric}}
|
|
61
|
+
@config.experiments = { my_experiment: { alternatives: ["control_opt", "other_opt"], metric: :my_metric } }
|
|
63
62
|
|
|
64
63
|
expect(@config.metrics).not_to be_nil
|
|
65
64
|
expect(@config.metrics.keys).to eq([:my_metric])
|
|
66
65
|
end
|
|
67
66
|
|
|
68
67
|
it "should allow loading of experiment using experment_for" do
|
|
69
|
-
@config.experiments = {:
|
|
70
|
-
|
|
71
|
-
expect(@config.experiment_for(:my_experiment)).to eq({:alternatives=>["control_opt", ["other_opt"]]})
|
|
68
|
+
@config.experiments = { my_experiment: { alternatives: ["control_opt", "other_opt"], metric: :my_metric } }
|
|
69
|
+
expect(@config.experiment_for(:my_experiment)).to eq({ alternatives: ["control_opt", ["other_opt"]] })
|
|
72
70
|
end
|
|
73
71
|
|
|
74
72
|
context "when experiments are defined via YAML" do
|
|
@@ -82,12 +80,12 @@ describe Split::Configuration do
|
|
|
82
80
|
- Alt One
|
|
83
81
|
- Alt Two
|
|
84
82
|
resettable: false
|
|
85
|
-
|
|
83
|
+
eos
|
|
86
84
|
@config.experiments = YAML.load(experiments_yaml)
|
|
87
85
|
end
|
|
88
86
|
|
|
89
|
-
it
|
|
90
|
-
expect(@config.normalized_experiments).to eq({:
|
|
87
|
+
it "should normalize experiments" do
|
|
88
|
+
expect(@config.normalized_experiments).to eq({ my_experiment: { resettable: false, alternatives: ["Control Opt", ["Alt One", "Alt Two"]] } })
|
|
91
89
|
end
|
|
92
90
|
end
|
|
93
91
|
|
|
@@ -110,14 +108,14 @@ describe Split::Configuration do
|
|
|
110
108
|
Alt Two:
|
|
111
109
|
text: 'Alternative Two'
|
|
112
110
|
resettable: false
|
|
113
|
-
|
|
111
|
+
eos
|
|
114
112
|
@config.experiments = YAML.load(experiments_yaml)
|
|
115
113
|
end
|
|
116
114
|
|
|
117
|
-
it
|
|
115
|
+
it "should have metadata on the experiment" do
|
|
118
116
|
meta = @config.normalized_experiments[:my_experiment][:metadata]
|
|
119
117
|
expect(meta).to_not be nil
|
|
120
|
-
expect(meta[
|
|
118
|
+
expect(meta["Control Opt"]["text"]).to eq("Control Option")
|
|
121
119
|
end
|
|
122
120
|
end
|
|
123
121
|
|
|
@@ -138,25 +136,23 @@ describe Split::Configuration do
|
|
|
138
136
|
alternatives:
|
|
139
137
|
- a
|
|
140
138
|
- b
|
|
141
|
-
|
|
139
|
+
eos
|
|
142
140
|
@config.experiments = YAML.load(experiments_yaml)
|
|
143
141
|
end
|
|
144
142
|
|
|
145
143
|
it "should normalize experiments" do
|
|
146
|
-
expect(@config.normalized_experiments).to eq({:
|
|
147
|
-
[{"Alt One"=>0.1}, {"Alt Two"=>0.23}]]}, :
|
|
144
|
+
expect(@config.normalized_experiments).to eq({ my_experiment: { resettable: false, alternatives: [{ "Control Opt"=>0.67 },
|
|
145
|
+
[{ "Alt One"=>0.1 }, { "Alt Two"=>0.23 }]] }, another_experiment: { alternatives: ["a", ["b"]] } })
|
|
148
146
|
end
|
|
149
147
|
|
|
150
148
|
it "should recognize metrics" do
|
|
151
149
|
expect(@config.metrics).not_to be_nil
|
|
152
150
|
expect(@config.metrics.keys).to eq([:my_metric])
|
|
153
151
|
end
|
|
154
|
-
|
|
155
152
|
end
|
|
156
153
|
end
|
|
157
154
|
|
|
158
155
|
context "as symbols" do
|
|
159
|
-
|
|
160
156
|
context "with valid YAML" do
|
|
161
157
|
before do
|
|
162
158
|
experiments_yaml = <<-eos
|
|
@@ -166,21 +162,20 @@ describe Split::Configuration do
|
|
|
166
162
|
- Alt One
|
|
167
163
|
- Alt Two
|
|
168
164
|
:resettable: false
|
|
169
|
-
|
|
165
|
+
eos
|
|
170
166
|
@config.experiments = YAML.load(experiments_yaml)
|
|
171
167
|
end
|
|
172
168
|
|
|
173
169
|
it "should normalize experiments" do
|
|
174
|
-
expect(@config.normalized_experiments).to eq({:
|
|
170
|
+
expect(@config.normalized_experiments).to eq({ my_experiment: { resettable: false, alternatives: ["Control Opt", ["Alt One", "Alt Two"]] } })
|
|
175
171
|
end
|
|
176
172
|
end
|
|
177
173
|
|
|
178
174
|
context "with invalid YAML" do
|
|
179
|
-
|
|
180
175
|
let(:yaml) { YAML.load(input) }
|
|
181
176
|
|
|
182
177
|
context "with an empty string" do
|
|
183
|
-
let(:input) {
|
|
178
|
+
let(:input) { "" }
|
|
184
179
|
|
|
185
180
|
it "should raise an error" do
|
|
186
181
|
expect { @config.experiments = yaml }.to raise_error(Split::InvalidExperimentsFormatError)
|
|
@@ -188,7 +183,7 @@ describe Split::Configuration do
|
|
|
188
183
|
end
|
|
189
184
|
|
|
190
185
|
context "with just the YAML header" do
|
|
191
|
-
let(:input) {
|
|
186
|
+
let(:input) { "---" }
|
|
192
187
|
|
|
193
188
|
it "should raise an error" do
|
|
194
189
|
expect { @config.experiments = yaml }.to raise_error(Split::InvalidExperimentsFormatError)
|
|
@@ -200,35 +195,24 @@ describe Split::Configuration do
|
|
|
200
195
|
|
|
201
196
|
it "should normalize experiments" do
|
|
202
197
|
@config.experiments = {
|
|
203
|
-
:
|
|
204
|
-
:
|
|
205
|
-
{ :
|
|
206
|
-
{ :
|
|
207
|
-
{ :
|
|
198
|
+
my_experiment: {
|
|
199
|
+
alternatives: [
|
|
200
|
+
{ name: "control_opt", percent: 67 },
|
|
201
|
+
{ name: "second_opt", percent: 10 },
|
|
202
|
+
{ name: "third_opt", percent: 23 },
|
|
208
203
|
],
|
|
209
204
|
}
|
|
210
205
|
}
|
|
211
206
|
|
|
212
|
-
expect(@config.normalized_experiments).to eq({:
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
context 'redis_url configuration [DEPRECATED]' do
|
|
216
|
-
it 'should warn on set and assign to #redis' do
|
|
217
|
-
expect(@config).to receive(:warn).with(/\[DEPRECATED\]/) { nil }
|
|
218
|
-
@config.redis_url = 'example_url'
|
|
219
|
-
expect(@config.redis).to eq('example_url')
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
it 'should warn on get and return #redis' do
|
|
223
|
-
expect(@config).to receive(:warn).with(/\[DEPRECATED\]/) { nil }
|
|
224
|
-
@config.redis = 'example_url'
|
|
225
|
-
expect(@config.redis_url).to eq('example_url')
|
|
226
|
-
end
|
|
207
|
+
expect(@config.normalized_experiments).to eq({ my_experiment: { alternatives: [{ "control_opt"=>0.67 }, [{ "second_opt"=>0.1 }, { "third_opt"=>0.23 }]] } })
|
|
227
208
|
end
|
|
228
209
|
|
|
229
210
|
context "redis configuration" do
|
|
230
211
|
it "should default to local redis server" do
|
|
231
|
-
|
|
212
|
+
old_redis_url = ENV["REDIS_URL"]
|
|
213
|
+
ENV.delete("REDIS_URL")
|
|
214
|
+
expect(Split::Configuration.new.redis).to eq("redis://localhost:6379")
|
|
215
|
+
ENV["REDIS_URL"] = old_redis_url
|
|
232
216
|
end
|
|
233
217
|
|
|
234
218
|
it "should allow for redis url to be configured" do
|
|
@@ -238,8 +222,10 @@ describe Split::Configuration do
|
|
|
238
222
|
|
|
239
223
|
context "provided REDIS_URL environment variable" do
|
|
240
224
|
it "should use the ENV variable" do
|
|
241
|
-
|
|
225
|
+
old_redis_url = ENV["REDIS_URL"]
|
|
226
|
+
ENV["REDIS_URL"] = "env_redis_url"
|
|
242
227
|
expect(Split::Configuration.new.redis).to eq("env_redis_url")
|
|
228
|
+
ENV["REDIS_URL"] = old_redis_url
|
|
243
229
|
end
|
|
244
230
|
end
|
|
245
231
|
end
|
|
@@ -255,4 +241,14 @@ describe Split::Configuration do
|
|
|
255
241
|
end
|
|
256
242
|
end
|
|
257
243
|
|
|
244
|
+
context "persistence cookie domain" do
|
|
245
|
+
it "should default to nil" do
|
|
246
|
+
expect(@config.persistence_cookie_domain).to eq(nil)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
it "should allow the persistence cookie domain to be configured" do
|
|
250
|
+
@config.persistence_cookie_domain = ".acme.com"
|
|
251
|
+
expect(@config.persistence_cookie_domain).to eq(".acme.com")
|
|
252
|
+
end
|
|
253
|
+
end
|
|
258
254
|
end
|
|
@@ -1,106 +1,110 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
require "split/dashboard/pagination_helpers"
|
|
3
5
|
|
|
4
6
|
describe Split::DashboardPaginationHelpers do
|
|
5
7
|
include Split::DashboardPaginationHelpers
|
|
6
8
|
|
|
7
|
-
let(:url) {
|
|
9
|
+
let(:url) { "/split/" }
|
|
8
10
|
|
|
9
|
-
describe
|
|
10
|
-
context
|
|
11
|
+
describe "#pagination_per" do
|
|
12
|
+
context "when params empty" do
|
|
11
13
|
let(:params) { Hash[] }
|
|
12
14
|
|
|
13
|
-
it
|
|
15
|
+
it "returns the default (10)" do
|
|
16
|
+
default_per_page = Split.configuration.dashboard_pagination_default_per_page
|
|
17
|
+
expect(pagination_per).to eql default_per_page
|
|
14
18
|
expect(pagination_per).to eql 10
|
|
15
19
|
end
|
|
16
20
|
end
|
|
17
21
|
|
|
18
|
-
context
|
|
22
|
+
context "when params[:per] is 5" do
|
|
19
23
|
let(:params) { Hash[per: 5] }
|
|
20
24
|
|
|
21
|
-
it
|
|
25
|
+
it "returns 5" do
|
|
22
26
|
expect(pagination_per).to eql 5
|
|
23
27
|
end
|
|
24
28
|
end
|
|
25
29
|
end
|
|
26
30
|
|
|
27
|
-
describe
|
|
28
|
-
context
|
|
31
|
+
describe "#page_number" do
|
|
32
|
+
context "when params empty" do
|
|
29
33
|
let(:params) { Hash[] }
|
|
30
34
|
|
|
31
|
-
it
|
|
35
|
+
it "returns 1" do
|
|
32
36
|
expect(page_number).to eql 1
|
|
33
37
|
end
|
|
34
38
|
end
|
|
35
39
|
|
|
36
40
|
context 'when params[:page] is "2"' do
|
|
37
|
-
let(:params) { Hash[page:
|
|
41
|
+
let(:params) { Hash[page: "2"] }
|
|
38
42
|
|
|
39
|
-
it
|
|
43
|
+
it "returns 2" do
|
|
40
44
|
expect(page_number).to eql 2
|
|
41
45
|
end
|
|
42
46
|
end
|
|
43
47
|
end
|
|
44
48
|
|
|
45
|
-
describe
|
|
49
|
+
describe "#paginated" do
|
|
46
50
|
let(:collection) { (1..20).to_a }
|
|
47
|
-
let(:params) { Hash[per:
|
|
51
|
+
let(:params) { Hash[per: "5", page: "3"] }
|
|
48
52
|
|
|
49
53
|
it { expect(paginated(collection)).to eql [11, 12, 13, 14, 15] }
|
|
50
54
|
end
|
|
51
55
|
|
|
52
|
-
describe
|
|
53
|
-
context
|
|
56
|
+
describe "#show_first_page_tag?" do
|
|
57
|
+
context "when page is 1" do
|
|
54
58
|
it { expect(show_first_page_tag?).to be false }
|
|
55
59
|
end
|
|
56
60
|
|
|
57
|
-
context
|
|
58
|
-
let(:params) { Hash[page:
|
|
61
|
+
context "when page is 3" do
|
|
62
|
+
let(:params) { Hash[page: "3"] }
|
|
59
63
|
it { expect(show_first_page_tag?).to be true }
|
|
60
64
|
end
|
|
61
65
|
end
|
|
62
66
|
|
|
63
|
-
describe
|
|
67
|
+
describe "#first_page_tag" do
|
|
64
68
|
it { expect(first_page_tag).to eql '<a href="/split?page=1&per=10">1</a>' }
|
|
65
69
|
end
|
|
66
70
|
|
|
67
|
-
describe
|
|
68
|
-
context
|
|
71
|
+
describe "#show_first_ellipsis_tag?" do
|
|
72
|
+
context "when page is 1" do
|
|
69
73
|
it { expect(show_first_ellipsis_tag?).to be false }
|
|
70
74
|
end
|
|
71
75
|
|
|
72
|
-
context
|
|
73
|
-
let(:params) { Hash[page:
|
|
76
|
+
context "when page is 4" do
|
|
77
|
+
let(:params) { Hash[page: "4"] }
|
|
74
78
|
it { expect(show_first_ellipsis_tag?).to be true }
|
|
75
79
|
end
|
|
76
80
|
end
|
|
77
81
|
|
|
78
|
-
describe
|
|
79
|
-
it { expect(ellipsis_tag).to eql
|
|
82
|
+
describe "#ellipsis_tag" do
|
|
83
|
+
it { expect(ellipsis_tag).to eql "<span>...</span>" }
|
|
80
84
|
end
|
|
81
85
|
|
|
82
|
-
describe
|
|
83
|
-
context
|
|
86
|
+
describe "#show_prev_page_tag?" do
|
|
87
|
+
context "when page is 1" do
|
|
84
88
|
it { expect(show_prev_page_tag?).to be false }
|
|
85
89
|
end
|
|
86
90
|
|
|
87
|
-
context
|
|
88
|
-
let(:params) { Hash[page:
|
|
91
|
+
context "when page is 2" do
|
|
92
|
+
let(:params) { Hash[page: "2"] }
|
|
89
93
|
it { expect(show_prev_page_tag?).to be true }
|
|
90
94
|
end
|
|
91
95
|
end
|
|
92
96
|
|
|
93
|
-
describe
|
|
94
|
-
context
|
|
95
|
-
let(:params) { Hash[page:
|
|
97
|
+
describe "#prev_page_tag" do
|
|
98
|
+
context "when page is 2" do
|
|
99
|
+
let(:params) { Hash[page: "2"] }
|
|
96
100
|
|
|
97
101
|
it do
|
|
98
102
|
expect(prev_page_tag).to eql '<a href="/split?page=1&per=10">1</a>'
|
|
99
103
|
end
|
|
100
104
|
end
|
|
101
105
|
|
|
102
|
-
context
|
|
103
|
-
let(:params) { Hash[page:
|
|
106
|
+
context "when page is 3" do
|
|
107
|
+
let(:params) { Hash[page: "3"] }
|
|
104
108
|
|
|
105
109
|
it do
|
|
106
110
|
expect(prev_page_tag).to eql '<a href="/split?page=2&per=10">2</a>'
|
|
@@ -108,90 +112,90 @@ describe Split::DashboardPaginationHelpers do
|
|
|
108
112
|
end
|
|
109
113
|
end
|
|
110
114
|
|
|
111
|
-
describe
|
|
112
|
-
context
|
|
115
|
+
describe "#show_prev_page_tag?" do
|
|
116
|
+
context "when page is 1" do
|
|
113
117
|
it { expect(show_prev_page_tag?).to be false }
|
|
114
118
|
end
|
|
115
119
|
|
|
116
|
-
context
|
|
117
|
-
let(:params) { Hash[page:
|
|
120
|
+
context "when page is 2" do
|
|
121
|
+
let(:params) { Hash[page: "2"] }
|
|
118
122
|
it { expect(show_prev_page_tag?).to be true }
|
|
119
123
|
end
|
|
120
124
|
end
|
|
121
125
|
|
|
122
|
-
describe
|
|
123
|
-
context
|
|
124
|
-
let(:params) { Hash[page:
|
|
125
|
-
it { expect(current_page_tag).to eql
|
|
126
|
+
describe "#current_page_tag" do
|
|
127
|
+
context "when page is 1" do
|
|
128
|
+
let(:params) { Hash[page: "1"] }
|
|
129
|
+
it { expect(current_page_tag).to eql "<span><b>1</b></span>" }
|
|
126
130
|
end
|
|
127
131
|
|
|
128
|
-
context
|
|
129
|
-
let(:params) { Hash[page:
|
|
130
|
-
it { expect(current_page_tag).to eql
|
|
132
|
+
context "when page is 2" do
|
|
133
|
+
let(:params) { Hash[page: "2"] }
|
|
134
|
+
it { expect(current_page_tag).to eql "<span><b>2</b></span>" }
|
|
131
135
|
end
|
|
132
136
|
end
|
|
133
137
|
|
|
134
|
-
describe
|
|
135
|
-
context
|
|
136
|
-
let(:params) { Hash[page:
|
|
138
|
+
describe "#show_next_page_tag?" do
|
|
139
|
+
context "when page is 2" do
|
|
140
|
+
let(:params) { Hash[page: "2"] }
|
|
137
141
|
|
|
138
|
-
context
|
|
142
|
+
context "when collection length is 20" do
|
|
139
143
|
let(:collection) { (1..20).to_a }
|
|
140
144
|
it { expect(show_next_page_tag?(collection)).to be false }
|
|
141
145
|
end
|
|
142
146
|
|
|
143
|
-
context
|
|
147
|
+
context "when collection length is 25" do
|
|
144
148
|
let(:collection) { (1..25).to_a }
|
|
145
149
|
it { expect(show_next_page_tag?(collection)).to be true }
|
|
146
150
|
end
|
|
147
151
|
end
|
|
148
152
|
end
|
|
149
153
|
|
|
150
|
-
describe
|
|
151
|
-
context
|
|
152
|
-
let(:params) { Hash[page:
|
|
154
|
+
describe "#next_page_tag" do
|
|
155
|
+
context "when page is 1" do
|
|
156
|
+
let(:params) { Hash[page: "1"] }
|
|
153
157
|
it { expect(next_page_tag).to eql '<a href="/split?page=2&per=10">2</a>' }
|
|
154
158
|
end
|
|
155
159
|
|
|
156
|
-
context
|
|
157
|
-
let(:params) { Hash[page:
|
|
160
|
+
context "when page is 2" do
|
|
161
|
+
let(:params) { Hash[page: "2"] }
|
|
158
162
|
it { expect(next_page_tag).to eql '<a href="/split?page=3&per=10">3</a>' }
|
|
159
163
|
end
|
|
160
164
|
end
|
|
161
165
|
|
|
162
|
-
describe
|
|
163
|
-
context
|
|
166
|
+
describe "#total_pages" do
|
|
167
|
+
context "when collection length is 30" do
|
|
164
168
|
let(:collection) { (1..30).to_a }
|
|
165
169
|
it { expect(total_pages(collection)).to eql 3 }
|
|
166
170
|
end
|
|
167
171
|
|
|
168
|
-
context
|
|
172
|
+
context "when collection length is 35" do
|
|
169
173
|
let(:collection) { (1..35).to_a }
|
|
170
174
|
it { expect(total_pages(collection)).to eql 4 }
|
|
171
175
|
end
|
|
172
176
|
end
|
|
173
177
|
|
|
174
|
-
describe
|
|
178
|
+
describe "#show_last_ellipsis_tag?" do
|
|
175
179
|
let(:collection) { (1..30).to_a }
|
|
176
|
-
let(:params) { Hash[per:
|
|
180
|
+
let(:params) { Hash[per: "5", page: "2"] }
|
|
177
181
|
it { expect(show_last_ellipsis_tag?(collection)).to be true }
|
|
178
182
|
end
|
|
179
183
|
|
|
180
|
-
describe
|
|
184
|
+
describe "#show_last_page_tag?" do
|
|
181
185
|
let(:collection) { (1..30).to_a }
|
|
182
186
|
|
|
183
|
-
context
|
|
184
|
-
let(:params) { Hash[per:
|
|
187
|
+
context "when page is 5/6" do
|
|
188
|
+
let(:params) { Hash[per: "5", page: "5"] }
|
|
185
189
|
it { expect(show_last_page_tag?(collection)).to be false }
|
|
186
190
|
end
|
|
187
191
|
|
|
188
|
-
context
|
|
189
|
-
let(:params) { Hash[per:
|
|
192
|
+
context "when page is 4/6" do
|
|
193
|
+
let(:params) { Hash[per: "5", page: "4"] }
|
|
190
194
|
it { expect(show_last_page_tag?(collection)).to be true }
|
|
191
195
|
end
|
|
192
196
|
end
|
|
193
197
|
|
|
194
|
-
describe
|
|
198
|
+
describe "#last_page_tag" do
|
|
195
199
|
let(:collection) { (1..30).to_a }
|
|
196
200
|
it { expect(last_page_tag(collection)).to eql '<a href="/split?page=3&per=10">3</a>' }
|
|
197
201
|
end
|