solidus_paypal_commerce_platform 0.5.0 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +21 -9
  3. data/.github/stale.yml +1 -17
  4. data/.gitignore +1 -0
  5. data/.rspec +0 -1
  6. data/.rubocop.yml +3 -2
  7. data/CHANGELOG.md +42 -9
  8. data/Gemfile +0 -41
  9. data/README.md +9 -12
  10. data/Rakefile +6 -1
  11. data/app/models/solidus_paypal_commerce_platform/payment_method.rb +6 -5
  12. data/app/models/solidus_paypal_commerce_platform/paypal_address.rb +6 -2
  13. data/app/models/solidus_paypal_commerce_platform/paypal_order.rb +22 -15
  14. data/bin/dummy-app +37 -0
  15. data/bin/rails-dummy-app +17 -0
  16. data/bin/rspec +11 -0
  17. data/bin/sandbox +3 -29
  18. data/lib/generators/solidus_paypal_commerce_platform/install/install_generator.rb +62 -23
  19. data/lib/generators/solidus_paypal_commerce_platform/install/templates/app/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform/button_actions.js +272 -0
  20. data/{app → lib/generators/solidus_paypal_commerce_platform/install/templates/app}/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform/buttons.js +0 -0
  21. data/{app → lib/generators/solidus_paypal_commerce_platform/install/templates/app}/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform/namespace.js +0 -0
  22. data/{app → lib/generators/solidus_paypal_commerce_platform/install/templates/app}/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform.js +7 -0
  23. data/{app → lib/generators/solidus_paypal_commerce_platform/install/templates/app}/assets/stylesheets/spree/frontend/solidus_paypal_commerce_platform.css +0 -0
  24. data/{app → lib/generators/solidus_paypal_commerce_platform/install/templates/app}/controllers/solidus_paypal_commerce_platform/orders_controller.rb +2 -1
  25. data/{app → lib/generators/solidus_paypal_commerce_platform/install/templates/app}/controllers/solidus_paypal_commerce_platform/payments_controller.rb +0 -0
  26. data/{app → lib/generators/solidus_paypal_commerce_platform/install/templates/app}/controllers/solidus_paypal_commerce_platform/paypal_orders_controller.rb +1 -1
  27. data/{app → lib/generators/solidus_paypal_commerce_platform/install/templates/app}/controllers/solidus_paypal_commerce_platform/shipping_rates_controller.rb +0 -0
  28. data/{app → lib/generators/solidus_paypal_commerce_platform/install/templates/app}/controllers/solidus_paypal_commerce_platform/wizard_controller.rb +0 -0
  29. data/lib/{views/frontend/spree/checkout → generators/solidus_paypal_commerce_platform/install/templates/app/views/checkouts}/payment/_paypal_commerce_platform.html.erb +5 -4
  30. data/lib/{views/frontend/spree → generators/solidus_paypal_commerce_platform/install/templates/app/views}/orders/payment/_paypal_commerce_platform.html.erb +4 -3
  31. data/lib/{views/frontend/spree → generators/solidus_paypal_commerce_platform/install/templates/app/views}/products/payment/_paypal_commerce_platform.html.erb +1 -1
  32. data/lib/{views/frontend → generators/solidus_paypal_commerce_platform/install/templates/app/views}/solidus_paypal_commerce_platform/cart/_cart_buttons.html.erb +0 -0
  33. data/lib/{views/frontend → generators/solidus_paypal_commerce_platform/install/templates/app/views}/solidus_paypal_commerce_platform/payments/_payment.html.erb +0 -0
  34. data/lib/{views/frontend → generators/solidus_paypal_commerce_platform/install/templates/app/views}/solidus_paypal_commerce_platform/product/_product_buttons.html.erb +0 -0
  35. data/lib/{views/frontend → generators/solidus_paypal_commerce_platform/install/templates/app/views}/solidus_paypal_commerce_platform/shared/_javascript_sdk_tag.html.erb +4 -2
  36. data/lib/generators/solidus_paypal_commerce_platform/install/templates/{initializer.rb → config/initializers/solidus_paypal_commerce_platform.rb} +0 -0
  37. data/lib/paypal/paypal_checkout_sdk/orders/orders_authorize_request.rb +0 -2
  38. data/lib/paypal/paypal_checkout_sdk/orders/orders_capture_request.rb +0 -2
  39. data/lib/paypal/paypal_checkout_sdk/orders/orders_create_request.rb +0 -2
  40. data/lib/paypal/paypal_checkout_sdk/orders/orders_get_request.rb +0 -2
  41. data/lib/paypal/paypal_checkout_sdk/orders/orders_patch_request.rb +0 -52
  42. data/lib/paypal/paypal_checkout_sdk/orders/orders_validate_request.rb +0 -2
  43. data/lib/paypal/paypal_checkout_sdk/payments/authorizations_capture_request.rb +0 -2
  44. data/lib/paypal/paypal_checkout_sdk/payments/authorizations_get_request.rb +0 -2
  45. data/lib/paypal/paypal_checkout_sdk/payments/authorizations_reauthorize_request.rb +0 -2
  46. data/lib/paypal/paypal_checkout_sdk/payments/authorizations_void_request.rb +0 -2
  47. data/lib/paypal/paypal_checkout_sdk/payments/captures_get_request.rb +0 -2
  48. data/lib/paypal/paypal_checkout_sdk/payments/captures_refund_request.rb +0 -2
  49. data/lib/paypal/paypal_checkout_sdk/payments/refunds_get_request.rb +0 -2
  50. data/lib/paypal/paypal_http_client.rb +4 -4
  51. data/lib/solidus_paypal_commerce_platform/client.rb +6 -3
  52. data/lib/solidus_paypal_commerce_platform/paypal_checkout_sdk/orders/orders_patch_request.rb +1 -54
  53. data/lib/solidus_paypal_commerce_platform/version.rb +1 -1
  54. data/solidus_paypal_commerce_platform.gemspec +1 -2
  55. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/CHECKOUT.ORDER.COMPLETED.v2.json +121 -0
  56. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/CHECKOUT.ORDER.PROCESSED.v2.json +121 -0
  57. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.COMPLETED.v1.json +50 -0
  58. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.COMPLETED.v2.json +72 -0
  59. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.DENIED.v1.json +50 -0
  60. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.DENIED.v2.json +68 -0
  61. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.REFUNDED.v1.json +51 -0
  62. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.REFUNDED.v2.json +63 -0
  63. data/spec/jobs/solidus_paypal_commerce_platform/webhook_job_spec.rb +44 -0
  64. data/spec/lib/solidus_paypal_commerce_platform/client_spec.rb +21 -0
  65. data/spec/lib/solidus_paypal_commerce_platform/configuration_spec.rb +91 -0
  66. data/spec/models/solidus_paypal_commerce_platform/payment_method_spec.rb +200 -0
  67. data/spec/models/solidus_paypal_commerce_platform/payment_source_spec.rb +119 -0
  68. data/spec/models/solidus_paypal_commerce_platform/paypal_address_spec.rb +67 -0
  69. data/spec/models/solidus_paypal_commerce_platform/paypal_order_spec.rb +80 -0
  70. data/spec/models/solidus_paypal_commerce_platform/state_guesser_spec.rb +38 -0
  71. data/spec/models/solidus_paypal_commerce_platform/wizard_spec.rb +9 -0
  72. data/spec/requests/solidus_paypal_commerce_platform/orders_controller_spec.rb +36 -0
  73. data/spec/requests/solidus_paypal_commerce_platform/shipping_rates_controller_spec.rb +44 -0
  74. data/spec/requests/solidus_paypal_commerce_platform/wizard_controller_spec.rb +59 -0
  75. data/spec/solidus_paypal_commerce_platform_spec_helper.rb +5 -0
  76. data/spec/support/solidus_paypal_commerce_platform/factories.rb +5 -0
  77. data/spec/support/solidus_paypal_commerce_platform/paypal_sdk_script_tag_helper.rb +13 -0
  78. data/spec/system/backend/new_payment_method_spec.rb +40 -0
  79. data/spec/system/frontend/cart_spec.rb +53 -0
  80. data/spec/system/frontend/checkout_spec.rb +104 -0
  81. data/spec/system/frontend/product_spec.rb +98 -0
  82. metadata +53 -37
  83. data/app/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform/button_actions.js +0 -203
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'solidus_paypal_commerce_platform_spec_helper'
4
+
5
+ RSpec.describe SolidusPaypalCommercePlatform::PaypalOrder, type: :model do
6
+ describe '#to_json' do
7
+ subject(:to_json) { described_class.new(order).to_json('intent') }
8
+
9
+ let(:order) { create(:order_ready_to_complete, ship_address: ship_address, bill_address: bill_address) }
10
+ let(:ship_address) { create_address('John', 'Von Doe') }
11
+ let(:bill_address) { create_address('Johnny', 'Vonny Doey') }
12
+
13
+ it { expect { to_json }.not_to raise_error }
14
+
15
+ it 'represents amounts as strings with double decimals' do
16
+ purchase_unit = to_json.dig(:purchase_units, 0)
17
+ expect(purchase_unit.dig(:amount, :breakdown)).to eq(
18
+ item_total: { currency_code: "USD", value: "10.00" },
19
+ shipping: { currency_code: "USD", value: "100.00" },
20
+ tax_total: { currency_code: "USD", value: "0.00" },
21
+ discount: { currency_code: "USD", value: "0.00" }
22
+ )
23
+ expect(purchase_unit.dig(:items, 0, :unit_amount)).to eq(currency_code: "USD", value: "10.00")
24
+ end
25
+
26
+ it 'maps the bill and ship address names correctly' do
27
+ expect(to_json).to match hash_including(
28
+ purchase_units: array_including(
29
+ hash_including(shipping: hash_including(name: { full_name: 'John Von Doe' }))
30
+ ),
31
+ payer: hash_including(name: { given_name: 'Johnny', surname: 'Vonny Doey' })
32
+ )
33
+ end
34
+
35
+ context 'when the item name is greater than 127 characters' do
36
+ let(:variant) { create(:variant, product: create(:product, name: 'a' * 128)) }
37
+ let(:order) do
38
+ create(:order_ready_to_complete, line_items_attributes: [{ variant: variant, quantity: 1, price: 10 }])
39
+ end
40
+
41
+ it 'returns the truncated name' do
42
+ expect(to_json).to match hash_including(
43
+ purchase_units: array_including(
44
+ hash_including(
45
+ items: array_including(hash_including(name: "#{'a' * 124}..."))
46
+ )
47
+ )
48
+ )
49
+ end
50
+ end
51
+
52
+ context 'when checkout_steps does not include "delivery"' do
53
+ let(:old_checkout_flow) { Spree::Order.checkout_flow }
54
+
55
+ before do
56
+ old_checkout_flow
57
+
58
+ Spree::Order.class_eval do
59
+ remove_checkout_step :delivery
60
+ end
61
+ end
62
+
63
+ after do
64
+ Spree::Order.checkout_flow(&old_checkout_flow)
65
+ end
66
+
67
+ it 'disable shipping requirements' do
68
+ expect(to_json).to match hash_including(
69
+ application_context: hash_including(shipping_preference: 'NO_SHIPPING')
70
+ )
71
+ end
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def create_address(firstname, lastname)
78
+ create(:address, name: "#{firstname} #{lastname}")
79
+ end
80
+ end
@@ -0,0 +1,38 @@
1
+ require 'solidus_paypal_commerce_platform_spec_helper'
2
+
3
+ RSpec.describe SolidusPaypalCommercePlatform::StateGuesser, type: :model do
4
+ let(:country) { create(:country, iso: "IT") }
5
+ let!(:state) { create(:state, country: country, name: "Abruzzo") }
6
+
7
+ describe "#guess" do
8
+ context "with a guessable state error" do
9
+ it "correctly guesses the state" do
10
+ expect(
11
+ described_class.new("Pescara", country).guess
12
+ ).to eq state
13
+ end
14
+
15
+ it "guesses the state using an abbreviation" do
16
+ expect(
17
+ described_class.new("PE", country).guess
18
+ ).to eq state
19
+ end
20
+ end
21
+
22
+ context "with an unsolvable state error" do
23
+ it "returns nil" do
24
+ expect(
25
+ described_class.new("Gondor", country).guess
26
+ ).to be_nil
27
+ end
28
+ end
29
+
30
+ context "with an already correct state" do
31
+ it "returns the correct state" do
32
+ expect(
33
+ described_class.new("Abruzzo", country).guess
34
+ ).to eq state
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,9 @@
1
+ require 'solidus_paypal_commerce_platform_spec_helper'
2
+
3
+ RSpec.describe SolidusPaypalCommercePlatform::Wizard do
4
+ describe "#nonce" do
5
+ it 'is between 45 and 128 chars long' do
6
+ expect(subject.nonce.size).to be_between(45, 128)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,36 @@
1
+ require 'solidus_paypal_commerce_platform_spec_helper'
2
+
3
+ RSpec.describe SolidusPaypalCommercePlatform::OrdersController, type: :request do
4
+ stub_authorization!
5
+ let(:order) { create(:order_with_line_items) }
6
+
7
+ describe "GET /solidus_paypal_commerce_platform/verify_total" do
8
+ context "when the amount is correct" do
9
+ it "passes" do
10
+ params = {
11
+ order_id: order.number,
12
+ paypal_total: order.total,
13
+ format: :json
14
+ }
15
+
16
+ get solidus_paypal_commerce_platform.verify_total_path, params: params
17
+
18
+ expect(response).to have_http_status(:ok)
19
+ end
20
+ end
21
+
22
+ context "when the amount is incorrect" do
23
+ it "fails" do
24
+ params = {
25
+ order_id: order.number,
26
+ paypal_total: order.total - 1,
27
+ format: :json
28
+ }
29
+
30
+ get solidus_paypal_commerce_platform.verify_total_path, params: params
31
+
32
+ expect(response).to have_http_status(:bad_request)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,44 @@
1
+ require 'solidus_paypal_commerce_platform_spec_helper'
2
+
3
+ RSpec.describe SolidusPaypalCommercePlatform::ShippingRatesController, type: :request do
4
+ stub_authorization!
5
+ let(:new_country) { create(:country, iso: "IT", states_required: true) }
6
+ let(:new_state) { create(:state, country: new_country) }
7
+ let(:new_address) { build(:address, country: new_country, state: new_state) }
8
+ let(:order) { Spree::TestingSupport::OrderWalkthrough.up_to(:payment) }
9
+ let(:paypal_address) {
10
+ {
11
+ country_code: new_country.iso,
12
+ city: new_address.city,
13
+ state: new_state&.abbr,
14
+ postal_code: new_address.zipcode
15
+ }
16
+ }
17
+
18
+ describe "GET /simulate_shipping_rates" do
19
+ before do
20
+ get solidus_paypal_commerce_platform.shipping_rates_path, params: {
21
+ order_id: order.number,
22
+ address: paypal_address
23
+ }
24
+ end
25
+
26
+ it "returns a paypal_order without the simulated address" do
27
+ expect(response.body).not_to include "admin_area_1\":\"#{new_address.state.abbr}\""
28
+ expect(response.body).not_to include "admin_area_1\":\"#{order.ship_address.state.abbr}\""
29
+ end
30
+
31
+ it "does not modify original address" do
32
+ expect(order.ship_address).not_to eq new_address
33
+ end
34
+
35
+ context "with an invalid address" do
36
+ let(:new_state) { nil }
37
+
38
+ it "returns a list of errors" do
39
+ expect(response).to have_http_status(:unprocessable_entity) # unprocessable_entity
40
+ expect(response.body).to include "State can't be blank"
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,59 @@
1
+ require 'solidus_paypal_commerce_platform_spec_helper'
2
+
3
+ RSpec.describe SolidusPaypalCommercePlatform::WizardController, type: :request do
4
+ stub_authorization!
5
+
6
+ let(:wizard) { SolidusPaypalCommercePlatform::Wizard.new }
7
+
8
+ describe "POST /solidus_paypal_commerce_platform/wizard" do
9
+ let(:params) {
10
+ {
11
+ authCode: "PFc4d2vp4DVfHqcnEHbGAA12C_H29U39NM_vmQrZBPzdLcxA12Br-GzjbliqXGu3AG6Gfwo5G9GTal6REkcKGMREc9fPsR_wv",
12
+ sharedId: "awj45zMAy1XonxWfgIhjjGHZGAPStkZFzXp4bfe1QmNWA-9DL6HkpklD0skHig4vVF7zVZD8Uwy5Qop4",
13
+ nonce: wizard.nonce,
14
+ }
15
+ }
16
+
17
+ it "creates a new payment method from data received from PayPal" do
18
+ expect_any_instance_of(SolidusPaypalCommercePlatform::Client).to receive(:execute) do |_client, request|
19
+ case request
20
+ when SolidusPaypalCommercePlatform::AccessTokenAuthorizationRequest
21
+ # rubocop:disable RSpec/VerifiedDoubles
22
+ double(
23
+ 'response',
24
+ result: double(
25
+ 'result',
26
+ access_token: "ACCESS-TOKEN"
27
+ )
28
+ )
29
+ # rubocop:enable RSpec/VerifiedDoubles
30
+ when SolidusPaypalCommercePlatform::FetchMerchantCredentialsRequest
31
+ expect(request.headers.fetch("Authorization")).to eq("Bearer ACCESS-TOKEN")
32
+
33
+ # rubocop:disable RSpec/VerifiedDoubles
34
+ double(
35
+ 'response',
36
+ result: double(
37
+ 'result',
38
+ client_id: "CLIENT-ID",
39
+ client_secret: "CLIENT-SECRET",
40
+ )
41
+ )
42
+ # rubocop:enable RSpec/VerifiedDoubles
43
+ else
44
+ raise "unexpected request: #{request}"
45
+ end
46
+ end.twice
47
+
48
+ expect {
49
+ post solidus_paypal_commerce_platform.wizard_index_path, params: params
50
+ }.to change(SolidusPaypalCommercePlatform::PaymentMethod, :count).from(0).to(1)
51
+
52
+ payment_method = SolidusPaypalCommercePlatform::PaymentMethod.last
53
+
54
+ expect(payment_method.preferred_client_id).to eq("CLIENT-ID")
55
+ expect(payment_method.preferred_client_secret).to eq("CLIENT-SECRET")
56
+ expect(response).to have_http_status(:created)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'solidus_starter_frontend_helper'
4
+
5
+ Dir["#{__dir__}/support/solidus_paypal_commerce_platform/**/*.rb"].sort.each { |f| require f }
@@ -0,0 +1,5 @@
1
+ FactoryBot.definition_file_paths << SolidusPaypalCommercePlatform::Engine.root.join(
2
+ 'lib/solidus_paypal_commerce_platform/testing_support/factories'
3
+ ).to_s
4
+
5
+ FactoryBot.reload
@@ -0,0 +1,13 @@
1
+ module PaypalSdkScriptTagHelper
2
+ def js_sdk_script_query
3
+ URI(page.find('script[src*="sdk/js?"]', visible: false)[:src]).query.split('&')
4
+ end
5
+
6
+ def js_sdk_script_partner_id
7
+ page.find('script[src*="sdk/js?"]', visible: false)['data-partner-attribution-id']
8
+ end
9
+ end
10
+
11
+ RSpec.configure do |config|
12
+ config.include PaypalSdkScriptTagHelper, type: :system
13
+ end
@@ -0,0 +1,40 @@
1
+ require 'solidus_paypal_commerce_platform_spec_helper'
2
+
3
+ RSpec.describe "creating a new payment" do
4
+ stub_authorization!
5
+
6
+ it "displays PayPal Commerce Platform as an option" do
7
+ visit "/admin/payment_methods/new"
8
+ expect(page).to have_select('payment_method_type', options: [
9
+ "PayPal Commerce Platform",
10
+ "Bogus Credit Card Payments",
11
+ "Check Payments",
12
+ "Simple Bogus Credit Card Payments",
13
+ "Store Credit Payments",
14
+ ])
15
+ select "PayPal Commerce Platform", from: 'payment_method_type'
16
+ fill_in "Name", with: "PayPal!"
17
+ click_on "Create"
18
+ expect(page).to have_text("Payment Method has been successfully created!")
19
+
20
+ fill_in "Client", with: "cli-123"
21
+ fill_in "Client secret", with: "cli-sec-123"
22
+ click_on "Update"
23
+ expect(page).to have_text("Payment Method has been successfully updated!")
24
+ end
25
+
26
+ it "displays the onboarding button", :js do
27
+ visit "/admin/payment_methods"
28
+
29
+ # main_window = current_window
30
+
31
+ within ".setup-wizard" do
32
+ paypal_button = page.find("button")
33
+ expect(paypal_button.text).to eq("Setup PayPal Commerce Platform")
34
+ # TODO: make this more complete
35
+ # paypal_window = window_opened_by do
36
+ # paypal_button.click
37
+ # end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,53 @@
1
+ require 'solidus_paypal_commerce_platform_spec_helper'
2
+
3
+ RSpec.describe "Cart page" do
4
+ describe "paypal payment method", :skip do
5
+ let(:order) { Spree::TestingSupport::OrderWalkthrough.up_to(:address) }
6
+ let(:paypal_payment_method) { create(:paypal_payment_method) }
7
+
8
+ before do
9
+ user = create(:user)
10
+ order.user = user
11
+ visit '/'
12
+ click_link 'Login'
13
+
14
+ fill_in 'spree_user[email]', with: user.email
15
+ fill_in 'spree_user[password]', with: 'secret'
16
+ click_button 'Login'
17
+
18
+ paypal_payment_method
19
+ allow_any_instance_of(OrdersController).to receive_messages(
20
+ current_order: order,
21
+ try_spree_current_user: user
22
+ )
23
+ end
24
+
25
+ context "when generating a script tag" do
26
+ it "generates a url with the correct credentials attached" do
27
+ visit '/cart/edit'
28
+ expect(js_sdk_script_query).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
29
+ end
30
+
31
+ it "generates a partner_id attribute with the correct partner code attached" do
32
+ visit '/cart/edit'
33
+ expect(js_sdk_script_partner_id).to eq("Solidus_PCP_SP")
34
+ end
35
+
36
+ it "generates a URL with the correct currency" do
37
+ order.update currency: "EUR"
38
+ visit '/cart/edit'
39
+ expect(js_sdk_script_query).to include("currency=EUR")
40
+ end
41
+
42
+ context "when auto-capture is set to true" do
43
+ it "generates a url with intent capture" do
44
+ paypal_payment_method.update(auto_capture: true)
45
+ visit '/cart/edit'
46
+
47
+ expect(js_sdk_script_query).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
48
+ expect(js_sdk_script_query).to include("intent=capture")
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,104 @@
1
+ require 'solidus_paypal_commerce_platform_spec_helper'
2
+
3
+ RSpec.describe "Checkout" do
4
+ describe "paypal payment method" do
5
+ let(:order) { Spree::TestingSupport::OrderWalkthrough.up_to(:payment) }
6
+ let(:paypal_payment_method) { create(:paypal_payment_method) }
7
+ let(:failed_response) { double('response', status_code: 500) } # rubocop:disable RSpec/VerifiedDoubles
8
+
9
+ before do
10
+ user = create(:user)
11
+ visit '/'
12
+ click_link 'Login'
13
+ fill_in 'spree_user[email]', with: user.email
14
+ fill_in 'spree_user[password]', with: 'secret'
15
+ click_button 'Login'
16
+ order.user = user
17
+ order.recalculate
18
+
19
+ paypal_payment_method
20
+ allow_any_instance_of(CheckoutsController).to receive_messages(
21
+ current_order: order, try_spree_current_user: user
22
+ )
23
+ end
24
+
25
+ context "when generating a script tag" do
26
+ it "generates a url with the correct credentials attached" do
27
+ visit '/checkout/payment'
28
+ expect(js_sdk_script_query).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
29
+ end
30
+
31
+ it "generates a partner_id attribute with the correct partner code attached" do
32
+ visit '/checkout/payment'
33
+ expect(js_sdk_script_partner_id).to eq("Solidus_PCP_SP")
34
+ end
35
+
36
+ it "generates a URL with the correct currency" do
37
+ allow(order).to receive(:currency).and_return "EUR"
38
+ visit '/checkout/payment'
39
+ expect(js_sdk_script_query).to include("currency=EUR")
40
+ end
41
+
42
+ context "when auto-capture is set to true" do
43
+ it "generates a url with intent capture" do
44
+ paypal_payment_method.update(auto_capture: true)
45
+ visit '/checkout/payment'
46
+ expect(js_sdk_script_query).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
47
+ expect(js_sdk_script_query).to include("intent=capture")
48
+ end
49
+ end
50
+ end
51
+
52
+ context "when no payment has been made" do
53
+ it "fails to process" do
54
+ visit '/checkout/payment'
55
+ choose(option: paypal_payment_method.id)
56
+ click_button("Save and Continue")
57
+ expect(page).to have_content("Payments source PayPal order can't be blank")
58
+ end
59
+ end
60
+
61
+ context "when a payment has been made" do
62
+ it "proceeds to the next step" do
63
+ visit '/checkout/payment'
64
+ choose(option: paypal_payment_method.id)
65
+ find(:xpath, "//input[@id='payments_source_paypal_order_id']", visible: false).set SecureRandom.hex(8)
66
+ click_button("Save and Continue")
67
+ expect(page).to have_css(".current", text: "Confirm")
68
+ end
69
+
70
+ it "records the paypal email address" do
71
+ visit '/checkout/payment'
72
+ choose(option: paypal_payment_method.id)
73
+ find(:xpath, "//input[@id='payments_source_paypal_order_id']", visible: false).set SecureRandom.hex(8)
74
+ find(:xpath, "//input[@id='payments_source_paypal_email']", visible: false).set "fake@email.com"
75
+ click_button("Save and Continue")
76
+ expect(Spree::Payment.last.source.paypal_email).to eq "fake@email.com"
77
+ end
78
+
79
+ it "records the paypal funding source" do
80
+ visit '/checkout/payment'
81
+ choose(option: paypal_payment_method.id)
82
+ find(:xpath, "//input[@id='payments_source_paypal_order_id']", visible: false).set SecureRandom.hex(8)
83
+ find(:xpath, "//input[@id='payments_source_paypal_email']", visible: false).set "fake@email.com"
84
+ find(:xpath, "//input[@id='payments_source_paypal_funding_source']", visible: false).set "venmo"
85
+ click_button("Save and Continue")
86
+ expect(Spree::Payment.last.source.paypal_funding_source).to eq "venmo"
87
+ end
88
+ end
89
+
90
+ context "when a payment fails" do
91
+ before { allow_any_instance_of(PayPal::PayPalHttpClient).to receive(:execute) { failed_response } }
92
+
93
+ it "redirects the user back to the payments page" do
94
+ visit '/checkout/payment'
95
+ choose(option: paypal_payment_method.id)
96
+ find(:xpath, "//input[@id='payments_source_paypal_order_id']", visible: false).set SecureRandom.hex(8)
97
+ click_button("Save and Continue")
98
+ click_button("Place Order")
99
+ expect(page).to have_current_path("/checkout/payment")
100
+ expect(page).to have_content("Your payment was declined")
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,98 @@
1
+ require 'solidus_paypal_commerce_platform_spec_helper'
2
+
3
+ RSpec.describe "Product page", js: true do
4
+ describe "paypal button", :skip do
5
+ before { create(:store, default: true) }
6
+
7
+ let!(:paypal_payment_method) { create(:paypal_payment_method) }
8
+ let!(:variants) {
9
+ option_type = create(:option_type)
10
+ product = create(:product, option_types: [option_type], slug: 'foo-bar')
11
+ option_s = create(:option_value, option_type: option_type, presentation: 'S')
12
+ option_xs = create(:option_value, option_type: option_type, presentation: 'XS')
13
+
14
+ [
15
+ create(:variant, product: product, option_values: [option_s]),
16
+ create(:variant, product: product, option_values: [option_xs]),
17
+ ]
18
+ }
19
+
20
+ context "when generating a script tag" do
21
+ it "generates a url with the correct credentials attached" do
22
+ visit "/products/foo-bar"
23
+
24
+ expect(js_sdk_script_query).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
25
+ end
26
+
27
+ it "generates a partner_id attribute with the correct partner code attached" do
28
+ visit "/products/foo-bar"
29
+
30
+ expect(js_sdk_script_partner_id).to eq("Solidus_PCP_SP")
31
+ end
32
+
33
+ it "generates a URL with the correct currency" do
34
+ allow_any_instance_of(SolidusPaypalCommercePlatform::PricingOptions).to receive(:currency).and_return "EUR"
35
+
36
+ visit "/products/foo-bar"
37
+
38
+ expect(js_sdk_script_query).to include("currency=EUR")
39
+ end
40
+
41
+ context "when auto-capture is set to true" do
42
+ it "generates a url with intent capture" do
43
+ paypal_payment_method.update(auto_capture: true)
44
+
45
+ visit "/products/foo-bar"
46
+
47
+ expect(js_sdk_script_query).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
48
+ expect(js_sdk_script_query).to include("intent=capture")
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "order creation" do
54
+ it "creates an order successfully" do
55
+ visit "/products/foo-bar"
56
+ page.evaluate_script("SolidusPaypalCommercePlatform.createOrder()")
57
+
58
+ expect(Spree::Order.last).to be_an_instance_of(Spree::Order)
59
+ end
60
+
61
+ it "sets the Spree number and token variables" do
62
+ visit "/products/foo-bar"
63
+ page.evaluate_script("SolidusPaypalCommercePlatform.createOrder()")
64
+
65
+ order = Spree::Order.last
66
+ expect(page.evaluate_script("SolidusPaypalCommercePlatform.current_order_id")).to eq order.number
67
+ expect(page.evaluate_script("SolidusPaypalCommercePlatform.current_order_token")).to eq order.guest_token
68
+ end
69
+
70
+ it "uses the specified quantity" do
71
+ visit "/products/foo-bar"
72
+ fill_in('quantity', with: 12)
73
+ page.evaluate_script("SolidusPaypalCommercePlatform.createOrder()")
74
+
75
+ expect(Spree::Order.last.line_items.first.quantity).to eq(12)
76
+ end
77
+
78
+ it "uses the selected variant" do
79
+ visit "/products/foo-bar"
80
+ find('label', text: 'XS').click
81
+ page.evaluate_script("SolidusPaypalCommercePlatform.createOrder()")
82
+
83
+ expect(Spree::Order.last.line_items.first.variant).to eq(variants.last)
84
+ end
85
+
86
+ it "assigns the order to the api token holder" do
87
+ user = create(:user)
88
+ user.generate_spree_api_key!
89
+
90
+ visit "/products/foo-bar"
91
+ page.evaluate_script("SolidusPaypalCommercePlatform.api_key = #{user.spree_api_key.to_json}")
92
+ page.evaluate_script("SolidusPaypalCommercePlatform.createOrder()")
93
+
94
+ expect(Spree::Order.last.user).to eq(user)
95
+ end
96
+ end
97
+ end
98
+ end