diff --git a/api/spec/features/checkout_spec.rb b/api/spec/features/checkout_spec.rb index f8638177fe0..21af915ed69 100644 --- a/api/spec/features/checkout_spec.rb +++ b/api/spec/features/checkout_spec.rb @@ -7,8 +7,6 @@ module Spree before do stub_spree_preferences(Spree::Api::Config, requires_authentication: false) end - let!(:promotion) { FactoryBot.create(:promotion, :with_order_adjustment, code: 'foo', weighted_order_adjustment_amount: 10) } - let(:promotion_code) { promotion.codes.first } let!(:store) { FactoryBot.create(:store) } let(:bill_address) { FactoryBot.create(:address) } let(:ship_address) { FactoryBot.create(:address) } @@ -62,14 +60,6 @@ def create_line_item(variant, quantity = 1) expect(response).to have_http_status(:created) end - def add_promotion(_promotion) - expect { - post "/api/orders/#{@order.number}/coupon_codes", - params: { coupon_code: promotion_code.value } - }.to change { @order.promotions.count }.by 1 - expect(response).to have_http_status(:ok) - end - def add_address(address, billing: true) address_type = billing ? :bill_address : :ship_address # It seems we are missing an order-scoped address api endpoint since we need @@ -103,8 +93,8 @@ def assert_order_expectations expect(@order.state).to eq 'complete' expect(@order.completed_at).to be_a ActiveSupport::TimeWithZone expect(@order.item_total).to eq 600.00 - expect(@order.total).to eq 600.00 - expect(@order.adjustment_total).to eq(-10.00) + expect(@order.total).to eq 610.00 + expect(@order.adjustment_total).to eq(0) expect(@order.shipment_total).to eq 10.00 expect(@order.user).to eq @user expect(@order.bill_address).to eq bill_address @@ -112,7 +102,6 @@ def assert_order_expectations expect(@order.payments.length).to eq 1 expect(@order.line_items.any? { |li| li.variant == variant_1 && li.quantity == 2 }).to eq true expect(@order.line_items.any? { |li| li.variant == variant_2 && li.quantity == 2 }).to eq true - expect(@order.promotions).to eq [promotion] end it "is able to checkout with individualized requests" do @@ -120,7 +109,6 @@ def assert_order_expectations create_order create_line_item(variant_1, 2) - add_promotion(promotion) create_line_item(variant_2, 2) add_address(bill_address) @@ -152,7 +140,6 @@ def assert_order_expectations } }) - add_promotion(promotion) add_payment advance @@ -180,7 +167,6 @@ def assert_order_expectations } }) - add_promotion(promotion) add_payment advance diff --git a/api/spec/requests/spree/api/coupon_codes_spec.rb b/api/spec/requests/spree/api/coupon_codes_spec.rb index c7324d9c58d..993d5852422 100644 --- a/api/spec/requests/spree/api/coupon_codes_spec.rb +++ b/api/spec/requests/spree/api/coupon_codes_spec.rb @@ -132,7 +132,6 @@ module Spree::Api subject expect(response.status).to eq(422) - expect(order.reload.promotions).to eq([]) expect(json_response).to eq({ "success" => nil, "error" => I18n.t('spree.coupon_code_not_present'), diff --git a/api/spec/requests/spree/api/promotion_application_spec.rb b/api/spec/requests/spree/api/promotion_application_spec.rb deleted file mode 100644 index bda24996eb6..00000000000 --- a/api/spec/requests/spree/api/promotion_application_spec.rb +++ /dev/null @@ -1,50 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -module Spree::Api - describe 'Promotion application', type: :request do - before do - stub_authentication! - end - - context "with an available promotion" do - let!(:order) { create(:order_with_line_items, line_items_count: 1) } - let!(:promotion) do - promotion = create(:promotion, name: "10% off", code: "10off") - calculator = Spree::Calculator::FlatPercentItemTotal.create(preferred_flat_percent: "10") - action = Spree::Promotion::Actions::CreateItemAdjustments.create(calculator: calculator) - promotion.actions << action - promotion - end - - it "can apply a coupon code to the order" do - expect(order.total).to eq(110.00) - post spree.api_order_coupon_codes_path(order), params: { coupon_code: "10off", order_token: order.guest_token } - expect(response.status).to eq(200) - expect(order.reload.total).to eq(109.00) - expect(json_response["success"]).to eq("The coupon code was successfully applied to your order.") - expect(json_response["error"]).to be_blank - expect(json_response["successful"]).to be true - expect(json_response["status_code"]).to eq("coupon_code_applied") - end - - context "with an expired promotion" do - before do - promotion.starts_at = 2.weeks.ago - promotion.expires_at = 1.week.ago - promotion.save - end - - it "fails to apply" do - post spree.api_order_coupon_codes_path(order), params: { coupon_code: "10off", order_token: order.guest_token } - expect(response.status).to eq(422) - expect(json_response["success"]).to be_blank - expect(json_response["error"]).to eq("The coupon code is expired") - expect(json_response["successful"]).to be false - expect(json_response["status_code"]).to eq("coupon_code_expired") - end - end - end - end -end diff --git a/legacy_promotions/lib/solidus_legacy_promotions.rb b/legacy_promotions/lib/solidus_legacy_promotions.rb index 3f5857cad20..11e190aa6e5 100644 --- a/legacy_promotions/lib/solidus_legacy_promotions.rb +++ b/legacy_promotions/lib/solidus_legacy_promotions.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "solidus_core" +require "solidus_api" require "solidus_support" module SolidusLegacyPromotions diff --git a/legacy_promotions/solidus_legacy_promotions.gemspec b/legacy_promotions/solidus_legacy_promotions.gemspec index 778d9fc367f..a31c951abd4 100644 --- a/legacy_promotions/solidus_legacy_promotions.gemspec +++ b/legacy_promotions/solidus_legacy_promotions.gemspec @@ -24,5 +24,6 @@ Gem::Specification.new do |s| s.required_rubygems_version = '>= 1.8.23' s.add_dependency 'solidus_core', s.version + s.add_dependency 'solidus_api', s.version s.add_dependency 'solidus_support' end diff --git a/legacy_promotions/spec/features/api/checkout_spec.rb b/legacy_promotions/spec/features/api/checkout_spec.rb new file mode 100644 index 00000000000..3455f07d366 --- /dev/null +++ b/legacy_promotions/spec/features/api/checkout_spec.rb @@ -0,0 +1,192 @@ +# frozen_string_literal: true + +require 'rails_helper' + +module Spree + RSpec.describe 'Api Feature Specs', type: :request do + before do + stub_spree_preferences(Spree::Api::Config, requires_authentication: false) + end + let!(:promotion) { FactoryBot.create(:promotion, :with_order_adjustment, code: 'foo', weighted_order_adjustment_amount: 10) } + let(:promotion_code) { promotion.codes.first } + let!(:store) { FactoryBot.create(:store) } + let(:bill_address) { FactoryBot.create(:address) } + let(:ship_address) { FactoryBot.create(:address) } + let(:variant_1) { FactoryBot.create(:variant, price: 100.00) } + let(:variant_2) { FactoryBot.create(:variant, price: 200.00) } + let(:payment_method) { FactoryBot.create(:check_payment_method) } + let!(:shipping_method) do + FactoryBot.create(:shipping_method).tap do |shipping_method| + shipping_method.zones.first.zone_members.create!(zoneable: ship_address.country) + shipping_method.calculator.set_preference(:amount, 10.0) + end + end + + def parsed + JSON.parse(response.body) + end + + def login + expect { + post '/api/users', params: { + user: { + email: "featurecheckoutuser@example.com", + password: "featurecheckoutuser" + } + } + }.to change { Spree.user_class.count }.by 1 + expect(response).to have_http_status(:created) + @user = Spree.user_class.find(parsed['id']) + + # copied from api testing helpers support since we can't really sign in + allow(Spree::LegacyUser).to receive(:find_by).with(hash_including(:spree_api_key)) { @user } + end + + def create_order(order_params: {}) + expect { post '/api/orders', params: order_params }.to change { Order.count }.by 1 + expect(response).to have_http_status(:created) + @order = Order.find(parsed['id']) + expect(@order.email).to eq "featurecheckoutuser@example.com" + end + + def update_order(order_params: {}) + put "/api/orders/#{@order.number}", params: order_params + expect(response).to have_http_status(:ok) + end + + def create_line_item(variant, quantity = 1) + expect { + post "/api/orders/#{@order.number}/line_items", + params: { line_item: { variant_id: variant.id, quantity: quantity } } + }.to change { @order.line_items.count }.by 1 + expect(response).to have_http_status(:created) + end + + def add_promotion(_promotion) + expect { + post "/api/orders/#{@order.number}/coupon_codes", + params: { coupon_code: promotion_code.value } + }.to change { @order.promotions.count }.by 1 + expect(response).to have_http_status(:ok) + end + + def add_address(address, billing: true) + address_type = billing ? :bill_address : :ship_address + # It seems we are missing an order-scoped address api endpoint since we need + # to use update here. + expect { + update_order(order_params: { order: { address_type => address.as_json.except('id') } }) + }.to change { @order.reload.public_send(address_type) }.to address + end + + def add_payment + expect { + post "/api/orders/#{@order.number}/payments", + params: { payment: { payment_method_id: payment_method.id } } + }.to change { @order.reload.payments.count }.by 1 + expect(response).to have_http_status(:created) + expect(@order.payments.last.payment_method).to eq payment_method + end + + def advance + put "/api/checkouts/#{@order.number}/advance" + expect(response).to have_http_status(:ok) + end + + def complete + put "/api/checkouts/#{@order.number}/complete" + expect(response).to have_http_status(:ok) + end + + def assert_order_expectations + @order.reload + expect(@order.state).to eq 'complete' + expect(@order.completed_at).to be_a ActiveSupport::TimeWithZone + expect(@order.item_total).to eq 600.00 + expect(@order.total).to eq 600.00 + expect(@order.adjustment_total).to eq(-10.00) + expect(@order.shipment_total).to eq 10.00 + expect(@order.user).to eq @user + expect(@order.bill_address).to eq bill_address + expect(@order.ship_address).to eq ship_address + expect(@order.payments.length).to eq 1 + expect(@order.line_items.any? { |li| li.variant == variant_1 && li.quantity == 2 }).to eq true + expect(@order.line_items.any? { |li| li.variant == variant_2 && li.quantity == 2 }).to eq true + expect(@order.promotions).to eq [promotion] + end + + it "is able to checkout with individualized requests" do + login + create_order + + create_line_item(variant_1, 2) + add_promotion(promotion) + create_line_item(variant_2, 2) + + add_address(bill_address) + add_address(ship_address, billing: false) + + add_payment + + advance + complete + + assert_order_expectations + end + + it "is able to checkout with the create request" do + login + + create_order(order_params: { + order: { + bill_address: bill_address.as_json.except('id'), + ship_address: ship_address.as_json.except('id'), + line_items: { + 0 => { variant_id: variant_1.id, quantity: 2 }, + 1 => { variant_id: variant_2.id, quantity: 2 } + }, + # Would like to do this, but it puts the payment in a complete state, + # which the order does not like when transitioning from confirm to complete + # since it looks to process pending payments. + # payments: [ { payment_method: payment_method.name, state: "pending" } ], + } + }) + + add_promotion(promotion) + add_payment + + advance + complete + + assert_order_expectations + end + + it "is able to checkout with the update request" do + login + + create_order + update_order(order_params: { + order: { + bill_address: bill_address.as_json.except('id'), + ship_address: ship_address.as_json.except('id'), + line_items: { + 0 => { variant_id: variant_1.id, quantity: 2 }, + 1 => { variant_id: variant_2.id, quantity: 2 } + }, + # Would like to do this, but it puts the payment in a complete state, + # which the order does not like when transitioning from confirm to complete + # since it looks to process pending payments. + # payments: [ { payment_method: payment_method.name, state: "pending" } ], + } + }) + + add_promotion(promotion) + add_payment + + advance + complete + + assert_order_expectations + end + end +end diff --git a/legacy_promotions/spec/rails_helper.rb b/legacy_promotions/spec/rails_helper.rb index c86a7eba5e9..f8a29a778bb 100644 --- a/legacy_promotions/spec/rails_helper.rb +++ b/legacy_promotions/spec/rails_helper.rb @@ -20,6 +20,7 @@ require 'spree/testing_support/preferences' require 'spree/testing_support/rake' require 'spree/testing_support/job_helpers' +require 'spree/api/testing_support/helpers' require 'cancan/matchers' ActiveJob::Base.queue_adapter = :test @@ -48,4 +49,5 @@ config.include Spree::TestingSupport::JobHelpers config.include FactoryBot::Syntax::Methods + config.include Spree::Api::TestingSupport::Helpers, type: :request end diff --git a/legacy_promotions/spec/requests/spree/api/promotion_application_spec.rb b/legacy_promotions/spec/requests/spree/api/promotion_application_spec.rb new file mode 100644 index 00000000000..eeb618d13ce --- /dev/null +++ b/legacy_promotions/spec/requests/spree/api/promotion_application_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Promotion application', type: :request do + before do + stub_authentication! + end + + context "with an available promotion" do + let!(:order) { create(:order_with_line_items, line_items_count: 1) } + let!(:promotion) do + promotion = create(:promotion, name: "10% off", code: "10off") + calculator = Spree::Calculator::FlatPercentItemTotal.create(preferred_flat_percent: "10") + action = Spree::Promotion::Actions::CreateItemAdjustments.create(calculator: calculator) + promotion.actions << action + promotion + end + + it "can apply a coupon code to the order" do + expect(order.total).to eq(110.00) + post spree.api_order_coupon_codes_path(order), params: { coupon_code: "10off", order_token: order.guest_token } + expect(response.status).to eq(200) + expect(order.reload.total).to eq(109.00) + expect(json_response["success"]).to eq("The coupon code was successfully applied to your order.") + expect(json_response["error"]).to be_blank + expect(json_response["successful"]).to be true + expect(json_response["status_code"]).to eq("coupon_code_applied") + end + + context "with an expired promotion" do + before do + promotion.starts_at = 2.weeks.ago + promotion.expires_at = 1.week.ago + promotion.save + end + + it "fails to apply" do + post spree.api_order_coupon_codes_path(order), params: { coupon_code: "10off", order_token: order.guest_token } + expect(response.status).to eq(422) + expect(json_response["success"]).to be_blank + expect(json_response["error"]).to eq("The coupon code is expired") + expect(json_response["successful"]).to be false + expect(json_response["status_code"]).to eq("coupon_code_expired") + end + end + end +end