solidus_paypal_commerce_platform 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +41 -0
  3. data/.gem_release.yml +5 -0
  4. data/.github/stale.yml +17 -0
  5. data/.gitignore +20 -0
  6. data/.rspec +2 -0
  7. data/.rubocop.yml +56 -0
  8. data/Gemfile +33 -0
  9. data/LICENSE +26 -0
  10. data/README.md +173 -0
  11. data/Rakefile +6 -0
  12. data/app/assets/javascripts/spree/backend/solidus_paypal_commerce_platform.js +2 -0
  13. data/app/assets/javascripts/spree/backend/solidus_paypal_commerce_platform/namespace.js +1 -0
  14. data/app/assets/javascripts/spree/backend/solidus_paypal_commerce_platform/wizard.js +28 -0
  15. data/app/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform.js +3 -0
  16. data/app/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform/button_actions.js +191 -0
  17. data/app/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform/buttons.js +26 -0
  18. data/app/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform/namespace.js +1 -0
  19. data/app/assets/stylesheets/spree/backend/solidus_paypal_commerce_platform.css +4 -0
  20. data/app/assets/stylesheets/spree/frontend/solidus_paypal_commerce_platform.css +17 -0
  21. data/app/controllers/solidus_paypal_commerce_platform/orders_controller.rb +83 -0
  22. data/app/controllers/solidus_paypal_commerce_platform/payments_controller.rb +44 -0
  23. data/app/controllers/solidus_paypal_commerce_platform/paypal_orders_controller.rb +19 -0
  24. data/app/controllers/solidus_paypal_commerce_platform/shipping_rates_controller.rb +31 -0
  25. data/app/controllers/solidus_paypal_commerce_platform/wizard_controller.rb +47 -0
  26. data/app/decorators/solidus_paypal_commerce_platform/remove_required_phone_from_address.rb +13 -0
  27. data/app/helpers/solidus_paypal_commerce_platform/button_options_helper.rb +21 -0
  28. data/app/jobs/solidus_paypal_commerce_platform/application_job.rb +6 -0
  29. data/app/jobs/solidus_paypal_commerce_platform/webhook_job.rb +22 -0
  30. data/app/models/solidus_paypal_commerce_platform/gateway.rb +88 -0
  31. data/app/models/solidus_paypal_commerce_platform/payment_method.rb +75 -0
  32. data/app/models/solidus_paypal_commerce_platform/payment_source.rb +27 -0
  33. data/app/models/solidus_paypal_commerce_platform/paypal_address.rb +81 -0
  34. data/app/models/solidus_paypal_commerce_platform/paypal_order.rb +107 -0
  35. data/app/models/solidus_paypal_commerce_platform/pricing_options.rb +9 -0
  36. data/app/models/solidus_paypal_commerce_platform/wizard.rb +40 -0
  37. data/app/overrides/spree/admin/payment_methods/form/insert_email_verification_notification.rb +9 -0
  38. data/app/overrides/spree/admin/payment_methods/index/insert_setup_wizards.rb +17 -0
  39. data/app/overrides/spree/admin/payments/log_entries/add_paypal_debug_id.rb +9 -0
  40. data/app/overrides/spree/orders/edit/insert_cart_buttons.rb +9 -0
  41. data/app/overrides/spree/payments/payment/add_paypal_email_to_payment.rb +9 -0
  42. data/app/overrides/spree/products/cart_form/insert_product_buttons.rb +10 -0
  43. data/app/views/solidus_paypal_commerce_platform/admin/payment_methods/_available_to_users.html.erb +6 -0
  44. data/app/views/solidus_paypal_commerce_platform/admin/payment_methods/_paypal_wizard.html.erb +16 -0
  45. data/app/views/solidus_paypal_commerce_platform/admin/payment_methods/_setup_wizards.html.erb +16 -0
  46. data/app/views/solidus_paypal_commerce_platform/admin/payments/_log_entries.html.erb +32 -0
  47. data/bin/console +17 -0
  48. data/bin/rails +7 -0
  49. data/bin/rails-engine +13 -0
  50. data/bin/rails-sandbox +18 -0
  51. data/bin/rake +7 -0
  52. data/bin/sandbox +86 -0
  53. data/bin/setup +8 -0
  54. data/codecov.yml +14 -0
  55. data/config/locales/en.yml +37 -0
  56. data/config/routes.rb +12 -0
  57. data/db/migrate/20200521190038_add_paypal_commerce_platform_sources.rb +13 -0
  58. data/lib/generators/solidus_paypal_commerce_platform/install/install_generator.rb +38 -0
  59. data/lib/solidus_paypal_commerce_platform.rb +21 -0
  60. data/lib/solidus_paypal_commerce_platform/access_token_authorization_request.rb +21 -0
  61. data/lib/solidus_paypal_commerce_platform/client.rb +84 -0
  62. data/lib/solidus_paypal_commerce_platform/configuration.rb +64 -0
  63. data/lib/solidus_paypal_commerce_platform/engine.rb +45 -0
  64. data/lib/solidus_paypal_commerce_platform/factories.rb +14 -0
  65. data/lib/solidus_paypal_commerce_platform/fetch_merchant_credentials_request.rb +17 -0
  66. data/lib/solidus_paypal_commerce_platform/version.rb +5 -0
  67. data/lib/views/api/spree/api/payments/source_views/_paypal_commerce_platform.json.jbuilder +3 -0
  68. data/lib/views/backend/spree/admin/payments/source_forms/_paypal_commerce_platform.html.erb +1 -0
  69. data/lib/views/backend/spree/admin/payments/source_views/_paypal_commerce_platform.html.erb +18 -0
  70. data/lib/views/backend/spree/admin/shared/preference_fields/_paypal_select.html.erb +13 -0
  71. data/lib/views/frontend/solidus_paypal_commerce_platform/cart/_cart_buttons.html.erb +3 -0
  72. data/lib/views/frontend/solidus_paypal_commerce_platform/payments/_payment.html.erb +4 -0
  73. data/lib/views/frontend/solidus_paypal_commerce_platform/product/_product_buttons.html.erb +3 -0
  74. data/lib/views/frontend/spree/checkout/payment/_paypal_commerce_platform.html.erb +13 -0
  75. data/lib/views/frontend/spree/orders/payment/_paypal_commerce_platform.html.erb +17 -0
  76. data/lib/views/frontend/spree/products/payment/_paypal_commerce_platform.html.erb +15 -0
  77. data/solidus_paypal_commerce_platform.gemspec +39 -0
  78. data/spec/features/backend/new_payment_method_spec.rb +40 -0
  79. data/spec/features/frontend/cart_spec.rb +38 -0
  80. data/spec/features/frontend/checkout_spec.rb +81 -0
  81. data/spec/features/frontend/product_spec.rb +79 -0
  82. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/CHECKOUT.ORDER.COMPLETED.v2.json +121 -0
  83. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/CHECKOUT.ORDER.PROCESSED.v2.json +121 -0
  84. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.COMPLETED.v1.json +50 -0
  85. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.COMPLETED.v2.json +72 -0
  86. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.DENIED.v1.json +50 -0
  87. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.DENIED.v2.json +68 -0
  88. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.REFUNDED.v1.json +51 -0
  89. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.REFUNDED.v2.json +63 -0
  90. data/spec/jobs/solidus_paypal_commerce_platform/webhook_job_spec.rb +44 -0
  91. data/spec/lib/solidus_paypal_commerce_platform/client_spec.rb +21 -0
  92. data/spec/lib/solidus_paypal_commerce_platform/configuration_spec.rb +67 -0
  93. data/spec/models/solidus_paypal_commerce_platform/payment_method_spec.rb +102 -0
  94. data/spec/models/solidus_paypal_commerce_platform/payment_source_spec.rb +62 -0
  95. data/spec/models/solidus_paypal_commerce_platform/paypal_address_spec.rb +55 -0
  96. data/spec/models/solidus_paypal_commerce_platform/wizard_spec.rb +9 -0
  97. data/spec/requests/solidus_paypal_commerce_platform/orders_controller_spec.rb +36 -0
  98. data/spec/requests/solidus_paypal_commerce_platform/shipping_rates_controller_spec.rb +44 -0
  99. data/spec/requests/solidus_paypal_commerce_platform/wizard_controller_spec.rb +44 -0
  100. data/spec/spec_helper.rb +30 -0
  101. metadata +258 -0
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'deface'
4
+ require 'spree/core'
5
+ require 'solidus_paypal_commerce_platform'
6
+ require 'solidus_webhooks'
7
+
8
+ module SolidusPaypalCommercePlatform
9
+ class Engine < Rails::Engine
10
+ include SolidusSupport::EngineExtensions
11
+
12
+ isolate_namespace SolidusPaypalCommercePlatform
13
+
14
+ engine_name 'solidus_paypal_commerce_platform'
15
+
16
+ initializer "solidus_paypal_commerce_platform.add_payment_method", after: "spree.register.payment_methods" do |app|
17
+ app.config.spree.payment_methods << SolidusPaypalCommercePlatform::PaymentMethod
18
+ SolidusPaypalCommercePlatform::PaymentMethod.allowed_admin_form_preference_types << :paypal_select
19
+ Spree::PermittedAttributes.source_attributes.concat [:paypal_order_id, :authorization_id, :paypal_email]
20
+ end
21
+
22
+ initializer "solidus_paypal_commerce_platform.add_wizard", after: "spree.register.payment_methods" do |app|
23
+ # Adding the class set below - if this is ported to core, we can remove this line.
24
+ Spree::Core::Environment.add_class_set("payment_setup_wizards")
25
+ app.config.spree.payment_setup_wizards << "SolidusPaypalCommercePlatform::Wizard"
26
+ end
27
+
28
+ initializer "solidus_paypal_commerce_platform.set_pricing_options_class" do
29
+ def (Spree::Config).pricing_options_class
30
+ SolidusPaypalCommercePlatform::PricingOptions
31
+ end
32
+ end
33
+
34
+ initializer "solidus_paypal_commerce_platform.webhooks" do
35
+ SolidusWebhooks.config.register_webhook_handler :solidus_paypal_commerce_platform, ->(payload) {
36
+ SolidusPaypalCommercePlatform::WebhooksJob.perform_now(payload)
37
+ }
38
+ end
39
+
40
+ # use rspec for tests
41
+ config.generators do |g|
42
+ g.test_framework :rspec
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :paypal_payment_method, class: 'SolidusPaypalCommercePlatform::PaymentMethod' do
5
+ type { "SolidusPaypalCommercePlatform::PaymentMethod" }
6
+ name { "PayPal Payment Method" }
7
+ preferences {
8
+ {
9
+ client_id: SecureRandom.hex(8),
10
+ client_secret: SecureRandom.hex(10)
11
+ }
12
+ }
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusPaypalCommercePlatform
4
+ # https://developer.paypal.com/docs/api/partner-referrals/v1/#merchant-integration_credentials
5
+ class FetchMerchantCredentialsRequest
6
+ attr_accessor :verb, :path, :headers, :body
7
+
8
+ def initialize(partner_merchant_id:, access_token:)
9
+ @verb = "GET"
10
+ @path = "/v1/customer/partners/#{partner_merchant_id}/merchant-integrations/credentials"
11
+ @headers = {
12
+ "Content-Type" => "application/json",
13
+ "Authorization" => "Bearer #{access_token}"
14
+ }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusPaypalCommercePlatform
4
+ VERSION = '0.0.1'
5
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ json.call(payment_source, :id, :paypal_order_id, :created_at)
@@ -0,0 +1 @@
1
+ <%= t('virtual_terminal_notice_html') %>
@@ -0,0 +1,18 @@
1
+ <fieldset data-hook="credit_card">
2
+ <legend align="center"><%= SolidusPaypalCommercePlatform::PaymentMethod.model_name.human %></legend>
3
+
4
+ <div class="row">
5
+ <div class="alpha six columns">
6
+ <dl>
7
+ <dt><%= I18n.t("spree.identifier") %>:</dt>
8
+ <dd><%= payment.number %></dd>
9
+
10
+ <dt><%= I18n.t("paypal_capture_id") %>:</dt>
11
+ <dd><%= payment.source.capture_id %></dd>
12
+
13
+ <dt><%= I18n.t("paypal_email") %>:</dt>
14
+ <dd><%= payment.source.paypal_email %></dd>
15
+ </dl>
16
+ </div>
17
+ </div>
18
+ </fieldset>
@@ -0,0 +1,13 @@
1
+ <% label = local_assigns[:label].presence %>
2
+ <% html_options = {class: 'custom-select fullwidth'}.update(local_assigns[:html_options] || {}) %>
3
+ <% options = @object.send("#{attribute}_options") %>
4
+
5
+ <div class="field">
6
+ <% if local_assigns[:form] %>
7
+ <%= form.label attribute, label %>
8
+ <%= form.select attribute, options, {}, html_options %>
9
+ <% else %>
10
+ <%= label_tag name, label %>
11
+ <%= select_tag name, value, html_options %>
12
+ <% end %>
13
+ </div>
@@ -0,0 +1,3 @@
1
+ <% Spree::PaymentMethod.available_to_users.select{ |payment_method| payment_method.try(:display_on_cart) }.each do |payment_method| %>
2
+ <%= render partial: "spree/orders/payment/#{payment_method.cart_partial_name}", locals: {payment_method: payment_method} %>
3
+ <% end %>
@@ -0,0 +1,4 @@
1
+ <% if payment.source.respond_to?(:paypal_email) %>
2
+ <br />
3
+ <%= t('payment_email', email: payment.source.paypal_email) %>
4
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <% Spree::PaymentMethod.available_to_users.select{ |payment_method| payment_method.try(:display_on_product_page) }.each do |payment_method| %>
2
+ <%= render partial: "spree/products/payment/#{payment_method.product_page_partial_name}", locals: {payment_method: payment_method} %>
3
+ <% end %>
@@ -0,0 +1,13 @@
1
+ <script src="<%= payment_method.javascript_sdk_url(order: @order) %>"></script>
2
+
3
+ <div id="paypal-button-container"></div>
4
+ <input type="hidden" name="payment_source[<%= payment_method.id %>][paypal_order_id]" id="payments_source_paypal_order_id">
5
+ <input type="hidden" name="payment_source[<%= payment_method.id %>][paypal_email]" id="payments_source_paypal_email">
6
+
7
+ <script>
8
+ $( document ).ready(function() {
9
+ SolidusPaypalCommercePlatform.renderButton("<%= payment_method.id %>",<%= raw payment_method.button_style.to_json %>)
10
+ })
11
+ </script>
12
+
13
+ <div id="paypal_commerce_platform_overlay"></div>
@@ -0,0 +1,17 @@
1
+ <div style="margin-left:auto;margin-right:auto;width:50%;margin-top:20px;">
2
+ <script src="<%= payment_method.javascript_sdk_url(order: @order) %>">
3
+ </script>
4
+
5
+ <div id="paypal-button-container"></div>
6
+
7
+ <script>
8
+ Spree.current_order_id = "<%= @order.number %>"
9
+ Spree.current_order_token = "<%= @order.guest_token %>"
10
+ SolidusPaypalCommercePlatform.checkout_url = "<%= checkout_url %>"
11
+ $( document ).ready(function() {
12
+ SolidusPaypalCommercePlatform.renderCartButton("<%= payment_method.id %>",<%= raw payment_method.button_style.to_json %>)
13
+ })
14
+ </script>
15
+ </div>
16
+
17
+ <div id="paypal_commerce_platform_overlay"></div>
@@ -0,0 +1,15 @@
1
+ <div style="margin-top:20px;">
2
+ <script src="<%= payment_method.javascript_sdk_url %>">
3
+ </script>
4
+
5
+ <div id="paypal-button-container"></div>
6
+
7
+ <script>
8
+ SolidusPaypalCommercePlatform.checkout_url = "<%= checkout_url %>"
9
+ $( document ).ready(function() {
10
+ SolidusPaypalCommercePlatform.renderProductButton("<%= payment_method.id %>",<%= raw payment_method.button_style.to_json %>)
11
+ })
12
+ </script>
13
+ </div>
14
+
15
+ <div id="paypal_commerce_platform_overlay"></div>
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/solidus_paypal_commerce_platform/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'solidus_paypal_commerce_platform'
7
+ spec.version = SolidusPaypalCommercePlatform::VERSION
8
+ spec.authors = ['Sean Denny', 'Elia Schito']
9
+ spec.email = 'contact@solidus.io'
10
+
11
+ spec.summary = 'Integrate Solidus with Paypal Commerce Platform'
12
+ spec.homepage = 'https://github.com/nebulab/solidus_paypal_commerce_platform#readme'
13
+ spec.license = 'BSD-3-Clause'
14
+
15
+ spec.metadata['homepage_uri'] = spec.homepage
16
+ spec.metadata['source_code_uri'] = 'https://github.com/nebulab/solidus_paypal_commerce_platform'
17
+ spec.metadata['changelog_uri'] = 'https://github.com/nebulab/solidus_paypal_commerce_platform/releases'
18
+
19
+ spec.required_ruby_version = Gem::Requirement.new('~> 2.5')
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ files = Dir.chdir(__dir__) { `git ls-files -z`.split("\x0") }
24
+
25
+ spec.files = files.grep_v(%r{^(test|spec|features)/})
26
+ spec.test_files = files.grep(%r{^(test|spec|features)/})
27
+ spec.bindir = "exe"
28
+ spec.executables = files.grep(%r{^exe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
30
+
31
+ spec.add_dependency 'deface', '~> 1.5'
32
+ spec.add_dependency 'solidus_core', ['>= 2.0.0', '< 3']
33
+ spec.add_dependency 'solidus_support', '~> 0.5'
34
+ spec.add_dependency 'solidus_webhooks', '~> 0.2.0'
35
+
36
+ spec.add_dependency 'paypal-checkout-sdk'
37
+
38
+ spec.add_development_dependency 'solidus_dev_support'
39
+ end
@@ -0,0 +1,40 @@
1
+ require '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,38 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe "Cart page" do
4
+ describe "paypal payment method" 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
+
12
+ paypal_payment_method
13
+ allow_any_instance_of(Spree::OrdersController).to receive_messages(
14
+ current_order: order,
15
+ try_spree_current_user: user
16
+ )
17
+ end
18
+
19
+ def paypal_script_options
20
+ script_tag_url = URI(page.find('script[src*="sdk/js?"]', visible: false)[:src])
21
+ script_tag_url.query.split('&')
22
+ end
23
+
24
+ it "generate a js file with the correct credentials and intent attached" do
25
+ visit '/cart'
26
+ expect(paypal_script_options).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
27
+ end
28
+
29
+ context "when auto-capture is set to true" do
30
+ it "generate a js file with intent capture" do
31
+ paypal_payment_method.update(auto_capture: true)
32
+ visit '/cart'
33
+ expect(paypal_script_options).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
34
+ expect(paypal_script_options).to include("intent=capture")
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,81 @@
1
+ require '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) { OpenStruct.new(status_code: 500) }
8
+
9
+ before do
10
+ user = create(:user)
11
+ order.user = user
12
+ order.recalculate
13
+
14
+ paypal_payment_method
15
+ allow_any_instance_of(Spree::CheckoutController).to receive_messages(
16
+ current_order: order, try_spree_current_user: user
17
+ )
18
+ end
19
+
20
+ def paypal_script_options
21
+ script_tag_url = URI(page.find('script[src*="sdk/js?"]', visible: false)[:src])
22
+ script_tag_url.query.split('&')
23
+ end
24
+
25
+ it "generates a js file with the correct credentials and intent attached" do
26
+ visit '/checkout/payment'
27
+ expect(paypal_script_options).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
28
+ end
29
+
30
+ context "when auto-capture is set to true" do
31
+ it "generates a js file with intent capture" do
32
+ paypal_payment_method.update(auto_capture: true)
33
+ visit '/checkout/payment'
34
+ expect(paypal_script_options).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
35
+ expect(paypal_script_options).to include("intent=capture")
36
+ end
37
+ end
38
+
39
+ context "when no payment has been made" do
40
+ it "fails to process" do
41
+ visit '/checkout/payment'
42
+ choose(option: paypal_payment_method.id)
43
+ click_button("Save and Continue")
44
+ expect(page).to have_content("Payments source PayPal order can't be blank")
45
+ end
46
+ end
47
+
48
+ context "when a payment has been made" do
49
+ it "proceeds to the next step" do
50
+ visit '/checkout/payment'
51
+ choose(option: paypal_payment_method.id)
52
+ find(:xpath, "//input[@id='payments_source_paypal_order_id']", visible: false).set SecureRandom.hex(8)
53
+ click_button("Save and Continue")
54
+ expect(page).to have_css(".current", text: "Confirm")
55
+ end
56
+
57
+ it "records the paypal email address" do
58
+ visit '/checkout/payment'
59
+ choose(option: paypal_payment_method.id)
60
+ find(:xpath, "//input[@id='payments_source_paypal_order_id']", visible: false).set SecureRandom.hex(8)
61
+ find(:xpath, "//input[@id='payments_source_paypal_email']", visible: false).set "fake@email.com"
62
+ click_button("Save and Continue")
63
+ expect(Spree::Payment.last.source.paypal_email).to eq "fake@email.com"
64
+ end
65
+ end
66
+
67
+ context "when a payment fails" do
68
+ before { allow_any_instance_of(PayPal::PayPalHttpClient).to receive(:execute) { failed_response } }
69
+
70
+ it "redirects the user back to the payments page" 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
+ click_button("Save and Continue")
75
+ click_button("Place Order")
76
+ expect(page).to have_current_path("/checkout/payment")
77
+ expect(page).to have_content("Your payment was declined")
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe "Product page", js: true do
4
+ describe "paypal button" do
5
+ let(:paypal_payment_method) { create(:paypal_payment_method) }
6
+ let(:product) { create(:product, variants: [variant, variant_two]) }
7
+ let(:store) { create(:store) }
8
+ let(:variant) { create(:variant) }
9
+ let(:variant_two) { create(:variant) }
10
+
11
+ before do
12
+ paypal_payment_method
13
+ end
14
+
15
+ def paypal_script_options
16
+ script_tag_url = URI(page.find('script[src*="sdk/js?"]', visible: false)[:src])
17
+ script_tag_url.query.split('&')
18
+ end
19
+
20
+ it "generates a js file with the correct credentials and intent attached" do
21
+ visit '/products/' + product.slug
22
+ expect(paypal_script_options).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
23
+ end
24
+
25
+ context "when auto-capture is set to true" do
26
+ it "generates a js file with intent capture" do
27
+ paypal_payment_method.update(auto_capture: true)
28
+ visit '/products/' + product.slug
29
+ expect(paypal_script_options).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
30
+ expect(paypal_script_options).to include("intent=capture")
31
+ end
32
+ end
33
+
34
+ describe "order creation" do
35
+ before do
36
+ allow_any_instance_of(Spree::Core::ControllerHelpers::Store).to receive(:current_store) { store }
37
+ visit '/products/' + product.slug
38
+
39
+ # Stubbing out paypal methods since their JS doesn't load in correctly on tests
40
+ page.execute_script("paypal = {}")
41
+ page.execute_script("paypal.render = function(){}")
42
+ page.execute_script("paypal.Buttons = function(){return paypal}")
43
+
44
+ # Waiting until the paypal button becomes available, because the SPCP namespace
45
+ # isn't immediately available
46
+ page.find("#paypal-button-container")
47
+ end
48
+
49
+ it "creates an order successfully" do
50
+ page.evaluate_script("SolidusPaypalCommercePlatform.createOrder()")
51
+
52
+ expect(Spree::Order.last).not_to be nil
53
+ end
54
+
55
+ it "sets the Spree number and token variables" do
56
+ page.evaluate_script("SolidusPaypalCommercePlatform.createOrder()")
57
+
58
+ expect(page.evaluate_script("Spree.current_order_id")).to eq Spree::Order.last.number
59
+ expect(page.evaluate_script("Spree.current_order_token")).to eq Spree::Order.last.guest_token
60
+ end
61
+
62
+ it "uses the specified quantity" do
63
+ quantity = 12
64
+ fill_in('quantity', with: quantity)
65
+
66
+ page.evaluate_script("SolidusPaypalCommercePlatform.createOrder()")
67
+
68
+ expect(Spree::Order.last.line_items.first.quantity).to eq quantity
69
+ end
70
+
71
+ it "uses the selected variant" do
72
+ page.choose("variant_id_#{variant_two.id}")
73
+ page.evaluate_script("SolidusPaypalCommercePlatform.createOrder()")
74
+
75
+ expect(Spree::Order.last.line_items.first.variant_id).to eq variant_two.id
76
+ end
77
+ end
78
+ end
79
+ end