require 'solidus_braintree_helper' RSpec.shared_context "with frontend checkout setup" do let(:braintree) { new_gateway(active: true) } let!(:gateway) { create :payment_method } let(:three_d_secure_enabled) { false } let(:venmo_enabled) { false } let(:card_number) { "4111111111111111" } let(:card_expiration) { "01/#{Time.now.utc.year + 3}" } before do braintree.save! create(:store, payment_methods: [gateway, braintree]).tap do |store| store.braintree_configuration.update!( credit_card: true, three_d_secure: three_d_secure_enabled, venmo: venmo_enabled ) braintree.update( preferred_credit_card_fields_style: { input: { 'font-size': '30px' } }, preferred_placeholder_text: { number: "Enter Your Card Number" } ) end order = if Spree.solidus_gem_version >= Gem::Version.new('2.6.0') SolidusBraintree::OrderWalkthrough.up_to(:delivery) else OrderWalkthrough.up_to(:delivery) end user = create(:user) order.user = user order.number = "R9999999" order.recalculate allow_any_instance_of(CheckoutsController).to receive_messages(current_order: order) allow_any_instance_of(CheckoutsController).to receive_messages(try_spree_current_user: user) allow_any_instance_of(CheckoutsController).to receive_messages(spree_current_user: user) allow_any_instance_of(Spree::Payment).to receive(:number).and_return("123ABC") allow_any_instance_of(SolidusBraintree::Source).to receive(:nonce).and_return("fake-valid-nonce") visit checkout_state_path(:delivery) click_button "Save and Continue" choose("Braintree") end around do |example| Capybara.using_wait_time(20) { example.run } end end RSpec.describe 'entering credit card details', type: :feature, js: true do context 'when page loads' do include_context "with frontend checkout setup" it "selectors display correctly" do expect(page).to have_selector("fieldset[name='payment-method-#{braintree.id}']", visible: :visible) expect(page).to have_selector("iframe#braintree-hosted-field-number") expect(page).to have_selector("iframe[type='number']") end it "credit card field style variable is set" do within_frame("braintree-hosted-field-number") do expect(find("#credit-card-number").style("font-size")).to eq({ "font-size" => "30px" }) end end it "sets the placeholder text correctly" do within_frame("braintree-hosted-field-number") do expect(find("#credit-card-number")['placeholder']).to eq("Enter Your Card Number") end end end context "with valid credit card data", vcr: { cassette_name: 'checkout/valid_credit_card', match_requests_on: [:braintree_uri] } do include_context "with frontend checkout setup" # To ensure Venmo inputs do not conflict with checkout let(:venmo_enabled) { true } before do within_frame("braintree-hosted-field-number") do fill_in("credit-card-number", with: card_number) end within_frame("braintree-hosted-field-expirationDate") do fill_in("expiration", with: card_expiration) end within_frame("braintree-hosted-field-cvv") do fill_in("cvv", with: "123") end click_button("Save and Continue") end it "checks out successfully" do within(".confirm-step") do expect(page).to have_content("CONFIRM") end check('accept_terms_and_conditions') click_button("Place Order") expect(page).to have_content("Your order has been processed successfully") end context 'with 3D secure enabled' do let(:three_d_secure_enabled) { true } it 'checks out successfully' do authenticate_3ds within(".confirm-step") do expect(page).to have_content("CONFIRM") end check('accept_terms_and_conditions') click_button("Place Order") expect(page).to have_content("Your order has been processed successfully") end context 'with 3ds authentication error' do let(:card_number) { "4000000000001125" } it 'shows a 3ds authentication error' do authenticate_3ds expect(page).to have_content( "3D Secure authentication failed. Please try again using a different payment method." ) end end end end context "with invalid credit card data" do include_context "with frontend checkout setup" # Attempt to submit an empty form once before do click_button "Save and Continue" end it "displays an alert with a meaningful error message" do expect(page).to have_text I18n.t("solidus_braintree.errors.empty_fields") expect(page).to have_selector("[type='submit']:enabled") end # Same error should be produced when submitting an empty form again context "when user tries to resubmit an empty form", vcr: { cassette_name: "checkout/invalid_credit_card" } do it "displays an alert with a meaningful error message" do expect(page).to have_selector("[type='submit']:enabled") click_button "Save and Continue" expect(page).to have_text I18n.t("solidus_braintree.errors.empty_fields") end end # User should be able to checkout after submit fails once context "when user enters valid data", vcr: { cassette_name: "checkout/resubmit_credit_card", match_requests_on: [:braintree_uri] } do it "allows them to resubmit and complete the purchase" do within_frame("braintree-hosted-field-number") do fill_in("credit-card-number", with: "4111111111111111") end within_frame("braintree-hosted-field-expirationDate") do fill_in("expiration", with: card_expiration) end within_frame("braintree-hosted-field-cvv") do fill_in("cvv", with: "123") end click_button("Save and Continue") within(".confirm-step") do expect(page).to have_content("CONFIRM") end check('accept_terms_and_conditions') click_button("Place Order") expect(page).to have_content("Your order has been processed successfully") end end end def authenticate_3ds within_frame("Cardinal-CCA-IFrame") do fill_in("challengeDataEntry", with: "1234") continue_button = find_button("SUBMIT") continue_button.scroll_to(continue_button) continue_button.click end end end