diff --git a/README.md b/README.md index 1754fb30..d6e86b17 100644 --- a/README.md +++ b/README.md @@ -73,10 +73,20 @@ Using Stripe Payment Intents API -------------------------------- If you want to use the new SCA-ready Stripe Payment Intents API you need -to change the `v3_intents` preference from the code above to true and, -if you want to allow also Apple Pay and Google Pay payments, set the -`stripe_country` preference, which represents the two-letter country -code of your Stripe account: +to change the `v3_intents` preference from the code above to true. + +Also, if you want to allow Apple Pay and Google Pay payments using the +Stripe payment request button API, you only need to set the `stripe_country` +preference, which represents the two-letter country code of your Stripe +account. Conversely, if you need to disable the button you can simply remove +the `stripe_country` preference. + +Please refer to Stripe official +[documentation](https://stripe.com/docs/stripe-js/elements/payment-request-button) +for further instructions on how to make this work properly. + +The following configuration will use both Payment Intents and the +payment request button API on the store payment page: ```ruby @@ -120,8 +130,8 @@ payment method configured for Stripe via the local variable <%= render 'stripe_payment_request_button', cart_checkout_payment_method: Spree::PaymentMethod::StripeCreditCard.first %> ``` -Of course, rules stated in the paragraph above (remember to add the stripe country -config value, for example) apply also for this payment method. +Of course, the rules listed in the Payment Intents section (adding the stripe +country config value, for example) apply also for this feature. Migrating from solidus_gateway diff --git a/app/assets/javascripts/solidus_stripe/stripe-init.js b/app/assets/javascripts/solidus_stripe/stripe-init.js deleted file mode 100644 index d607cf85..00000000 --- a/app/assets/javascripts/solidus_stripe/stripe-init.js +++ /dev/null @@ -1 +0,0 @@ -//= require ./stripe-init/base diff --git a/app/assets/javascripts/solidus_stripe/stripe-init/base.js b/app/assets/javascripts/solidus_stripe/stripe-init/base.js deleted file mode 100644 index b64ec27f..00000000 --- a/app/assets/javascripts/solidus_stripe/stripe-init/base.js +++ /dev/null @@ -1,180 +0,0 @@ -window.SolidusStripe = window.SolidusStripe || {}; - -SolidusStripe.paymentMethod = { - config: $('[data-stripe-config').data('stripe-config'), - requestShipping: false -} - -var authToken = $('meta[name="csrf-token"]').attr('content'); - -var stripe = Stripe(SolidusStripe.paymentMethod.config.publishable_key) -var elements = stripe.elements({locale: 'en'}); - -var element = $('#payment_method_' + SolidusStripe.paymentMethod.config.id); -var form = element.parents('form'); -var errorElement = form.find('#card-errors'); -var submitButton = form.find('input[type="submit"]'); - -function stripeTokenHandler(token) { - var baseSelector = ``); - element.append(`${baseSelector}[last_digits]' value='${token.card.last4}'/>`); - element.append(`${baseSelector}[month]' value='${token.card.exp_month}'/>`); - element.append(`${baseSelector}[year]' value='${token.card.exp_year}'/>`); - form.find('input#cc_type').val(mapCC(token.card.brand || token.card.type)); -}; - -function initElements() { - var style = { - base: { - color: 'black', - fontFamily: '"Helvetica Neue", Helvetica, sans-serif', - fontSmoothing: 'antialiased', - fontSize: '14px', - '::placeholder': { - color: 'silver' - } - }, - invalid: { - color: 'red', - iconColor: 'red' - } - }; - - elements.create('cardExpiry', {style: style}).mount('#card_expiry'); - elements.create('cardCvc', {style: style}).mount('#card_cvc'); - - var cardNumber = elements.create('cardNumber', {style: style}); - cardNumber.mount('#card_number'); - - return cardNumber; -} - -function setUpPaymentRequest(config, onPrButtonMounted) { - if (typeof config !== 'undefined') { - var paymentRequest = stripe.paymentRequest({ - country: config.country, - currency: config.currency, - total: { - label: config.label, - amount: config.amount - }, - requestPayerName: true, - requestPayerEmail: true, - requestShipping: config.requestShipping, - shippingOptions: [ - ] - }); - - var prButton = elements.create('paymentRequestButton', { - paymentRequest: paymentRequest - }); - - paymentRequest.canMakePayment().then(function(result) { - var id = 'payment-request-button'; - - if (result) { - prButton.mount('#' + id); - } else { - document.getElementById(id).style.display = 'none'; - } - if (typeof onPrButtonMounted === 'function') { - onPrButtonMounted(id, result); - } - }); - - paymentRequest.on('paymentmethod', function(result) { - errorElement.text('').hide(); - handlePayment(result); - }); - - paymentRequest.on('shippingaddresschange', function(ev) { - fetch('/stripe/shipping_rates', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - authenticity_token: authToken, - shipping_address: ev.shippingAddress - }) - }).then(function(response) { - return response.json(); - }).then(function(result) { - if (result.error) { - showError(result.error); - return false; - } else { - ev.updateWith({ - status: 'success', - shippingOptions: result.shipping_rates - }); - } - }); - }); - - return paymentRequest; - } -}; - -function handleServerResponse(response, payment) { - if (response.error) { - showError(response.error); - completePaymentRequest(payment, 'fail'); - } else if (response.requires_action) { - stripe.handleCardAction( - response.stripe_payment_intent_client_secret - ).then(function(result) { - if (result.error) { - showError(result.error.message); - } else { - fetch('/stripe/confirm_intents', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - spree_payment_method_id: SolidusStripe.paymentMethod.config.id, - stripe_payment_intent_id: result.paymentIntent.id, - authenticity_token: authToken - }) - }).then(function(confirmResult) { - return confirmResult.json(); - }).then(handleServerResponse); - } - }); - } else { - completePaymentRequest(payment, 'success'); - submitPayment(payment); - } -} - -function completePaymentRequest(payment, state) { - if (payment && typeof payment.complete === 'function') { - payment.complete(state); - } -} - -function showError(error) { - errorElement.text(error).show(); - - if (submitButton.length) { - setTimeout(function() { - $.rails.enableElement(submitButton[0]); - submitButton.removeAttr('disabled').removeClass('disabled'); - }, 100); - } -}; - -function mapCC(ccType) { - if (ccType === 'MasterCard') { - return 'mastercard'; - } else if (ccType === 'Visa') { - return 'visa'; - } else if (ccType === 'American Express') { - return 'amex'; - } else if (ccType === 'Discover') { - return 'discover'; - } else if (ccType === 'Diners Club') { - return 'dinersclub'; - } else if (ccType === 'JCB') { - return 'jcb'; - } -}; diff --git a/app/assets/javascripts/spree/stripe-payments/stripe-cart-page-checkout.js b/app/assets/javascripts/spree/stripe-payments/stripe-cart-page-checkout.js new file mode 100644 index 00000000..3ff0c3d7 --- /dev/null +++ b/app/assets/javascripts/spree/stripe-payments/stripe-cart-page-checkout.js @@ -0,0 +1,88 @@ +SolidusStripe.CartPageCheckout = function() { + SolidusStripe.Payment.call(this); + + this.errorElement = $('#card-errors'); +}; + +SolidusStripe.CartPageCheckout.prototype = Object.create(SolidusStripe.Payment.prototype); +Object.defineProperty(SolidusStripe.CartPageCheckout.prototype, 'constructor', { + value: SolidusStripe.CartPageCheckout, + enumerable: false, + writable: true +}); + +SolidusStripe.CartPageCheckout.prototype.init = function() { + this.setUpPaymentRequest({requestShipping: true}); +}; + +SolidusStripe.CartPageCheckout.prototype.showError = function(error) { + this.errorElement.text(error).show(); +}; + +SolidusStripe.CartPageCheckout.prototype.submitPayment = function(payment) { + var showError = this.showError.bind(this); + + $.ajax({ + url: $('[data-submit-url]').data('submit-url'), + headers: { + 'X-Spree-Order-Token': $('[data-order-token]').data('order-token') + }, + type: 'PATCH', + contentType: 'application/json', + data: JSON.stringify(this.prTokenHandler(payment.paymentMethod)), + success: function() { + window.location = $('[data-complete-url]').data('complete-url'); + }, + error: function(xhr,status,error) { + showError(xhr.responseJSON.error); + } + }); +}; + +SolidusStripe.CartPageCheckout.prototype.onPrPayment = function(result) { + var handleServerResponse = this.handleServerResponse.bind(this); + + fetch('/stripe/update_order', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + shipping_address: result.shippingAddress, + shipping_option: result.shippingOption, + email: result.payerEmail, + name: result.payerName, + authenticity_token: this.authToken + }) + }).then(function(response) { + response.json().then(function(json) { + handleServerResponse(json, result); + }) + }); +}; + +SolidusStripe.CartPageCheckout.prototype.onPrButtonMounted = function(buttonId, success) { + var container = document.getElementById(buttonId).parentElement; + + if (success) { + container.style.display = ''; + } else { + container.style.display = 'none'; + } +}; + +SolidusStripe.CartPageCheckout.prototype.prTokenHandler = function(token) { + return { + order: { + payments_attributes: [ + { + payment_method_id: this.config.id, + source_attributes: { + gateway_payment_profile_id: token.id, + last_digits: token.card.last4, + month: token.card.exp_month, + year: token.card.exp_year + } + } + ] + } + } +}; diff --git a/app/assets/javascripts/spree/stripe-payments/stripe-elements.js b/app/assets/javascripts/spree/stripe-payments/stripe-elements.js new file mode 100644 index 00000000..2f5c0788 --- /dev/null +++ b/app/assets/javascripts/spree/stripe-payments/stripe-elements.js @@ -0,0 +1,108 @@ +SolidusStripe.Elements = function() { + SolidusStripe.Payment.call(this); + + this.form = this.element.parents('form'); + this.errorElement = this.form.find('#card-errors'); + this.submitButton = this.form.find('input[type="submit"]'); +}; + +SolidusStripe.Elements.prototype = Object.create(SolidusStripe.Payment.prototype); +Object.defineProperty(SolidusStripe.Elements.prototype, 'constructor', { + value: SolidusStripe.Elements, + enumerable: false, + writable: true +}); + +SolidusStripe.Elements.prototype.init = function() { + this.initElements(); +}; + +SolidusStripe.Elements.prototype.initElements = function() { + var buildElements = function(elements) { + var style = { + base: { + color: 'black', + fontFamily: '"Helvetica Neue", Helvetica, sans-serif', + fontSmoothing: 'antialiased', + fontSize: '14px', + '::placeholder': { + color: 'silver' + } + }, + invalid: { + color: 'red', + iconColor: 'red' + } + }; + + elements.create('cardExpiry', {style: style}).mount('#card_expiry'); + elements.create('cardCvc', {style: style}).mount('#card_cvc'); + + var cardNumber = elements.create('cardNumber', {style: style}); + cardNumber.mount('#card_number'); + + return cardNumber; + }; + + this.cardNumber = buildElements(this.elements); + + var cardChange = function(event) { + if (event.error) { + this.showError(event.error.message); + } else { + this.errorElement.hide().text(''); + } + }; + this.cardNumber.addEventListener('change', cardChange.bind(this)); + this.form.bind('submit', this.onFormSubmit.bind(this)); +}; + +SolidusStripe.Elements.prototype.showError = function(error) { + var message = error.message || error; + + this.errorElement.text(message).show(); + this.submitButton.removeAttr('disabled').removeClass('disabled'); +}; + +SolidusStripe.Elements.prototype.onFormSubmit = function(event) { + if (this.element.is(':visible')) { + event.preventDefault(); + + var onTokenCreate = function(result) { + if (result.error) { + this.showError(result.error.message); + } else { + this.elementsTokenHandler(result.token); + this.form[0].submit(); + } + }; + + this.stripe.createToken(this.cardNumber).then(onTokenCreate.bind(this)); + } +}; + +SolidusStripe.Elements.prototype.elementsTokenHandler = function(token) { + var mapCC = function(ccType) { + if (ccType === 'MasterCard') { + return 'mastercard'; + } else if (ccType === 'Visa') { + return 'visa'; + } else if (ccType === 'American Express') { + return 'amex'; + } else if (ccType === 'Discover') { + return 'discover'; + } else if (ccType === 'Diners Club') { + return 'dinersclub'; + } else if (ccType === 'JCB') { + return 'jcb'; + } + }; + + var baseSelector = ``); + this.element.append(`${baseSelector}[last_digits]' value='${token.card.last4}'/>`); + this.element.append(`${baseSelector}[month]' value='${token.card.exp_month}'/>`); + this.element.append(`${baseSelector}[year]' value='${token.card.exp_year}'/>`); + this.form.find('input#cc_type').val(mapCC(token.card.brand || token.card.type)); +}; diff --git a/app/assets/javascripts/spree/stripe-payments/stripe-payment-intents.js b/app/assets/javascripts/spree/stripe-payments/stripe-payment-intents.js new file mode 100644 index 00000000..3c430cf9 --- /dev/null +++ b/app/assets/javascripts/spree/stripe-payments/stripe-payment-intents.js @@ -0,0 +1,82 @@ +SolidusStripe.PaymentIntents = function() { + SolidusStripe.Elements.call(this); +}; + +SolidusStripe.PaymentIntents.prototype = Object.create(SolidusStripe.Elements.prototype); +Object.defineProperty(SolidusStripe.PaymentIntents.prototype, 'constructor', { + value: SolidusStripe.PaymentIntents, + enumerable: false, + writable: true +}); + +SolidusStripe.PaymentIntents.prototype.init = function() { + this.setUpPaymentRequest(); + this.initElements(); +}; + +SolidusStripe.PaymentIntents.prototype.onPrPayment = function(payment) { + if (payment.error) { + this.showError(payment.error.message); + } else { + var that = this; + + this.elementsTokenHandler(payment.paymentMethod); + fetch('/stripe/confirm_payment', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + spree_payment_method_id: this.config.id, + stripe_payment_method_id: payment.paymentMethod.id, + authenticity_token: this.authToken + }) + }).then(function(response) { + response.json().then(function(json) { + that.handleServerResponse(json, payment); + }) + }); + } +}; + +SolidusStripe.PaymentIntents.prototype.onFormSubmit = function(event) { + if (this.element.is(':visible')) { + event.preventDefault(); + + this.errorElement.text('').hide(); + + this.stripe.createPaymentMethod( + 'card', + this.cardNumber + ).then(this.onIntentsPayment.bind(this)); + } +}; + +SolidusStripe.PaymentIntents.prototype.submitPayment = function(_payment) { + this.form.unbind('submit').submit(); +}; + +SolidusStripe.PaymentIntents.prototype.onIntentsPayment = function(payment) { + if (payment.error) { + this.showError(payment.error.message); + } else { + var that = this; + + this.elementsTokenHandler(payment.paymentMethod); + fetch('/stripe/confirm_intents', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + spree_payment_method_id: this.config.id, + stripe_payment_method_id: payment.paymentMethod.id, + authenticity_token: this.authToken + }) + }).then(function(response) { + response.json().then(function(json) { + that.handleServerResponse(json, payment); + }) + }); + } +}; diff --git a/app/assets/javascripts/spree/stripe-payments/stripe-payment-request-button-shared.js b/app/assets/javascripts/spree/stripe-payments/stripe-payment-request-button-shared.js new file mode 100644 index 00000000..3c9772c3 --- /dev/null +++ b/app/assets/javascripts/spree/stripe-payments/stripe-payment-request-button-shared.js @@ -0,0 +1,122 @@ +// Shared code between Payment Intents and Payment Request Button on cart page + +(function() { + var PaymentRequestButtonShared; + + PaymentRequestButtonShared = { + authToken: $('meta[name="csrf-token"]').attr('content'), + + setUpPaymentRequest: function(opts) { + var opts = opts || {}; + var config = this.config.payment_request; + + if (config) { + config.requestShipping = opts.requestShipping || false; + + var paymentRequest = this.stripe.paymentRequest({ + country: config.country, + currency: config.currency, + total: { + label: config.label, + amount: config.amount + }, + requestPayerName: true, + requestPayerEmail: true, + requestShipping: config.requestShipping, + shippingOptions: [] + }); + + var prButton = this.elements.create('paymentRequestButton', { + paymentRequest: paymentRequest + }); + + var onButtonMount = function(result) { + var id = 'payment-request-button'; + + if (result) { + prButton.mount('#' + id); + } else { + document.getElementById(id).style.display = 'none'; + } + if (typeof this.onPrButtonMounted === 'function') { + this.onPrButtonMounted(id, result); + } + } + paymentRequest.canMakePayment().then(onButtonMount.bind(this)); + + var onPrPaymentMethod = function(result) { + this.errorElement.text('').hide(); + this.onPrPayment(result); + }; + paymentRequest.on('paymentmethod', onPrPaymentMethod.bind(this)); + + onShippingAddressChange = function(ev) { + var showError = this.showError.bind(this); + + fetch('/stripe/shipping_rates', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + authenticity_token: this.authToken, + shipping_address: ev.shippingAddress + }) + }).then(function(response) { + return response.json(); + }).then(function(result) { + if (result.error) { + showError(result.error); + return false; + } else { + ev.updateWith({ + status: 'success', + shippingOptions: result.shipping_rates + }); + } + }); + }; + paymentRequest.on('shippingaddresschange', onShippingAddressChange.bind(this)); + } + }, + + handleServerResponse: function(response, payment) { + if (response.error) { + this.showError(response.error); + this.completePaymentRequest(payment, 'fail'); + } else if (response.requires_action) { + this.stripe.handleCardAction( + response.stripe_payment_intent_client_secret + ).then(this.onIntentsClientSecret.bind(this)); + } else { + this.completePaymentRequest(payment, 'success'); + this.submitPayment(payment); + } + }, + + onIntentsClientSecret: function(result) { + if (result.error) { + this.showError(result.error); + } else { + fetch('/stripe/confirm_intents', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + spree_payment_method_id: this.config.id, + stripe_payment_intent_id: result.paymentIntent.id, + authenticity_token: this.authToken + }) + }).then(function(confirmResult) { + return confirmResult.json(); + }).then(this.handleServerResponse.bind(this)); + } + }, + + completePaymentRequest: function(payment, state) { + if (payment && typeof payment.complete === 'function') { + payment.complete(state); + } + } + }; + + Object.assign(SolidusStripe.PaymentIntents.prototype, PaymentRequestButtonShared); + Object.assign(SolidusStripe.CartPageCheckout.prototype, PaymentRequestButtonShared); +})() diff --git a/app/assets/javascripts/spree/stripe-payments/stripe-payment.js b/app/assets/javascripts/spree/stripe-payments/stripe-payment.js new file mode 100644 index 00000000..784a2737 --- /dev/null +++ b/app/assets/javascripts/spree/stripe-payments/stripe-payment.js @@ -0,0 +1,10 @@ +window.SolidusStripe = window.SolidusStripe || {}; + +SolidusStripe.Payment = function() { + this.config = $('[data-stripe-config]').data('stripe-config'); + this.element = $('#payment_method_' + this.config.id); + this.authToken = $('meta[name="csrf-token"]').attr('content'); + + this.stripe = Stripe(this.config.publishable_key); + this.elements = this.stripe.elements({locale: 'en'}); +}; diff --git a/app/assets/javascripts/spree/stripe-v3-payments.js b/app/assets/javascripts/spree/stripe-v3-payments.js new file mode 100644 index 00000000..b405d113 --- /dev/null +++ b/app/assets/javascripts/spree/stripe-v3-payments.js @@ -0,0 +1,5 @@ +//= require ./stripe-payments/stripe-payment +//= require ./stripe-payments/stripe-elements +//= require ./stripe-payments/stripe-payment-intents +//= require ./stripe-payments/stripe-cart-page-checkout +//= require ./stripe-payments/stripe-payment-request-button-shared diff --git a/lib/solidus_stripe/engine.rb b/lib/solidus_stripe/engine.rb index e797220e..7070ea8c 100644 --- a/lib/solidus_stripe/engine.rb +++ b/lib/solidus_stripe/engine.rb @@ -21,7 +21,7 @@ class Engine < Rails::Engine if SolidusSupport.frontend_available? paths["app/views"] << "lib/views/frontend" - config.assets.precompile += ['solidus_stripe/stripe-init.js'] + config.assets.precompile += ['spree/stripe-v3-payments.js'] end if SolidusSupport.api_available? diff --git a/lib/views/frontend/spree/checkout/payment/v3/_elements_js.html.erb b/lib/views/frontend/spree/checkout/payment/v3/_elements_js.html.erb deleted file mode 100644 index ca45709a..00000000 --- a/lib/views/frontend/spree/checkout/payment/v3/_elements_js.html.erb +++ /dev/null @@ -1,28 +0,0 @@ - diff --git a/lib/views/frontend/spree/checkout/payment/v3/_intents.html.erb b/lib/views/frontend/spree/checkout/payment/v3/_intents.html.erb index 0e2fbaed..b102cb87 100644 --- a/lib/views/frontend/spree/checkout/payment/v3/_intents.html.erb +++ b/lib/views/frontend/spree/checkout/payment/v3/_intents.html.erb @@ -1,5 +1,9 @@ <%= render 'spree/checkout/payment/v3/form_elements', payment_method: payment_method %> -<%= javascript_include_tag "solidus_stripe/stripe-init.js" %> +<%= javascript_include_tag 'spree/stripe-v3-payments' %> -<%= render "spree/checkout/payment/v3/intents_js" %> + diff --git a/lib/views/frontend/spree/checkout/payment/v3/_intents_js.html.erb b/lib/views/frontend/spree/checkout/payment/v3/_intents_js.html.erb deleted file mode 100644 index 6d1219f3..00000000 --- a/lib/views/frontend/spree/checkout/payment/v3/_intents_js.html.erb +++ /dev/null @@ -1,48 +0,0 @@ - diff --git a/lib/views/frontend/spree/checkout/payment/v3/_stripe.html.erb b/lib/views/frontend/spree/checkout/payment/v3/_stripe.html.erb index 1a4dc7d7..21c15fdf 100644 --- a/lib/views/frontend/spree/checkout/payment/v3/_stripe.html.erb +++ b/lib/views/frontend/spree/checkout/payment/v3/_stripe.html.erb @@ -1,5 +1,9 @@ <%= render 'spree/checkout/payment/v3/form_elements', payment_method: payment_method %> -<%= javascript_include_tag "solidus_stripe/stripe-init.js" %> +<%= javascript_include_tag 'spree/stripe-v3-payments' %> -<%= render "spree/checkout/payment/v3/elements_js" %> + diff --git a/lib/views/frontend/spree/orders/_stripe_payment_request_button.html.erb b/lib/views/frontend/spree/orders/_stripe_payment_request_button.html.erb index 40072532..dc77df45 100644 --- a/lib/views/frontend/spree/orders/_stripe_payment_request_button.html.erb +++ b/lib/views/frontend/spree/orders/_stripe_payment_request_button.html.erb @@ -13,80 +13,11 @@ - <%= javascript_include_tag "solidus_stripe/stripe-init" %> + <%= javascript_include_tag 'spree/stripe-v3-payments' %> <% end %> diff --git a/spec/features/stripe_checkout_spec.rb b/spec/features/stripe_checkout_spec.rb index fa1eb29a..e96b2522 100644 --- a/spec/features/stripe_checkout_spec.rb +++ b/spec/features/stripe_checkout_spec.rb @@ -41,8 +41,7 @@ expect(page).to have_current_path("/checkout/address") within("#billing") do - fill_in "First Name", with: "Han" - fill_in "Last Name", with: "Solo" + fill_in_name fill_in "Street Address", with: "YT-1300" fill_in "City", with: "Mos Eisley" select "United States of America", from: "Country" @@ -100,8 +99,7 @@ expect(page).to have_current_path("/checkout/address") within("#billing") do - fill_in "First Name", with: "Han" - fill_in "Last Name", with: "Solo" + fill_in_name fill_in "Street Address", with: "YT-1300" fill_in "City", with: "Mos Eisley" select "United States of America", from: "Country" @@ -264,8 +262,7 @@ expect(page).to have_current_path("/checkout/address") within("#billing") do - fill_in "First Name", with: "Han" - fill_in "Last Name", with: "Solo" + fill_in_name fill_in "Street Address", with: "YT-1300" fill_in "City", with: "Mos Eisley" select "United States of America", from: "Country" @@ -400,8 +397,7 @@ expect(page).to have_current_path("/checkout/address") within("#billing") do - fill_in "First Name", with: "Han" - fill_in "Last Name", with: "Solo" + fill_in_name fill_in "Street Address", with: "YT-1300" fill_in "City", with: "Mos Eisley" select "United States of America", from: "Country" diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index cc1ed71f..f8f16a12 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -19,4 +19,5 @@ config.infer_spec_type_from_file_location! FactoryBot.find_definitions config.use_transactional_fixtures = false + config.include SolidusAddressNameHelper, type: :feature end diff --git a/spec/support/solidus_address_helper.rb b/spec/support/solidus_address_helper.rb new file mode 100644 index 00000000..2e640743 --- /dev/null +++ b/spec/support/solidus_address_helper.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +# Since https://github.com/solidusio/solidus/pull/3524 was merged, +# we need to verify if we're using the single "Name" field or the +# previous first/last name combination. +module SolidusAddressNameHelper + def fill_in_name + if Spree::Config.preferences[:use_combined_first_and_last_name_in_address] + fill_in "Name", with: "Han Solo" + else + fill_in "First Name", with: "Han" + fill_in "Last Name", with: "Solo" + end + end +end