solidus_paypal_braintree 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +9 -1
  3. data/Gemfile +1 -3
  4. data/README.md +96 -5
  5. data/app/assets/config/solidus_paypal_braintree_manifest.js +1 -0
  6. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_blue_button_280x48.svg +19 -0
  7. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_blue_button_320x48.svg +19 -0
  8. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_blue_button_375x48.svg +19 -0
  9. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_white_button_280x48.svg +19 -0
  10. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_white_button_320x48.svg +19 -0
  11. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_white_button_375x48.svg +19 -0
  12. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_blue_acceptance_mark.svg +15 -0
  13. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_blue_button_280x48.svg +19 -0
  14. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_blue_button_320x48.svg +19 -0
  15. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_blue_button_375x48.svg +19 -0
  16. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_blue_logo.svg +18 -0
  17. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_white_acceptance_mark.svg +20 -0
  18. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_white_button_280x48.svg +19 -0
  19. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_white_button_320x48.svg +19 -0
  20. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_white_button_375x48.svg +19 -0
  21. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_white_logo.svg +18 -0
  22. data/app/assets/javascripts/solidus_paypal_braintree/client.js +34 -0
  23. data/app/assets/javascripts/solidus_paypal_braintree/constants.js +8 -0
  24. data/app/assets/javascripts/solidus_paypal_braintree/frontend.js +1 -0
  25. data/app/assets/javascripts/solidus_paypal_braintree/paypal_button.js +26 -3
  26. data/app/assets/javascripts/solidus_paypal_braintree/venmo_button.js +86 -0
  27. data/app/assets/javascripts/spree/backend/solidus_paypal_braintree.js +2 -2
  28. data/app/assets/javascripts/spree/frontend/paypal_button.js +3 -3
  29. data/app/assets/stylesheets/spree/frontend/solidus_paypal_braintree.css +12 -0
  30. data/app/decorators/controllers/solidus_paypal_braintree/checkout_controller_decorator.rb +1 -1
  31. data/app/decorators/controllers/solidus_paypal_braintree/orders_controller_decorator.rb +1 -1
  32. data/app/helpers/solidus_paypal_braintree/braintree_checkout_helper.rb +19 -5
  33. data/app/models/solidus_paypal_braintree/address.rb +43 -9
  34. data/app/models/solidus_paypal_braintree/avs_result.rb +3 -0
  35. data/app/models/solidus_paypal_braintree/configuration.rb +15 -2
  36. data/app/models/solidus_paypal_braintree/gateway.rb +27 -2
  37. data/app/models/solidus_paypal_braintree/source.rb +31 -2
  38. data/app/models/solidus_paypal_braintree/transaction.rb +1 -1
  39. data/app/models/solidus_paypal_braintree/transaction_address.rb +17 -13
  40. data/app/models/solidus_paypal_braintree/transaction_import.rb +2 -1
  41. data/app/overrides/spree/payments/payment/add_paypal_funding_source_to_payment.rb +9 -0
  42. data/app/views/spree/shared/_braintree_errors.html.erb +3 -0
  43. data/app/views/spree/shared/_paypal_braintree_head_scripts.html.erb +10 -6
  44. data/app/views/spree/shared/_paypal_cart_button.html.erb +2 -0
  45. data/app/views/spree/shared/_venmo_button.html.erb +33 -0
  46. data/config/locales/en.yml +34 -0
  47. data/config/locales/it.yml +2 -0
  48. data/db/migrate/20211222170950_add_paypal_funding_source_to_solidus_paypal_braintree_sources.rb +5 -0
  49. data/db/migrate/20220104150301_add_venmo_to_braintree_configuration.rb +5 -0
  50. data/lib/controllers/backend/solidus_paypal_braintree/configurations_controller.rb +4 -1
  51. data/lib/controllers/frontend/solidus_paypal_braintree/transactions_controller.rb +1 -0
  52. data/lib/solidus_paypal_braintree/engine.rb +4 -2
  53. data/lib/solidus_paypal_braintree/factories.rb +32 -1
  54. data/lib/solidus_paypal_braintree/version.rb +1 -1
  55. data/lib/views/backend/solidus_paypal_braintree/configurations/list.html.erb +8 -0
  56. data/lib/views/backend/spree/admin/payments/source_views/_paypal_braintree.html.erb +5 -0
  57. data/lib/views/backend/spree/admin/shared/preference_fields/_preference_select.html.erb +13 -0
  58. data/lib/views/frontend/solidus_paypal_braintree/payments/_payment.html.erb +12 -0
  59. data/lib/views/frontend/spree/checkout/payment/_paypal_braintree.html.erb +4 -0
  60. data/lib/views/frontend/spree/shared/_paypal_checkout_button.html.erb +2 -0
  61. data/solidus_paypal_braintree.gemspec +6 -5
  62. data/spec/controllers/solidus_paypal_braintree/transactions_controller_spec.rb +1 -1
  63. data/spec/features/frontend/braintree_credit_card_checkout_spec.rb +5 -1
  64. data/spec/features/frontend/venmo_checkout_spec.rb +189 -0
  65. data/spec/fixtures/cassettes/checkout/valid_venmo_transaction.yml +599 -0
  66. data/spec/helpers/solidus_paypal_braintree/braintree_checkout_helper_spec.rb +70 -0
  67. data/spec/models/solidus_paypal_braintree/address_spec.rb +20 -0
  68. data/spec/models/solidus_paypal_braintree/gateway_spec.rb +1 -1
  69. data/spec/models/solidus_paypal_braintree/source_spec.rb +139 -0
  70. data/spec/models/solidus_paypal_braintree/transaction_address_spec.rb +8 -26
  71. data/spec/models/solidus_paypal_braintree/transaction_import_spec.rb +17 -0
  72. data/spec/spec_helper.rb +3 -0
  73. metadata +52 -15
@@ -0,0 +1,189 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'spree/testing_support/order_walkthrough'
5
+
6
+ describe "Checkout", type: :feature, js: true do
7
+ let(:braintree_preferences) { { venmo: true }.merge(preferences) }
8
+ let(:preferences) { {} }
9
+ let(:user) { create(:user) }
10
+ let!(:payment_method) { create_gateway }
11
+
12
+ before do
13
+ create(:store, payment_methods: [payment_method]).tap do |s|
14
+ s.braintree_configuration.update!(braintree_preferences)
15
+ end
16
+
17
+ go_to_payment_checkout_page
18
+ end
19
+
20
+ context 'with Venmo checkout' do
21
+ context 'when Venmo is disabled' do
22
+ let(:preferences) { { venmo: false } }
23
+
24
+ it 'does not load the Venmo payment button' do
25
+ expect(page).not_to have_selector('#venmo-button')
26
+ end
27
+ end
28
+
29
+ context 'when Venmo is enabled' do
30
+ it 'loads the Venmo payment button' do
31
+ expect(page).to have_selector('#venmo-button')
32
+ end
33
+ end
34
+
35
+ context "when Venmo's button style is customized" do
36
+ context 'when venmo_button_color is "blue" and venmo_button_width is "280"' do
37
+ let(:preferences) { { preferred_venmo_button_color: 'blue', preferred_venmo_button_width: '280' } }
38
+
39
+ it 'has the correct style' do
40
+ venmo_button.assert_matches_style(width: '280px', 'background-image': /venmo_blue_button_280x48/)
41
+ venmo_button.hover
42
+ venmo_button.assert_matches_style('background-image': /venmo_active_blue_button_280x48/)
43
+ end
44
+ end
45
+
46
+ context 'when venmo_button_color is "white" and venmo_button_width is "375"' do
47
+ let(:preferences) { { preferred_venmo_button_color: 'white', preferred_venmo_button_width: '375' } }
48
+
49
+ it 'has the correct style' do
50
+ venmo_button.assert_matches_style(width: '375px', 'background-image': /venmo_white_button_375x48/)
51
+ venmo_button.hover
52
+ venmo_button.assert_matches_style('background-image': /venmo_active_white_button_375x48/)
53
+ end
54
+ end
55
+ end
56
+
57
+ context 'when the Venmo button is clicked' do
58
+ before { venmo_button.click }
59
+
60
+ it 'opens the QR modal which shows an error when closed' do
61
+ within_frame(venmo_frame) do
62
+ expect(page).to have_selector('#venmo-qr-code-view')
63
+
64
+ click_button('close-icon')
65
+
66
+ expect(page).not_to have_selector('#venmo-qr-code-view')
67
+ end
68
+
69
+ expect(page).to have_content('Venmo authorization was canceled by closing the Venmo Desktop modal.')
70
+ end
71
+ end
72
+
73
+ context 'with Venmo transactions', vcr: { cassette_name: 'checkout/valid_venmo_transaction' } do
74
+ before do
75
+ fake_venmo_successful_tokenization
76
+ end
77
+
78
+ context 'with CreditCard disabled' do
79
+ it 'can checkout with Venmo' do
80
+ next_checkout_step
81
+ finalize_checkout
82
+
83
+ expect(Spree::Order.last.complete?).to eq(true)
84
+ end
85
+ end
86
+
87
+ # To test that the hosted-fields inputs do not conflict with Venmo's
88
+ context 'with CreditCard enabled' do
89
+ let(:preferences) { { credit_card: true } }
90
+
91
+ it 'can checkout with Venmo' do
92
+ disable_hosted_fields_inputs
93
+ disable_hosted_fields_form_listener
94
+
95
+ next_checkout_step
96
+ finalize_checkout
97
+
98
+ expect(Spree::Order.last.complete?).to eq(true)
99
+ expect(Spree::Payment.last.source.venmo?).to eq(true)
100
+ end
101
+ end
102
+
103
+ # https://developer.paypal.com/braintree/docs/guides/venmo/client-side#custom-integration
104
+ it "meet's Braintree's acceptance criteria during checkout", aggregate_failures: true do
105
+ next_checkout_step
106
+
107
+ expect(page).to have_content('Payment Type: Venmo')
108
+
109
+ finalize_checkout
110
+
111
+ expect(page).to have_content('Venmo Account: venmojoe')
112
+ end
113
+
114
+ # the VCR must be based on this test, so it includes HTTP requests of the second order
115
+ it 'saves the used Venmo source in the wallet and can be reused' do
116
+ next_checkout_step
117
+ finalize_checkout
118
+ go_to_payment_checkout_page(order_number: 'R300000002')
119
+
120
+ expect(Spree::User.first.wallet.wallet_payment_sources).not_to be_empty
121
+ expect(page).to have_selector('#existing_cards')
122
+ expect(page).to have_content('venmojoe')
123
+
124
+ next_checkout_step
125
+ finalize_checkout
126
+
127
+ expect(Spree::Order.all.all?(&:complete?)).to eq(true)
128
+ end
129
+ end
130
+ end
131
+
132
+ private
133
+
134
+ def go_to_payment_checkout_page(order_number: 'R300000001' )
135
+ order = if Spree.solidus_gem_version >= Gem::Version.new('2.6.0')
136
+ Spree::TestingSupport::OrderWalkthrough.up_to(:address)
137
+ else
138
+ OrderWalkthrough.up_to(:address)
139
+ end
140
+
141
+ order.update!(user: user, number: order_number) # constant order number for VCRs
142
+
143
+ allow_any_instance_of(Spree::CheckoutController).to receive_messages(current_order: order)
144
+ allow_any_instance_of(Spree::CheckoutController).to receive_messages(try_spree_current_user: Spree::User.first)
145
+ allow_any_instance_of(Spree::Payment).to receive(:gateway_order_id).and_return(order_number)
146
+
147
+ visit spree.checkout_state_path(order.state)
148
+ next_checkout_step
149
+ end
150
+
151
+ def next_checkout_step
152
+ click_button('Save and Continue')
153
+ end
154
+
155
+ def finalize_checkout
156
+ click_button('Place Order')
157
+ end
158
+
159
+ def venmo_button
160
+ find_button('venmo-button', disabled: false)
161
+ end
162
+
163
+ def venmo_frame
164
+ find('#venmo-desktop-iframe')
165
+ end
166
+
167
+ def fake_venmo_successful_tokenization
168
+ enable_venmo_inputs
169
+ fake_payment_method_nonce
170
+ end
171
+
172
+ def enable_venmo_inputs
173
+ page.execute_script("$('.venmo-fields input').each(function(_index, input){input.removeAttribute('disabled');});")
174
+ end
175
+
176
+ def fake_payment_method_nonce
177
+ page.execute_script("$('#venmo_payment_method_nonce').val('fake-venmo-account-nonce');")
178
+ end
179
+
180
+ def disable_hosted_fields_inputs
181
+ page.execute_script("$('.hosted-fields input').each(function(_index, input){input.disabled=true;});")
182
+ end
183
+
184
+ def disable_hosted_fields_form_listener
185
+ # Once the submit button is enabled, the submit listener has been added
186
+ find("#checkout_form_payment input[type='submit']:not(:disabled)")
187
+ page.execute_script("$('#checkout_form_payment').off('submit');")
188
+ end
189
+ end