From 6d53147fcfb87a829553d06d324829c989c4f478 Mon Sep 17 00:00:00 2001 From: Eugene Chaikin Date: Wed, 21 May 2025 15:30:13 +0200 Subject: [PATCH 1/5] Create controller concern for `move` action --- .../concerns/solidus_admin/moveable.rb | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 admin/app/controllers/concerns/solidus_admin/moveable.rb diff --git a/admin/app/controllers/concerns/solidus_admin/moveable.rb b/admin/app/controllers/concerns/solidus_admin/moveable.rb new file mode 100644 index 00000000000..a1f3756d0de --- /dev/null +++ b/admin/app/controllers/concerns/solidus_admin/moveable.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module SolidusAdmin::Moveable + extend ActiveSupport::Concern + + included do + before_action :load_moveable, only: [:move] + end + + def move + @moveable.insert_at(params.require(:position).to_i) + + respond_to do |format| + format.js { head :no_content } + end + end + + private + + def load_moveable + @moveable = moveable_class.find(params.require(:id)) + authorize! action_name, @moveable + end + + def moveable_class + "Spree::#{self.class.name.demodulize.remove('Controller').singularize}".constantize + rescue NameError + raise NameError, + "could not infer model class from #{self.class.name}. Please override `moveable_class` to specify it explicitly." + end +end From 0eb580020e30cc3007e8707c32f239e27cfef05f Mon Sep 17 00:00:00 2001 From: Eugene Chaikin Date: Wed, 21 May 2025 15:35:28 +0200 Subject: [PATCH 2/5] Cleanup controllers with moveable concern --- .../solidus_admin/option_types_controller.rb | 18 +----------------- .../payment_methods_controller.rb | 18 +----------------- .../solidus_admin/taxonomies_controller.rb | 18 +----------------- 3 files changed, 3 insertions(+), 51 deletions(-) diff --git a/admin/app/controllers/solidus_admin/option_types_controller.rb b/admin/app/controllers/solidus_admin/option_types_controller.rb index 444f1bbbafa..18b9ce8f1df 100644 --- a/admin/app/controllers/solidus_admin/option_types_controller.rb +++ b/admin/app/controllers/solidus_admin/option_types_controller.rb @@ -3,8 +3,7 @@ module SolidusAdmin class OptionTypesController < SolidusAdmin::BaseController include SolidusAdmin::ControllerHelpers::Search - - before_action :load_option_type, only: [:move] + include SolidusAdmin::Moveable def index option_types = apply_search_to( @@ -19,14 +18,6 @@ def index end end - def move - @option_type.insert_at(params[:position].to_i) - - respond_to do |format| - format.js { head :no_content } - end - end - def destroy @option_types = Spree::OptionType.where(id: params[:id]) @@ -35,12 +26,5 @@ def destroy flash[:notice] = t('.success') redirect_back_or_to option_types_path, status: :see_other end - - private - - def load_option_type - @option_type = Spree::OptionType.find(params[:id]) - authorize! action_name, @option_type - end end end diff --git a/admin/app/controllers/solidus_admin/payment_methods_controller.rb b/admin/app/controllers/solidus_admin/payment_methods_controller.rb index 684eb7381f3..fc3ce0316dd 100644 --- a/admin/app/controllers/solidus_admin/payment_methods_controller.rb +++ b/admin/app/controllers/solidus_admin/payment_methods_controller.rb @@ -3,8 +3,7 @@ module SolidusAdmin class PaymentMethodsController < SolidusAdmin::BaseController include SolidusAdmin::ControllerHelpers::Search - - before_action :load_payment_method, only: [:move] + include SolidusAdmin::Moveable search_scope(:all) search_scope(:active, default: true, &:active) @@ -25,14 +24,6 @@ def index end end - def move - @payment_method.insert_at(params[:position].to_i) - - respond_to do |format| - format.js { head :no_content } - end - end - def destroy @payment_methods = Spree::PaymentMethod.where(id: params[:id]) @@ -41,12 +32,5 @@ def destroy flash[:notice] = t('.success') redirect_back_or_to payment_methods_path, status: :see_other end - - private - - def load_payment_method - @payment_method = Spree::PaymentMethod.find_by!(id: params[:id]) - authorize! action_name, @payment_method - end end end diff --git a/admin/app/controllers/solidus_admin/taxonomies_controller.rb b/admin/app/controllers/solidus_admin/taxonomies_controller.rb index fb0387d075a..3c6b4cdc2db 100644 --- a/admin/app/controllers/solidus_admin/taxonomies_controller.rb +++ b/admin/app/controllers/solidus_admin/taxonomies_controller.rb @@ -3,8 +3,7 @@ module SolidusAdmin class TaxonomiesController < SolidusAdmin::BaseController include SolidusAdmin::ControllerHelpers::Search - - before_action :load_taxonomy, only: [:move] + include SolidusAdmin::Moveable def index taxonomies = apply_search_to( @@ -19,14 +18,6 @@ def index end end - def move - @taxonomy.insert_at(params[:position].to_i) - - respond_to do |format| - format.js { head :no_content } - end - end - def destroy @taxonomies = Spree::Taxonomy.where(id: params[:id]) @@ -35,12 +26,5 @@ def destroy flash[:notice] = t('.success') redirect_back_or_to taxonomies_path, status: :see_other end - - private - - def load_taxonomy - @taxonomy = Spree::Taxonomy.find(params[:id]) - authorize! action_name, @taxonomy - end end end From 722db432fa5f075703426073396ad07c9ef05808 Mon Sep 17 00:00:00 2001 From: Eugene Chaikin Date: Mon, 26 May 2025 19:49:25 +0200 Subject: [PATCH 3/5] Add shared examples for sorting --- .../shared_examples/moveable.rb | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 admin/lib/solidus_admin/testing_support/shared_examples/moveable.rb diff --git a/admin/lib/solidus_admin/testing_support/shared_examples/moveable.rb b/admin/lib/solidus_admin/testing_support/shared_examples/moveable.rb new file mode 100644 index 00000000000..8c942242c15 --- /dev/null +++ b/admin/lib/solidus_admin/testing_support/shared_examples/moveable.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +RSpec.shared_examples_for "requests: moveable" do + let(:admin_user) { create(:admin_user) } + let(:record) { create(factory, position: 1) } + let(:request_path) do + solidus_admin.send("move_#{record.model_name.singular_route_key}_path", record, format: :js) + end + + before do + allow_any_instance_of(SolidusAdmin::BaseController).to receive(:spree_current_user).and_return(admin_user) + end + + describe "PATCH /move" do + it "updates record's position" do + expect { patch request_path, params: { position: 2 } }.to change { record.reload.position }.from(1).to(2) + expect(response).to have_http_status(:no_content) + end + end +end + +RSpec.shared_examples_for "features: sortable" do + let(:factory_attrs) { {} } + + before do + create(factory, displayed_attribute => "First", position: 1, **factory_attrs) + create(factory, displayed_attribute => "Second", position: 2, **factory_attrs) + visit path + end + + it "allows sorting via drag and drop" do + row_1 = find_row("First") + row_2 = find_row("Second") + + row_2.drag_to row_1 + + expect(find("table tbody tr:first-child")).to have_text("Second") + expect(find("table tbody tr:last-child")).to have_text("First") + end +end From cbefbccf4cc8c68eecf8f8d81710fafadd454c1c Mon Sep 17 00:00:00 2001 From: Eugene Chaikin Date: Tue, 27 May 2025 10:25:07 +0200 Subject: [PATCH 4/5] Add missing specs for sortables --- admin/spec/features/payment_methods_spec.rb | 7 +++++++ admin/spec/features/taxonomies_spec.rb | 7 +++++++ .../requests/solidus_admin/payment_methods_spec.rb | 11 +++++++++++ admin/spec/requests/solidus_admin/taxonomies_spec.rb | 10 ++++++++++ 4 files changed, 35 insertions(+) create mode 100644 admin/spec/requests/solidus_admin/payment_methods_spec.rb create mode 100644 admin/spec/requests/solidus_admin/taxonomies_spec.rb diff --git a/admin/spec/features/payment_methods_spec.rb b/admin/spec/features/payment_methods_spec.rb index 55ebf3ec74b..06b4dc0f3ab 100644 --- a/admin/spec/features/payment_methods_spec.rb +++ b/admin/spec/features/payment_methods_spec.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'spec_helper' +require "solidus_admin/testing_support/shared_examples/moveable" describe "Payment Methods", :js, type: :feature do before { sign_in create(:admin_user, email: 'admin@example.com') } @@ -45,4 +46,10 @@ expect(page).not_to have_content("Check") expect(Spree::PaymentMethod.count).to eq(3) end + + it_behaves_like "features: sortable" do + let(:factory) { :payment_method } + let(:displayed_attribute) { :name } + let(:path) { solidus_admin.payment_methods_path } + end end diff --git a/admin/spec/features/taxonomies_spec.rb b/admin/spec/features/taxonomies_spec.rb index 88cb0ec782a..33fab23194e 100644 --- a/admin/spec/features/taxonomies_spec.rb +++ b/admin/spec/features/taxonomies_spec.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'spec_helper' +require "solidus_admin/testing_support/shared_examples/moveable" describe "Taxonomies", :js, type: :feature do before { sign_in create(:admin_user, email: 'admin@example.com') } @@ -21,4 +22,10 @@ expect(page).not_to have_content("Categories") expect(Spree::Taxonomy.count).to eq(1) end + + it_behaves_like "features: sortable" do + let(:factory) { :taxonomy } + let(:displayed_attribute) { :name } + let(:path) { solidus_admin.taxonomies_path } + end end diff --git a/admin/spec/requests/solidus_admin/payment_methods_spec.rb b/admin/spec/requests/solidus_admin/payment_methods_spec.rb new file mode 100644 index 00000000000..5cc99dae2ab --- /dev/null +++ b/admin/spec/requests/solidus_admin/payment_methods_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require "spec_helper" +require "solidus_admin/testing_support/shared_examples/moveable" + +RSpec.describe "SolidusAdmin::PaymentMethodsController", type: :request do + it_behaves_like "requests: moveable" do + let(:factory) { :payment_method } + let(:request_path) { solidus_admin.move_payment_method_path(record, format: :js) } + end +end diff --git a/admin/spec/requests/solidus_admin/taxonomies_spec.rb b/admin/spec/requests/solidus_admin/taxonomies_spec.rb new file mode 100644 index 00000000000..0c93d5551c1 --- /dev/null +++ b/admin/spec/requests/solidus_admin/taxonomies_spec.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require "spec_helper" +require "solidus_admin/testing_support/shared_examples/moveable" + +RSpec.describe "SolidusAdmin::TaxonomiesController", type: :request do + it_behaves_like "requests: moveable" do + let(:factory) { :taxonomy } + end +end From c057d37268e13183c44b6f580204f6da40e1e29d Mon Sep 17 00:00:00 2001 From: Eugene Chaikin Date: Tue, 10 Jun 2025 11:57:09 +0200 Subject: [PATCH 5/5] Update shared examples for sorting Sortable elements might not always be inside a table, so we'll identify them by presence of "data-controller='sortable'" on their parent. --- .../testing_support/shared_examples/moveable.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/admin/lib/solidus_admin/testing_support/shared_examples/moveable.rb b/admin/lib/solidus_admin/testing_support/shared_examples/moveable.rb index 8c942242c15..a321ea5faa4 100644 --- a/admin/lib/solidus_admin/testing_support/shared_examples/moveable.rb +++ b/admin/lib/solidus_admin/testing_support/shared_examples/moveable.rb @@ -21,6 +21,7 @@ RSpec.shared_examples_for "features: sortable" do let(:factory_attrs) { {} } + let(:scope) { "body" } before do create(factory, displayed_attribute => "First", position: 1, **factory_attrs) @@ -29,12 +30,15 @@ end it "allows sorting via drag and drop" do - row_1 = find_row("First") - row_2 = find_row("Second") + within(scope) do + expect(find("[data-controller='sortable']").all(:xpath, "./*").first).to have_text("First") + expect(find("[data-controller='sortable']").all(:xpath, "./*").last).to have_text("Second") - row_2.drag_to row_1 + rows = find("[data-controller='sortable']").all(:xpath, "./*") + rows[1].drag_to rows[0] - expect(find("table tbody tr:first-child")).to have_text("Second") - expect(find("table tbody tr:last-child")).to have_text("First") + expect(find("[data-controller='sortable']").all(:xpath, "./*").first).to have_text("Second") + expect(find("[data-controller='sortable']").all(:xpath, "./*").last).to have_text("First") + end end end