summaryrefslogtreecommitdiff
path: root/spec/support/shared_examples/relative_positioning_shared_examples.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/support/shared_examples/relative_positioning_shared_examples.rb')
-rw-r--r--spec/support/shared_examples/relative_positioning_shared_examples.rb124
1 files changed, 77 insertions, 47 deletions
diff --git a/spec/support/shared_examples/relative_positioning_shared_examples.rb b/spec/support/shared_examples/relative_positioning_shared_examples.rb
index 5ee62644c54..9837ba806db 100644
--- a/spec/support/shared_examples/relative_positioning_shared_examples.rb
+++ b/spec/support/shared_examples/relative_positioning_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_examples "a class that supports relative positioning" do
+RSpec.shared_examples 'a class that supports relative positioning' do
let(:item1) { create(factory, default_params) }
let(:item2) { create(factory, default_params) }
let(:new_item) { create(factory, default_params) }
@@ -9,24 +9,38 @@ RSpec.shared_examples "a class that supports relative positioning" do
create(factory, params.merge(default_params))
end
- describe '.move_to_end' do
- it 'moves the object to the end' do
- item1.update(relative_position: 5)
- item2.update(relative_position: 15)
+ def create_items_with_positions(positions)
+ positions.map do |position|
+ create_item(relative_position: position)
+ end
+ end
- described_class.move_to_end([item1, item2])
+ describe '.move_nulls_to_end' do
+ it 'moves items with null relative_position to the end' do
+ skip("#{item1} has a default relative position") if item1.relative_position
+ skip("#{item2} has a default relative position") if item2.relative_position
+
+ described_class.move_nulls_to_end([item1, item2])
expect(item2.prev_relative_position).to eq item1.relative_position
expect(item1.prev_relative_position).to eq nil
expect(item2.next_relative_position).to eq nil
end
+ it 'moves the item near the start position when there are no existing positions' do
+ skip("#{item1} has a default relative position") if item1.relative_position
+
+ described_class.move_nulls_to_end([item1])
+
+ expect(item1.relative_position).to eq(described_class::START_POSITION + described_class::IDEAL_DISTANCE)
+ end
+
it 'does not perform any moves if all items have their relative_position set' do
item1.update!(relative_position: 1)
expect(item1).not_to receive(:save)
- described_class.move_to_end([item1])
+ described_class.move_nulls_to_end([item1])
end
end
@@ -96,46 +110,6 @@ RSpec.shared_examples "a class that supports relative positioning" do
end
end
- describe '#shift_after?' do
- before do
- [item1, item2].each do |item1|
- item1.move_to_end && item1.save
- end
- end
-
- it 'returns true' do
- item1.update(relative_position: item2.relative_position - 1)
-
- expect(item1.shift_after?).to be_truthy
- end
-
- it 'returns false' do
- item1.update(relative_position: item2.relative_position - 2)
-
- expect(item1.shift_after?).to be_falsey
- end
- end
-
- describe '#shift_before?' do
- before do
- [item1, item2].each do |item1|
- item1.move_to_end && item1.save
- end
- end
-
- it 'returns true' do
- item1.update(relative_position: item2.relative_position + 1)
-
- expect(item1.shift_before?).to be_truthy
- end
-
- it 'returns false' do
- item1.update(relative_position: item2.relative_position + 2)
-
- expect(item1.shift_before?).to be_falsey
- end
- end
-
describe '#move_between' do
before do
[item1, item2].each do |item1|
@@ -249,5 +223,61 @@ RSpec.shared_examples "a class that supports relative positioning" do
expect(new_item.relative_position).to be(100)
end
+
+ it 'avoids N+1 queries when rebalancing other items' do
+ items = create_items_with_positions([100, 101, 102])
+
+ count = ActiveRecord::QueryRecorder.new do
+ new_item.move_between(items[-2], items[-1])
+ end
+
+ items = create_items_with_positions([150, 151, 152, 153, 154])
+
+ expect { new_item.move_between(items[-2], items[-1]) }.not_to exceed_query_limit(count)
+ end
+ end
+
+ describe '#move_sequence_before' do
+ it 'moves the whole sequence of items to the middle of the nearest gap' do
+ items = create_items_with_positions([90, 100, 101, 102])
+
+ items.last.move_sequence_before
+ items.last.save!
+
+ positions = items.map { |item| item.reload.relative_position }
+ expect(positions).to eq([90, 95, 96, 102])
+ end
+
+ it 'finds a gap if there are unused positions' do
+ items = create_items_with_positions([100, 101, 102])
+
+ items.last.move_sequence_before
+ items.last.save!
+
+ positions = items.map { |item| item.reload.relative_position }
+ expect(positions).to eq([50, 51, 102])
+ end
+ end
+
+ describe '#move_sequence_after' do
+ it 'moves the whole sequence of items to the middle of the nearest gap' do
+ items = create_items_with_positions([100, 101, 102, 110])
+
+ items.first.move_sequence_after
+ items.first.save!
+
+ positions = items.map { |item| item.reload.relative_position }
+ expect(positions).to eq([100, 105, 106, 110])
+ end
+
+ it 'finds a gap if there are unused positions' do
+ items = create_items_with_positions([100, 101, 102])
+
+ items.first.move_sequence_after
+ items.first.save!
+
+ positions = items.map { |item| item.reload.relative_position }
+ expect(positions).to eq([100, 601, 602])
+ end
end
end