mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
And also remove a couple of now unused `let`'s that were already using this terminology. Co-authored-by: David Cook <david@openfoodnetwork.org.au>
237 lines
9.1 KiB
Ruby
237 lines
9.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'spec_helper'
|
|
require 'stripe/payment_intent_validator'
|
|
|
|
RSpec.describe Stripe::PaymentIntentValidator do
|
|
# These are test payment method IDs, recognised by Stripe for testing purposes.
|
|
# See Cards By Brand > PaymentMethods here: https://docs.stripe.com/testing?testing-method=payment-methods#cards
|
|
# We do not send raw card numbers to the API.
|
|
|
|
self::VALID_NON_3DS_TEST_PAYMENT_METHODS = {
|
|
"pm_card_visa" => "Visa",
|
|
"pm_card_visa_debit" => "Visa (debit)",
|
|
"pm_card_mastercard" => "Mastercard",
|
|
"pm_card_mastercard_debit" => "Mastercard (debit)",
|
|
"pm_card_mastercard_prepaid" => "Mastercard (prepaid)",
|
|
"pm_card_amex" => "American Express",
|
|
"pm_card_discover" => "Discover",
|
|
"pm_card_diners" => "Diners Club",
|
|
"pm_card_jcb" => "JCB",
|
|
"pm_card_unionpay" => "UnionPay"
|
|
}.freeze
|
|
|
|
self::VALID_3DS_TEST_PAYMENT_METHODS = {
|
|
"pm_card_authenticationRequiredOnSetup" => "Authenticate unless set up",
|
|
"pm_card_authenticationRequired" => "Always authenticate",
|
|
"pm_card_authenticationRequiredSetupForOffSession" => "Already set up",
|
|
"pm_card_authenticationRequiredChargeDeclinedInsufficientFunds" => "Insufficient funds"
|
|
}.freeze
|
|
|
|
self::INVALID_TEST_PAYMENT_METHODS = {
|
|
"pm_card_visa_chargeDeclined" => {
|
|
type: "Generic decline",
|
|
message: "Your card was declined."
|
|
},
|
|
"pm_card_visa_chargeDeclinedInsufficientFunds" => {
|
|
type: "Insufficient funds decline",
|
|
message: "Your card has insufficient funds."
|
|
},
|
|
"pm_card_visa_chargeDeclinedLostCard" => {
|
|
type: "Lost card decline",
|
|
message: "Your card was declined."
|
|
},
|
|
"pm_card_visa_chargeDeclinedStolenCard" => {
|
|
type: "Stolen card decline",
|
|
message: "Your card was declined."
|
|
},
|
|
"pm_card_chargeDeclinedExpiredCard" => {
|
|
type: "Expired card decline",
|
|
message: "Your card has expired."
|
|
},
|
|
"pm_card_chargeDeclinedIncorrectCvc" => {
|
|
type: "Incorrect CVC decline",
|
|
message: "Your card's security code is incorrect."
|
|
},
|
|
"pm_card_chargeDeclinedProcessingError" => {
|
|
type: "Processing error decline",
|
|
message: "An error occurred while processing your card. Try again in a little bit."
|
|
},
|
|
"pm_card_visa_chargeDeclinedVelocityLimitExceeded" => {
|
|
type: "Exceeding velocity limit decline",
|
|
message: %(Your card was declined for making repeated attempts too frequently
|
|
or exceeding its amount limit.).squish
|
|
}
|
|
}.freeze
|
|
|
|
let(:payment_method) {
|
|
create(:stripe_sca_payment_method, distributor_ids: [create(:distributor_enterprise).id],
|
|
preferred_enterprise_id: create(:enterprise).id)
|
|
}
|
|
|
|
let(:year_valid) { Time.zone.now.year.next }
|
|
|
|
describe "#call", :vcr, :stripe_version do
|
|
let!(:user) { create(:user, email: "apple.customer@example.com") }
|
|
let(:credit_card) { create(:credit_card, user:) }
|
|
let(:payment) {
|
|
create(:payment, amount: payment_intent.amount, payment_method:,
|
|
response_code: payment_intent.id, source: credit_card)
|
|
}
|
|
let(:validator) { Stripe::PaymentIntentValidator.new(payment) }
|
|
|
|
describe "as a guest" do
|
|
context "when payment intent is valid" do
|
|
self::VALID_NON_3DS_TEST_PAYMENT_METHODS.each do |payment_method_id, card_type|
|
|
context "from #{card_type}" do
|
|
let!(:payment_intent) do
|
|
Stripe::PaymentIntent.create({
|
|
amount: 100,
|
|
currency: 'eur',
|
|
payment_method: payment_method_id,
|
|
payment_method_types: ['card'],
|
|
capture_method: 'manual',
|
|
})
|
|
end
|
|
|
|
before do
|
|
Stripe::PaymentIntent.confirm(payment_intent.id)
|
|
end
|
|
it "returns payment intent id" do
|
|
result = validator.call
|
|
expect(result.id).to eq(payment_intent.id)
|
|
end
|
|
|
|
it "captures the payment" do
|
|
expect(Stripe::PaymentIntent.retrieve(
|
|
payment_intent.id
|
|
).status).to eq("requires_capture")
|
|
|
|
Stripe::PaymentIntent.capture(payment_intent.id)
|
|
|
|
expect(Stripe::PaymentIntent.retrieve(
|
|
payment_intent.id
|
|
).status).to eq("succeeded")
|
|
end
|
|
end
|
|
end
|
|
|
|
self::VALID_3DS_TEST_PAYMENT_METHODS.each_key do |payment_method_id|
|
|
xcontext "from 3D card #{payment_method_id}" do
|
|
pending("updating spec to handle 3D2S cards")
|
|
|
|
it "is correctly handled"
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when payment intent is invalid" do
|
|
self::INVALID_TEST_PAYMENT_METHODS.each do |payment_method_id, error|
|
|
context "from #{error[:type]}" do
|
|
let(:payment_intent) do
|
|
Stripe::PaymentIntent.create({
|
|
amount: 100,
|
|
currency: 'eur',
|
|
payment_method: payment_method_id,
|
|
payment_method_types: ['card'],
|
|
capture_method: 'manual',
|
|
})
|
|
end
|
|
it "raises Stripe error with payment intent last_payment_error as message" do
|
|
expect {
|
|
Stripe::PaymentIntent.confirm(payment_intent.id)
|
|
}.to raise_error Stripe::StripeError, error[:message]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "as a Stripe customer" do
|
|
context "when payment intent is valid" do
|
|
let(:customer_id) { customer.id }
|
|
let(:customer) do
|
|
Stripe::Customer.create({
|
|
name: 'Apple Customer',
|
|
email: 'applecustomer@example.com',
|
|
})
|
|
end
|
|
|
|
self::VALID_NON_3DS_TEST_PAYMENT_METHODS.each do |payment_method_id, card_type|
|
|
context "from #{card_type}" do
|
|
let!(:payment_intent) do
|
|
Stripe::PaymentIntent.create({
|
|
amount: 100,
|
|
currency: 'eur',
|
|
payment_method: payment_method_id,
|
|
payment_method_types: ['card'],
|
|
capture_method: 'manual',
|
|
customer: customer.id,
|
|
setup_future_usage: "off_session"
|
|
})
|
|
end
|
|
|
|
before do
|
|
Stripe::PaymentIntent.confirm(payment_intent.id)
|
|
end
|
|
it "returns payment intent id" do
|
|
result = validator.call
|
|
expect(result.id).to eq(payment_intent.id)
|
|
end
|
|
|
|
it "captures the payment" do
|
|
expect(Stripe::PaymentIntent.retrieve(
|
|
payment_intent.id
|
|
).status).to eq("requires_capture")
|
|
|
|
Stripe::PaymentIntent.capture(payment_intent.id)
|
|
|
|
expect(Stripe::PaymentIntent.retrieve(
|
|
payment_intent.id
|
|
).status).to eq("succeeded")
|
|
end
|
|
end
|
|
end
|
|
|
|
self::VALID_3DS_TEST_PAYMENT_METHODS.each_key do |payment_method_id|
|
|
xcontext "from 3D card #{payment_method_id}" do
|
|
pending("updating spec to handle 3D2S cards")
|
|
|
|
it "is correctly handled"
|
|
end
|
|
end
|
|
end
|
|
context "when payment intent is invalid" do
|
|
let(:customer_id) { customer.id }
|
|
let(:customer) do
|
|
Stripe::Customer.create({
|
|
name: 'Apple Customer',
|
|
email: 'applecustomer@example.com',
|
|
})
|
|
end
|
|
|
|
self::INVALID_TEST_PAYMENT_METHODS.each do |payment_method_id, error|
|
|
context "from #{error[:type]}" do
|
|
let(:payment_intent) do
|
|
Stripe::PaymentIntent.create({
|
|
amount: 100,
|
|
currency: 'eur',
|
|
payment_method: payment_method_id,
|
|
payment_method_types: ['card'],
|
|
capture_method: 'manual',
|
|
customer: customer.id,
|
|
setup_future_usage: "off_session"
|
|
})
|
|
end
|
|
it "raises Stripe error with payment intent last_payment_error as message" do
|
|
expect {
|
|
Stripe::PaymentIntent.confirm(payment_intent.id)
|
|
}.to raise_error Stripe::StripeError, error[:message]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|