solidus_paypal_braintree 0.4.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +40 -0
- data/.gem_release.yml +5 -0
- data/.github/stale.yml +17 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.rubocop.yml +68 -0
- data/CHANGELOG.md +258 -0
- data/Gemfile +43 -0
- data/LICENSE +2 -2
- data/README.md +77 -23
- data/Rakefile +4 -25
- data/app/assets/javascripts/solidus_paypal_braintree/checkout.js +32 -3
- data/app/assets/javascripts/solidus_paypal_braintree/client.js +23 -4
- data/app/assets/javascripts/solidus_paypal_braintree/constants.js +19 -0
- data/app/assets/javascripts/solidus_paypal_braintree/frontend.js +1 -0
- data/app/assets/javascripts/solidus_paypal_braintree/hosted_form.js +15 -5
- data/app/assets/javascripts/solidus_paypal_braintree/paypal_button.js +47 -20
- data/app/assets/javascripts/solidus_paypal_braintree/paypal_messaging.js +22 -0
- data/app/decorators/controllers/solidus_paypal_braintree/admin_payments_controller_decorator.rb +11 -0
- data/app/decorators/controllers/solidus_paypal_braintree/checkout_controller_decorator.rb +11 -0
- data/app/decorators/controllers/solidus_paypal_braintree/client_tokens_controller.rb +41 -0
- data/app/decorators/controllers/solidus_paypal_braintree/orders_controller_decorator.rb +11 -0
- data/app/decorators/models/solidus_paypal_braintree/spree/store_decorator.rb +20 -0
- data/app/decorators/models/solidus_paypal_braintree/spree/user_decorator.rb +13 -0
- data/app/helpers/solidus_paypal_braintree/braintree_admin_helper.rb +23 -0
- data/app/helpers/solidus_paypal_braintree/braintree_checkout_helper.rb +46 -0
- data/app/models/application_record.rb +2 -0
- data/app/models/solidus_paypal_braintree/address.rb +30 -0
- data/app/models/solidus_paypal_braintree/configuration.rb +26 -3
- data/app/models/solidus_paypal_braintree/customer.rb +7 -3
- data/app/models/solidus_paypal_braintree/gateway.rb +52 -20
- data/app/models/solidus_paypal_braintree/response.rb +3 -2
- data/app/models/solidus_paypal_braintree/source.rb +21 -7
- data/app/models/solidus_paypal_braintree/transaction.rb +2 -0
- data/app/models/solidus_paypal_braintree/transaction_address.rb +30 -12
- data/app/models/solidus_paypal_braintree/transaction_import.rb +13 -9
- data/app/views/spree/api/payments/source_views/_paypal_braintree.json.jbuilder +3 -0
- data/app/views/spree/checkout/existing_payment/_paypal_braintree.html.erb +10 -0
- data/app/views/spree/shared/_apple_pay_button.html.erb +2 -2
- data/app/views/spree/shared/_braintree_errors.html.erb +11 -17
- data/app/views/spree/shared/_braintree_hosted_fields.html.erb +24 -9
- data/app/views/spree/shared/_paypal_braintree_head_scripts.html.erb +9 -6
- data/app/views/spree/shared/_paypal_cart_button.html.erb +16 -2
- data/app/views/spree/shared/_paypal_messaging.html.erb +13 -0
- data/bin/console +17 -0
- data/bin/rails +15 -0
- data/bin/setup +8 -0
- data/config/locales/en.yml +10 -0
- data/config/locales/it.yml +51 -8
- data/config/routes.rb +2 -0
- data/db/migrate/20160906201711_create_solidus_paypal_braintree_customers.rb +3 -1
- data/db/migrate/20161125172005_add_braintree_configuration_to_stores.rb +5 -7
- data/db/migrate/20170505193712_add_null_constraint_to_sources.rb +3 -1
- data/db/migrate/20190705115327_add_paypal_button_preferences_to_braintree_configurations.rb +5 -0
- data/db/migrate/20190911141712_add_3d_secure_to_braintree_configuration.rb +5 -0
- data/lib/controllers/backend/solidus_paypal_braintree/configurations_controller.rb +20 -5
- data/lib/controllers/frontend/solidus_paypal_braintree/checkouts_controller.rb +25 -21
- data/lib/controllers/frontend/solidus_paypal_braintree/transactions_controller.rb +55 -51
- data/lib/generators/solidus_paypal_braintree/install/install_generator.rb +7 -5
- data/lib/solidus_paypal_braintree.rb +4 -0
- data/lib/solidus_paypal_braintree/country_mapper.rb +4 -2
- data/lib/solidus_paypal_braintree/engine.rb +11 -11
- data/lib/solidus_paypal_braintree/factories.rb +8 -4
- data/lib/solidus_paypal_braintree/request_protection.rb +3 -0
- data/lib/solidus_paypal_braintree/version.rb +3 -1
- data/lib/views/backend/solidus_paypal_braintree/configurations/list.html.erb +30 -5
- data/lib/views/backend/spree/admin/payments/source_forms/_paypal_braintree.html.erb +2 -2
- data/lib/views/backend/spree/admin/payments/source_views/_paypal_braintree.html.erb +2 -2
- data/lib/views/backend_v1.2/spree/admin/payments/source_forms/_paypal_braintree.html.erb +2 -2
- data/lib/views/frontend/spree/checkout/payment/_paypal_braintree.html.erb +4 -2
- data/lib/views/frontend/spree/shared/_paypal_checkout_button.html.erb +30 -0
- data/solidus_paypal_braintree.gemspec +42 -0
- data/spec/controllers/solidus_paypal_braintree/checkouts_controller_spec.rb +99 -0
- data/spec/controllers/solidus_paypal_braintree/client_tokens_controller_spec.rb +55 -0
- data/spec/controllers/solidus_paypal_braintree/configurations_controller_spec.rb +73 -0
- data/spec/controllers/solidus_paypal_braintree/transactions_controller_spec.rb +183 -0
- data/spec/features/backend/configuration_spec.rb +23 -0
- data/spec/features/backend/new_payment_spec.rb +137 -0
- data/spec/features/frontend/braintree_credit_card_checkout_spec.rb +187 -0
- data/spec/features/frontend/paypal_checkout_spec.rb +166 -0
- data/spec/fixtures/cassettes/admin/invalid_credit_card.yml +63 -0
- data/spec/fixtures/cassettes/admin/resubmit_credit_card.yml +352 -0
- data/spec/fixtures/cassettes/admin/valid_credit_card.yml +412 -0
- data/spec/fixtures/cassettes/braintree/create_profile.yml +71 -0
- data/spec/fixtures/cassettes/braintree/generate_token.yml +63 -0
- data/spec/fixtures/cassettes/braintree/token.yml +63 -0
- data/spec/fixtures/cassettes/checkout/invalid_credit_card.yml +63 -0
- data/spec/fixtures/cassettes/checkout/resubmit_credit_card.yml +216 -0
- data/spec/fixtures/cassettes/checkout/update.yml +71 -0
- data/spec/fixtures/cassettes/checkout/valid_credit_card.yml +156 -0
- data/spec/fixtures/cassettes/gateway/authorize.yml +86 -0
- data/spec/fixtures/cassettes/gateway/authorize/credit_card/address.yml +86 -0
- data/spec/fixtures/cassettes/gateway/authorize/merchant_account/EUR.yml +154 -0
- data/spec/fixtures/cassettes/gateway/authorize/paypal/EUR.yml +90 -0
- data/spec/fixtures/cassettes/gateway/authorize/paypal/address.yml +90 -0
- data/spec/fixtures/cassettes/gateway/authorized_transaction.yml +73 -0
- data/spec/fixtures/cassettes/gateway/cancel/missing.yml +63 -0
- data/spec/fixtures/cassettes/gateway/cancel/refunds.yml +272 -0
- data/spec/fixtures/cassettes/gateway/cancel/void.yml +201 -0
- data/spec/fixtures/cassettes/gateway/capture.yml +141 -0
- data/spec/fixtures/cassettes/gateway/complete.yml +157 -0
- data/spec/fixtures/cassettes/gateway/credit.yml +208 -0
- data/spec/fixtures/cassettes/gateway/purchase.yml +87 -0
- data/spec/fixtures/cassettes/gateway/settled_transaction.yml +140 -0
- data/spec/fixtures/cassettes/gateway/void.yml +137 -0
- data/spec/fixtures/cassettes/source/card_type.yml +267 -0
- data/spec/fixtures/cassettes/source/last4.yml +267 -0
- data/spec/fixtures/cassettes/transaction/import/valid.yml +71 -0
- data/spec/fixtures/cassettes/transaction/import/valid/capture.yml +224 -0
- data/spec/fixtures/views/spree/orders/edit.html.erb +50 -0
- data/spec/helpers/solidus_paypal_braintree/braintree_admin_helper_spec.rb +17 -0
- data/spec/models/solidus_paypal_braintree/address_spec.rb +51 -0
- data/spec/models/solidus_paypal_braintree/avs_result_spec.rb +317 -0
- data/spec/models/solidus_paypal_braintree/gateway_spec.rb +692 -0
- data/spec/models/solidus_paypal_braintree/response_spec.rb +280 -0
- data/spec/models/solidus_paypal_braintree/source_spec.rb +360 -0
- data/spec/models/solidus_paypal_braintree/transaction_address_spec.rb +253 -0
- data/spec/models/solidus_paypal_braintree/transaction_import_spec.rb +283 -0
- data/spec/models/solidus_paypal_braintree/transaction_spec.rb +85 -0
- data/spec/models/spree/store_spec.rb +14 -0
- data/spec/requests/spree/api/orders_controller_spec.rb +36 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/support/capybara.rb +7 -0
- data/spec/support/factories.rb +2 -0
- data/spec/support/gateway_helpers.rb +29 -0
- data/spec/support/order_ready_for_payment.rb +37 -0
- data/spec/support/vcr.rb +42 -0
- data/spec/support/views.rb +1 -0
- metadata +182 -194
- data/app/controllers/solidus_paypal_braintree/client_tokens_controller.rb +0 -22
- data/app/helpers/braintree_admin_helper.rb +0 -18
- data/app/models/spree/store_decorator.rb +0 -11
- data/app/views/spree/shared/_paypal_checkout_button.html.erb +0 -27
- data/config/initializers/braintree.rb +0 -1
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SolidusPaypalBraintree::ConfigurationsController, type: :controller do
|
4
|
+
routes { SolidusPaypalBraintree::Engine.routes }
|
5
|
+
|
6
|
+
let!(:store_1) { create :store }
|
7
|
+
let!(:store_2) { create :store }
|
8
|
+
|
9
|
+
stub_authorization!
|
10
|
+
|
11
|
+
describe "GET #list" do
|
12
|
+
subject { get :list }
|
13
|
+
|
14
|
+
it "assigns all store's configurations as @configurations" do
|
15
|
+
subject
|
16
|
+
expect(assigns(:configurations)).
|
17
|
+
to eq [store_1.braintree_configuration, store_2.braintree_configuration]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "renders the correct view" do
|
21
|
+
expect(subject).to render_template :list
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "POST #update" do
|
26
|
+
subject { post :update, params: configurations_params }
|
27
|
+
|
28
|
+
let(:paypal_button_color) { 'blue' }
|
29
|
+
let(:configurations_params) do
|
30
|
+
{
|
31
|
+
configurations: {
|
32
|
+
configuration_fields: {
|
33
|
+
store_1.braintree_configuration.id.to_s => { paypal: true, apple_pay: true },
|
34
|
+
store_2.braintree_configuration.id.to_s => {
|
35
|
+
paypal: true,
|
36
|
+
apple_pay: false,
|
37
|
+
preferred_paypal_button_color: paypal_button_color
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
context "with valid parameters" do
|
45
|
+
it "updates the configuration" do
|
46
|
+
expect { subject }.to change { store_1.braintree_configuration.reload.paypal }.
|
47
|
+
from(false).to(true)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "displays a success message to the user" do
|
51
|
+
subject
|
52
|
+
expect(flash[:success]).to eq "Successfully updated Braintree configurations."
|
53
|
+
end
|
54
|
+
|
55
|
+
it "displays all configurations" do
|
56
|
+
expect(subject).to redirect_to action: :list
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "with invalid parameters" do
|
61
|
+
let(:paypal_button_color) { 'invalid-color' }
|
62
|
+
|
63
|
+
it "displays an error message to the user" do
|
64
|
+
subject
|
65
|
+
expect(flash[:error]).to eq "An error occurred while updating Braintree configurations."
|
66
|
+
end
|
67
|
+
|
68
|
+
it "returns the user to the edit page" do
|
69
|
+
expect(subject).to redirect_to action: :list
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe SolidusPaypalBraintree::TransactionsController, type: :controller do
|
4
|
+
routes { SolidusPaypalBraintree::Engine.routes }
|
5
|
+
|
6
|
+
let!(:country) { create :country }
|
7
|
+
let(:line_item) { create :line_item, price: 50 }
|
8
|
+
let(:order) do
|
9
|
+
Spree::Order.create!(
|
10
|
+
line_items: [line_item],
|
11
|
+
email: 'test@example.com',
|
12
|
+
bill_address: create(:address, country: country),
|
13
|
+
ship_address: create(:address, country: country),
|
14
|
+
user: create(:user)
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:payment_method) { create_gateway }
|
19
|
+
|
20
|
+
before do
|
21
|
+
allow(controller).to receive(:spree_current_user) { order.user }
|
22
|
+
allow(controller).to receive(:current_order) { order }
|
23
|
+
create :shipping_method, cost: 5
|
24
|
+
create :state, abbr: "WA", country: country
|
25
|
+
end
|
26
|
+
|
27
|
+
cassette_options = {
|
28
|
+
cassette_name: "transactions_controller/create",
|
29
|
+
match_requests_on: [:braintree_uri]
|
30
|
+
}
|
31
|
+
describe "POST create", vcr: cassette_options do
|
32
|
+
subject(:post_create) { post :create, params: params }
|
33
|
+
|
34
|
+
let!(:country) { create :country, iso: 'US' }
|
35
|
+
|
36
|
+
let(:params) do
|
37
|
+
{
|
38
|
+
transaction: {
|
39
|
+
nonce: "fake-valid-nonce",
|
40
|
+
payment_type: SolidusPaypalBraintree::Source::PAYPAL,
|
41
|
+
phone: "1112223333",
|
42
|
+
email: "batman@example.com",
|
43
|
+
address_attributes: {
|
44
|
+
name: "Wade Wilson",
|
45
|
+
address_line_1: "123 Fake Street",
|
46
|
+
city: "Seattle",
|
47
|
+
zip: "98101",
|
48
|
+
state_code: "WA",
|
49
|
+
country_code: "US"
|
50
|
+
}
|
51
|
+
},
|
52
|
+
payment_method_id: payment_method.id
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
before do
|
57
|
+
create :state, abbr: "WA", country: country
|
58
|
+
end
|
59
|
+
|
60
|
+
context "when import has invalid address" do
|
61
|
+
before { params[:transaction][:address_attributes][:city] = nil }
|
62
|
+
|
63
|
+
it "raises a validation error" do
|
64
|
+
expect { post_create }.to raise_error(
|
65
|
+
SolidusPaypalBraintree::TransactionsController::InvalidImportError,
|
66
|
+
"Import invalid: " \
|
67
|
+
"Address is invalid, " \
|
68
|
+
"Address city can't be blank"
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "when the transaction is valid", vcr: {
|
74
|
+
cassette_name: 'transaction/import/valid',
|
75
|
+
match_requests_on: [:braintree_uri]
|
76
|
+
} do
|
77
|
+
it "imports the payment" do
|
78
|
+
expect { post_create }.to change { order.payments.count }.by(1)
|
79
|
+
expect(order.payments.first.amount).to eq 55
|
80
|
+
end
|
81
|
+
|
82
|
+
context "when no end state is provided" do
|
83
|
+
it "advances the order to confirm" do
|
84
|
+
post_create
|
85
|
+
expect(order).to be_confirm
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "when end state provided is delivery" do
|
90
|
+
let(:params) { super().merge(state: 'delivery') }
|
91
|
+
|
92
|
+
it "advances the order to delivery" do
|
93
|
+
post_create
|
94
|
+
expect(order).to be_delivery
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "with provided address" do
|
99
|
+
it "creates a new address" do
|
100
|
+
# Creating the order also creates 3 addresses, we want to make sure
|
101
|
+
# the transaction import only creates 1 new one
|
102
|
+
order
|
103
|
+
expect { post_create }.to change { Spree::Address.count }.by(1)
|
104
|
+
expect(Spree::Address.last.full_name).to eq "Wade Wilson"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context "without country ISO" do
|
109
|
+
before do
|
110
|
+
params[:transaction][:address_attributes][:country_code] = ""
|
111
|
+
params[:transaction][:address_attributes][:country_name] = "United States"
|
112
|
+
end
|
113
|
+
|
114
|
+
it "creates a new address, looking up the ISO by country name" do
|
115
|
+
order
|
116
|
+
expect { post_create }.to change { Spree::Address.count }.by(1)
|
117
|
+
expect(Spree::Address.last.country.iso).to eq "US"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context "without transaction address" do
|
122
|
+
before { params[:transaction].delete(:address_attributes) }
|
123
|
+
|
124
|
+
it "does not create a new address" do
|
125
|
+
order
|
126
|
+
expect { post_create }.not_to(change { Spree::Address.count })
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context "when format is HTML" do
|
131
|
+
context "when import! leaves the order in confirm" do
|
132
|
+
it "redirects the user to the confirm page" do
|
133
|
+
expect(post_create).to redirect_to spree.checkout_state_path("confirm")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "when import! completes the order" do
|
138
|
+
before { allow(order).to receive(:complete?).and_return(true) }
|
139
|
+
|
140
|
+
it "displays the order to the user" do
|
141
|
+
expect(post_create).to redirect_to spree.order_path(order)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context "when format is JSON" do
|
147
|
+
before { params[:format] = :json }
|
148
|
+
|
149
|
+
it "has a successful response" do
|
150
|
+
post_create
|
151
|
+
expect(response).to be_successful
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context "when the transaction is invalid" do
|
157
|
+
before { params[:transaction][:email] = nil }
|
158
|
+
|
159
|
+
context "when format is HTML" do
|
160
|
+
it "raises an error including the validation messages" do
|
161
|
+
expect { post_create }.to raise_error(
|
162
|
+
SolidusPaypalBraintree::TransactionsController::InvalidImportError,
|
163
|
+
"Import invalid: Email can't be blank"
|
164
|
+
)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "when format is JSON" do
|
169
|
+
before { params[:format] = :json }
|
170
|
+
|
171
|
+
it "has a failed status" do
|
172
|
+
post_create
|
173
|
+
expect(response.status).to eq 422
|
174
|
+
end
|
175
|
+
|
176
|
+
it "returns the errors as JSON" do
|
177
|
+
post_create
|
178
|
+
expect(JSON.parse(response.body)["errors"]["email"]).to eq ["can't be blank"]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe "viewing the configuration interface" do
|
4
|
+
stub_authorization!
|
5
|
+
|
6
|
+
# Regression to ensure this page still renders on old versions of solidus
|
7
|
+
it "doesn't raise any errors due to unavailable route helpers" do
|
8
|
+
visit "/solidus_paypal_braintree/configurations/list"
|
9
|
+
expect(page).to have_content("Braintree Configurations")
|
10
|
+
end
|
11
|
+
|
12
|
+
# Regression to ensure this page renders on Solidus 2.4
|
13
|
+
it "doesn't raise any errors due to unavailable preference field partial" do
|
14
|
+
Rails.application.config.spree.payment_methods << SolidusPaypalBraintree::Gateway
|
15
|
+
Spree::PaymentMethod.create!(
|
16
|
+
type: 'SolidusPaypalBraintree::Gateway',
|
17
|
+
name: 'Braintree Payments'
|
18
|
+
)
|
19
|
+
visit '/admin/payment_methods'
|
20
|
+
page.find('a[title="Edit"]').click
|
21
|
+
expect(page).to have_field 'Name', with: 'Braintree Payments'
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'spree/testing_support/order_walkthrough'
|
3
|
+
|
4
|
+
shared_context "with backend checkout setup" do
|
5
|
+
let(:braintree) { new_gateway(active: true) }
|
6
|
+
let!(:gateway) { create :payment_method }
|
7
|
+
let(:order) { create(:completed_order_with_totals, number: 'R9999999') }
|
8
|
+
let(:pending_case_insensitive) { /pending/i }
|
9
|
+
let(:expiration) { "02/#{Date.current.year.next}" }
|
10
|
+
|
11
|
+
before do
|
12
|
+
braintree.save!
|
13
|
+
create(:store, payment_methods: [gateway, braintree]).tap do |store|
|
14
|
+
store.braintree_configuration.update!(credit_card: true)
|
15
|
+
end
|
16
|
+
|
17
|
+
allow_any_instance_of(SolidusPaypalBraintree::Source).to receive(:nonce).and_return("fake-valid-nonce")
|
18
|
+
|
19
|
+
# Order and payment numbers must be identical between runs to re-use the VCR
|
20
|
+
# cassette
|
21
|
+
allow_any_instance_of(Spree::Payment).to receive(:number).and_return("123ABC")
|
22
|
+
end
|
23
|
+
|
24
|
+
around do |example|
|
25
|
+
Capybara.using_wait_time(20) { example.run }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'creating a new payment', type: :feature, js: true do
|
30
|
+
stub_authorization!
|
31
|
+
|
32
|
+
context "with valid credit card data", vcr: {
|
33
|
+
cassette_name: 'admin/valid_credit_card',
|
34
|
+
match_requests_on: [:braintree_uri]
|
35
|
+
} do
|
36
|
+
include_context "with backend checkout setup"
|
37
|
+
|
38
|
+
it "checks out successfully" do
|
39
|
+
visit "/admin/orders/#{order.number}/payments/new"
|
40
|
+
choose('Braintree')
|
41
|
+
expect(page).to have_selector("#payment_method_#{braintree.id}", visible: :visible)
|
42
|
+
expect(page).to have_selector("iframe#braintree-hosted-field-number")
|
43
|
+
|
44
|
+
within_frame("braintree-hosted-field-number") do
|
45
|
+
fill_in("credit-card-number", with: "4111111111111111")
|
46
|
+
end
|
47
|
+
within_frame("braintree-hosted-field-expirationDate") do
|
48
|
+
fill_in("expiration", with: expiration)
|
49
|
+
end
|
50
|
+
within_frame("braintree-hosted-field-cvv") do
|
51
|
+
fill_in("cvv", with: "123")
|
52
|
+
end
|
53
|
+
|
54
|
+
click_button("Update")
|
55
|
+
|
56
|
+
within('table#payments') do
|
57
|
+
expect(page).to have_content('Braintree')
|
58
|
+
expect(page).to have_content(pending_case_insensitive)
|
59
|
+
end
|
60
|
+
|
61
|
+
click_icon(:capture)
|
62
|
+
|
63
|
+
expect(page).not_to have_content('Cannot perform requested operation')
|
64
|
+
expect(page).to have_content('Payment Updated')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "with invalid credit card data" do
|
69
|
+
include_context "with backend checkout setup"
|
70
|
+
|
71
|
+
# Attempt to submit an invalid form once
|
72
|
+
before do
|
73
|
+
visit "/admin/orders/#{order.number}/payments/new"
|
74
|
+
choose('Braintree')
|
75
|
+
|
76
|
+
within_frame("braintree-hosted-field-number") do
|
77
|
+
fill_in("credit-card-number", with: "1111111111111111")
|
78
|
+
end
|
79
|
+
within_frame("braintree-hosted-field-expirationDate") do
|
80
|
+
fill_in("expiration", with: expiration)
|
81
|
+
end
|
82
|
+
within_frame("braintree-hosted-field-cvv") do
|
83
|
+
fill_in("cvv", with: "123")
|
84
|
+
end
|
85
|
+
|
86
|
+
click_button "Update"
|
87
|
+
end
|
88
|
+
|
89
|
+
it "displays a meaningful error message" do
|
90
|
+
expect(page).to have_text(
|
91
|
+
"BraintreeError: Some payment input fields are invalid. Cannot tokenize invalid card fields."
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Same error should be produced when submitting an empty form again
|
96
|
+
context "when user tries to resubmit another invalid form", vcr: {
|
97
|
+
cassette_name: "admin/invalid_credit_card",
|
98
|
+
match_requests_on: [:braintree_uri]
|
99
|
+
} do
|
100
|
+
it "displays a meaningful error message" do
|
101
|
+
click_button "Update"
|
102
|
+
expect(page).to have_text(
|
103
|
+
"BraintreeError: Some payment input fields are invalid. Cannot tokenize invalid card fields."
|
104
|
+
)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# User should be able to checkout after submit fails once
|
109
|
+
context "when user enters valid data", vcr: {
|
110
|
+
cassette_name: "admin/resubmit_credit_card",
|
111
|
+
match_requests_on: [:braintree_uri]
|
112
|
+
} do
|
113
|
+
it "creates the payment successfully" do
|
114
|
+
within_frame("braintree-hosted-field-number") do
|
115
|
+
fill_in("credit-card-number", with: "4111111111111111")
|
116
|
+
end
|
117
|
+
within_frame("braintree-hosted-field-expirationDate") do
|
118
|
+
fill_in("expiration", with: expiration)
|
119
|
+
end
|
120
|
+
within_frame("braintree-hosted-field-cvv") do
|
121
|
+
fill_in("cvv", with: "123")
|
122
|
+
end
|
123
|
+
click_button("Update")
|
124
|
+
|
125
|
+
within('table#payments') do
|
126
|
+
expect(page).to have_content('Braintree')
|
127
|
+
expect(page).to have_content(pending_case_insensitive)
|
128
|
+
end
|
129
|
+
|
130
|
+
click_icon(:capture)
|
131
|
+
|
132
|
+
expect(page).not_to have_content('Cannot perform requested operation')
|
133
|
+
expect(page).to have_content('Payment Updated')
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'spree/testing_support/order_walkthrough'
|
3
|
+
|
4
|
+
shared_context "with frontend checkout setup" do
|
5
|
+
let(:braintree) { new_gateway(active: true) }
|
6
|
+
let!(:gateway) { create :payment_method }
|
7
|
+
let(:three_d_secure_enabled) { false }
|
8
|
+
let(:card_number) { "4111111111111111" }
|
9
|
+
let(:card_expiration) { "01/#{Time.now.utc.year + 2}" }
|
10
|
+
|
11
|
+
before do
|
12
|
+
braintree.save!
|
13
|
+
|
14
|
+
create(:store, payment_methods: [gateway, braintree]).tap do |store|
|
15
|
+
store.braintree_configuration.update!(
|
16
|
+
credit_card: true,
|
17
|
+
three_d_secure: three_d_secure_enabled
|
18
|
+
)
|
19
|
+
|
20
|
+
braintree.update(
|
21
|
+
preferred_credit_card_fields_style: { input: { 'font-size': '30px' } },
|
22
|
+
preferred_placeholder_text: { number: "Enter Your Card Number" }
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
order = if Spree.solidus_gem_version >= Gem::Version.new('2.6.0')
|
27
|
+
Spree::TestingSupport::OrderWalkthrough.up_to(:delivery)
|
28
|
+
else
|
29
|
+
OrderWalkthrough.up_to(:delivery)
|
30
|
+
end
|
31
|
+
|
32
|
+
user = create(:user)
|
33
|
+
order.user = user
|
34
|
+
order.number = "R9999999"
|
35
|
+
order.recalculate
|
36
|
+
|
37
|
+
allow_any_instance_of(Spree::CheckoutController).to receive_messages(current_order: order)
|
38
|
+
allow_any_instance_of(Spree::CheckoutController).to receive_messages(try_spree_current_user: user)
|
39
|
+
allow_any_instance_of(Spree::Payment).to receive(:number).and_return("123ABC")
|
40
|
+
allow_any_instance_of(SolidusPaypalBraintree::Source).to receive(:nonce).and_return("fake-valid-nonce")
|
41
|
+
|
42
|
+
visit spree.checkout_state_path(:delivery)
|
43
|
+
click_button "Save and Continue"
|
44
|
+
choose("Braintree")
|
45
|
+
end
|
46
|
+
|
47
|
+
around do |example|
|
48
|
+
Capybara.using_wait_time(20) { example.run }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'entering credit card details', type: :feature, js: true do
|
53
|
+
context 'when page loads' do
|
54
|
+
include_context "with frontend checkout setup"
|
55
|
+
|
56
|
+
it "selectors display correctly" do
|
57
|
+
expect(page).to have_selector("#payment_method_#{braintree.id}", visible: :visible)
|
58
|
+
expect(page).to have_selector("iframe#braintree-hosted-field-number")
|
59
|
+
expect(page).to have_selector("iframe[type='number']")
|
60
|
+
end
|
61
|
+
|
62
|
+
it "credit card field style variable is set" do
|
63
|
+
within_frame("braintree-hosted-field-number") do
|
64
|
+
expect(find("#credit-card-number").style("font-size")).to eq({ "font-size" => "30px" })
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it "sets the placeholder text correctly" do
|
69
|
+
within_frame("braintree-hosted-field-number") do
|
70
|
+
expect(find("#credit-card-number")['placeholder']).to eq("Enter Your Card Number")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "with valid credit card data", vcr: {
|
76
|
+
cassette_name: 'checkout/valid_credit_card',
|
77
|
+
match_requests_on: [:braintree_uri]
|
78
|
+
} do
|
79
|
+
include_context "with frontend checkout setup"
|
80
|
+
|
81
|
+
before do
|
82
|
+
within_frame("braintree-hosted-field-number") do
|
83
|
+
fill_in("credit-card-number", with: card_number)
|
84
|
+
end
|
85
|
+
within_frame("braintree-hosted-field-expirationDate") do
|
86
|
+
fill_in("expiration", with: card_expiration)
|
87
|
+
end
|
88
|
+
within_frame("braintree-hosted-field-cvv") do
|
89
|
+
fill_in("cvv", with: "123")
|
90
|
+
end
|
91
|
+
|
92
|
+
click_button("Save and Continue")
|
93
|
+
end
|
94
|
+
|
95
|
+
it "checks out successfully" do
|
96
|
+
within("#order_details") do
|
97
|
+
expect(page).to have_content("CONFIRM")
|
98
|
+
end
|
99
|
+
click_button("Place Order")
|
100
|
+
expect(page).to have_content("Your order has been processed successfully")
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'with 3D secure enabled' do
|
104
|
+
let(:three_d_secure_enabled) { true }
|
105
|
+
let(:card_number) { "4000000000000002" }
|
106
|
+
|
107
|
+
it 'checks out successfully' do
|
108
|
+
authenticate_3ds
|
109
|
+
|
110
|
+
within("#order_details") do
|
111
|
+
expect(page).to have_content("CONFIRM")
|
112
|
+
end
|
113
|
+
|
114
|
+
click_button("Place Order")
|
115
|
+
expect(page).to have_content("Your order has been processed successfully")
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'with 3ds authentication error' do
|
119
|
+
let(:card_number) { "4000000000000028" }
|
120
|
+
|
121
|
+
it 'shows a 3ds authentication error' do
|
122
|
+
authenticate_3ds
|
123
|
+
expect(page).to have_content(
|
124
|
+
"3D Secure authentication failed. Please try again using a different payment method."
|
125
|
+
)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "with invalid credit card data" do
|
132
|
+
include_context "with frontend checkout setup"
|
133
|
+
|
134
|
+
# Attempt to submit an empty form once
|
135
|
+
before do
|
136
|
+
click_button "Save and Continue"
|
137
|
+
end
|
138
|
+
|
139
|
+
it "displays an alert with a meaningful error message" do
|
140
|
+
expect(page).to have_text I18n.t("solidus_paypal_braintree.errors.empty_fields")
|
141
|
+
expect(page).to have_selector("input[type='submit']:enabled")
|
142
|
+
end
|
143
|
+
|
144
|
+
# Same error should be produced when submitting an empty form again
|
145
|
+
context "when user tries to resubmit an empty form", vcr: { cassette_name: "checkout/invalid_credit_card" } do
|
146
|
+
it "displays an alert with a meaningful error message" do
|
147
|
+
expect(page).to have_selector("input[type='submit']:enabled")
|
148
|
+
|
149
|
+
click_button "Save and Continue"
|
150
|
+
expect(page).to have_text I18n.t("solidus_paypal_braintree.errors.empty_fields")
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# User should be able to checkout after submit fails once
|
155
|
+
context "when user enters valid data", vcr: {
|
156
|
+
cassette_name: "checkout/resubmit_credit_card",
|
157
|
+
match_requests_on: [:braintree_uri]
|
158
|
+
} do
|
159
|
+
it "allows them to resubmit and complete the purchase" do
|
160
|
+
within_frame("braintree-hosted-field-number") do
|
161
|
+
fill_in("credit-card-number", with: "4111111111111111")
|
162
|
+
end
|
163
|
+
within_frame("braintree-hosted-field-expirationDate") do
|
164
|
+
fill_in("expiration", with: card_expiration)
|
165
|
+
end
|
166
|
+
within_frame("braintree-hosted-field-cvv") do
|
167
|
+
fill_in("cvv", with: "123")
|
168
|
+
end
|
169
|
+
click_button("Save and Continue")
|
170
|
+
within("#order_details") do
|
171
|
+
expect(page).to have_content("CONFIRM")
|
172
|
+
end
|
173
|
+
click_button("Place Order")
|
174
|
+
expect(page).to have_content("Your order has been processed successfully")
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def authenticate_3ds
|
180
|
+
within_frame("Cardinal-CCA-IFrame") do
|
181
|
+
within_frame("authWindow") do
|
182
|
+
fill_in("password", with: "1234")
|
183
|
+
click_button("Submit")
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|