solidus_paypal_braintree 1.1.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +3 -0
- data/.github/stale.yml +1 -17
- data/.github_changelog_generator +2 -0
- data/.gitignore +4 -3
- data/.rubocop.yml +1 -2
- data/CHANGELOG.md +32 -0
- data/Gemfile +18 -20
- data/README.md +41 -17
- data/app/assets/stylesheets/spree/backend/solidus_paypal_braintree.css +4 -0
- data/app/models/solidus_paypal_braintree/configuration.rb +1 -3
- data/app/models/solidus_paypal_braintree/gateway.rb +1 -0
- data/app/models/solidus_paypal_braintree/source.rb +4 -2
- data/app/models/solidus_paypal_braintree/transaction_address.rb +1 -0
- data/bin/rails +4 -12
- data/bin/rails-engine +13 -0
- data/bin/rails-sandbox +16 -0
- data/bin/rake +7 -0
- data/bin/sandbox +103 -0
- data/bin/setup +1 -1
- data/lib/generators/solidus_paypal_braintree/install/install_generator.rb +9 -4
- data/lib/generators/solidus_paypal_braintree/install/templates/initializer.rb +6 -0
- data/lib/solidus_paypal_braintree/engine.rb +6 -5
- data/lib/solidus_paypal_braintree/extension_configuration.rb +23 -0
- data/lib/solidus_paypal_braintree/request_protection.rb +2 -2
- data/lib/solidus_paypal_braintree/{factories.rb → testing_support/factories.rb} +0 -0
- data/lib/solidus_paypal_braintree/version.rb +1 -1
- data/lib/solidus_paypal_braintree.rb +5 -3
- data/solidus_paypal_braintree.gemspec +39 -39
- 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 +191 -0
- data/spec/features/frontend/paypal_checkout_spec.rb +166 -0
- data/spec/features/frontend/venmo_checkout_spec.rb +194 -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 +171 -0
- data/spec/fixtures/cassettes/checkout/valid_venmo_transaction.yml +599 -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/authorize.yml +86 -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/customer.yml +79 -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/bin.yml +295 -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/capture.yml +224 -0
- data/spec/fixtures/cassettes/transaction/import/valid.yml +71 -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/helpers/solidus_paypal_braintree/braintree_checkout_helper_spec.rb +70 -0
- data/spec/models/solidus_paypal_braintree/address_spec.rb +71 -0
- data/spec/models/solidus_paypal_braintree/avs_result_spec.rb +317 -0
- data/spec/models/solidus_paypal_braintree/gateway_spec.rb +742 -0
- data/spec/models/solidus_paypal_braintree/response_spec.rb +280 -0
- data/spec/models/solidus_paypal_braintree/source_spec.rb +539 -0
- data/spec/models/solidus_paypal_braintree/transaction_address_spec.rb +235 -0
- data/spec/models/solidus_paypal_braintree/transaction_import_spec.rb +302 -0
- data/spec/models/solidus_paypal_braintree/transaction_spec.rb +86 -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 +32 -0
- data/spec/support/capybara.rb +7 -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 +146 -15
@@ -1,11 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'solidus_core'
|
4
|
-
require '
|
5
|
-
|
4
|
+
require 'solidus_support'
|
5
|
+
|
6
6
|
require 'solidus_paypal_braintree/country_mapper'
|
7
7
|
require 'solidus_paypal_braintree/request_protection'
|
8
|
-
require '
|
8
|
+
require 'solidus_paypal_braintree/extension_configuration'
|
9
|
+
require 'solidus_paypal_braintree/version'
|
10
|
+
require 'solidus_paypal_braintree/engine'
|
9
11
|
|
10
12
|
module SolidusPaypalBraintree
|
11
13
|
def self.table_name_prefix
|
@@ -1,42 +1,42 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
3
|
+
require_relative 'lib/solidus_paypal_braintree/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'solidus_paypal_braintree'
|
7
|
+
spec.version = SolidusPaypalBraintree::VERSION
|
8
|
+
spec.authors = ['Stembolt']
|
9
|
+
spec.email = 'braintree+gemfile@stembolt.com'
|
10
|
+
|
11
|
+
spec.summary = 'Officially supported Paypal/Braintree extension'
|
12
|
+
spec.description = 'Uses the javascript API for seamless braintree payments'
|
13
|
+
spec.homepage = 'https://github.com/solidusio/solidus_paypal_braintree'
|
14
|
+
spec.license = 'BSD-3-Clause'
|
15
|
+
|
16
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
17
|
+
spec.metadata['source_code_uri'] = 'https://github.com/solidusio/solidus_paypal_braintree'
|
18
|
+
spec.metadata['changelog_uri'] = 'https://github.com/solidusio/solidus_paypal_braintree/blob/master/CHANGELOG.md'
|
19
|
+
|
20
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.5', '< 4')
|
21
|
+
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
|
+
files = Dir.chdir(__dir__) { `git ls-files -z`.split("\x0") }
|
25
|
+
|
26
|
+
spec.files = files.grep_v(%r{^(test|spec|features)/})
|
27
|
+
spec.test_files = files.grep(%r{^(test|spec|features)/})
|
28
|
+
spec.bindir = "exe"
|
29
|
+
spec.executables = files.grep(%r{^exe/}) { |f| File.basename(f) }
|
30
|
+
spec.require_paths = ["lib"]
|
31
|
+
|
32
|
+
spec.add_dependency 'activemerchant', '~> 1.48'
|
33
|
+
spec.add_dependency 'braintree', '~> 3.4'
|
34
|
+
spec.add_dependency 'solidus_api', ['>= 2.4.0', '< 4']
|
35
|
+
spec.add_dependency 'solidus_core', ['>= 2.4.0', '< 4']
|
36
|
+
spec.add_dependency 'solidus_support', ['>= 0.8.1', '< 1']
|
37
|
+
|
38
|
+
spec.add_development_dependency 'rails-controller-testing'
|
39
|
+
spec.add_development_dependency 'solidus_dev_support', '~> 2.5'
|
40
|
+
spec.add_development_dependency 'vcr'
|
41
|
+
spec.add_development_dependency 'webmock'
|
42
42
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/order_ready_for_payment'
|
3
|
+
|
4
|
+
RSpec.describe SolidusPaypalBraintree::CheckoutsController, type: :controller do
|
5
|
+
routes { SolidusPaypalBraintree::Engine.routes }
|
6
|
+
|
7
|
+
include_context 'when order is ready for payment'
|
8
|
+
|
9
|
+
describe 'PATCH update' do
|
10
|
+
subject(:patch_update) { patch :update, params: params }
|
11
|
+
|
12
|
+
let(:params) do
|
13
|
+
{
|
14
|
+
"state" => "payment",
|
15
|
+
"order" => {
|
16
|
+
"payments_attributes" => [
|
17
|
+
{
|
18
|
+
"payment_method_id" => payment_method.id,
|
19
|
+
"source_attributes" => {
|
20
|
+
"nonce" => "fake-paypal-billing-agreement-nonce",
|
21
|
+
"payment_type" => SolidusPaypalBraintree::Source::PAYPAL
|
22
|
+
}
|
23
|
+
}
|
24
|
+
],
|
25
|
+
"use_billing" => "1",
|
26
|
+
"use_postmates_shipping" => "0"
|
27
|
+
},
|
28
|
+
"reuse_credit" => "1",
|
29
|
+
"order_bill_address" => "",
|
30
|
+
"reuse_bill_address" => "1"
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
let!(:payment_method) do
|
35
|
+
create_gateway
|
36
|
+
end
|
37
|
+
|
38
|
+
before do
|
39
|
+
allow(controller).to receive(:try_spree_current_user) { user }
|
40
|
+
allow(controller).to receive(:spree_current_user) { user }
|
41
|
+
allow(controller).to receive(:current_order) { order }
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when a payment is created successfully", vcr: {
|
45
|
+
cassette_name: 'checkout/update',
|
46
|
+
match_requests_on: [:braintree_uri]
|
47
|
+
} do
|
48
|
+
it 'creates a payment' do
|
49
|
+
expect { patch_update }.
|
50
|
+
to change { order.payments.count }.
|
51
|
+
from(0).
|
52
|
+
to(1)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'creates a payment source' do
|
56
|
+
expect { patch_update }.
|
57
|
+
to change(SolidusPaypalBraintree::Source, :count).
|
58
|
+
from(0).
|
59
|
+
to(1)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'assigns @order' do
|
63
|
+
patch_update
|
64
|
+
expect(assigns(:order)).to eq order
|
65
|
+
end
|
66
|
+
|
67
|
+
it "is successful" do
|
68
|
+
expect(patch_update).to be_successful
|
69
|
+
end
|
70
|
+
|
71
|
+
it "renders 'ok'" do
|
72
|
+
expect(patch_update.body).to eql("ok")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "when a payment is not created successfully" do
|
77
|
+
before do
|
78
|
+
allow_any_instance_of(::Spree::Payment).to receive(:save).and_return(false)
|
79
|
+
end
|
80
|
+
|
81
|
+
# No idea why this is the case, but I'm just adding the tests here
|
82
|
+
it "is successful" do
|
83
|
+
expect(patch_update).to be_successful
|
84
|
+
end
|
85
|
+
|
86
|
+
it "renders 'not-ok'" do
|
87
|
+
expect(patch_update.body).to eq('not-ok')
|
88
|
+
end
|
89
|
+
|
90
|
+
it "does not change the number of payments in the system" do
|
91
|
+
expect{ patch_update }.not_to(change(::Spree::Payment, :count))
|
92
|
+
end
|
93
|
+
|
94
|
+
it "does not change the number of sources in the system" do
|
95
|
+
expect{ patch_update }.not_to(change(SolidusPaypalBraintree::Source, :count))
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SolidusPaypalBraintree::ClientTokensController do
|
4
|
+
routes { SolidusPaypalBraintree::Engine.routes }
|
5
|
+
|
6
|
+
cassette_options = { cassette_name: "braintree/token" }
|
7
|
+
describe "POST create", vcr: cassette_options do
|
8
|
+
let!(:gateway) { create_gateway }
|
9
|
+
let(:user) { create(:user) }
|
10
|
+
let(:json) { JSON.parse(response.body) }
|
11
|
+
|
12
|
+
before { user.generate_spree_api_key! }
|
13
|
+
|
14
|
+
context 'without a payment method id' do
|
15
|
+
subject(:response) do
|
16
|
+
post :create, params: { token: user.spree_api_key }
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns a client token", aggregate_failures: true do
|
20
|
+
expect(response).to have_http_status(:success)
|
21
|
+
expect(response.content_type).to include 'application/json'
|
22
|
+
expect(json["client_token"]).to be_present
|
23
|
+
expect(json["client_token"]).to be_a String
|
24
|
+
expect(json["payment_method_id"]).to eq gateway.id
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when there's two gateway's for different stores" do
|
28
|
+
let!(:store1) { create(:store, code: 'store_1') }
|
29
|
+
let!(:store2) { create(:store, code: 'store_2') }
|
30
|
+
let!(:gateway_for_store1) { create_gateway.tap{ |gw| store1.payment_methods << gw } }
|
31
|
+
let!(:gateway_for_store2) { create_gateway.tap{ |gw| store2.payment_methods << gw } }
|
32
|
+
|
33
|
+
it "returns the correct gateway for store1" do
|
34
|
+
allow_any_instance_of(described_class).to receive(:current_store).and_return store1
|
35
|
+
expect(json["payment_method_id"]).to eq gateway_for_store1.id
|
36
|
+
end
|
37
|
+
|
38
|
+
it "returns the correct gateway for store2" do
|
39
|
+
allow_any_instance_of(described_class).to receive(:current_store).and_return store2
|
40
|
+
expect(json["payment_method_id"]).to eq gateway_for_store2.id
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with a payment method id' do
|
46
|
+
subject(:response) do
|
47
|
+
post :create, params: { token: user.spree_api_key, payment_method_id: gateway.id }
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'uses the selected gateway' do
|
51
|
+
expect(json["payment_method_id"]).to eq gateway.id
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -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.address1).to eq "123 Fake Street"
|
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).to have_http_status :unprocessable_entity
|
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
|