From dc8da111589c46a07fc696ce5d1bc1572977d809 Mon Sep 17 00:00:00 2001 From: Jim Benton <3331+jim@users.noreply.github.com> Date: Thu, 30 Nov 2023 19:59:39 -0600 Subject: [PATCH] Add controller tests for renewals/payments (#1209) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # What it does Adds a controller test for `Renewals::PaymentsController`, based heavily on the one we have for `Signup::PaymentController`. This is a followup to #1192, which fixed a bug but did not include tests for timing reasons. # Why it is important This is a critical flow in the application, and we'd like to ensure that it is still working as intended 😄 # Implementation notes * There's a decent amount of duplication between `Renewals::PaymentsController` and `Signup::PaymentController`, and the same is true of their tests. It is looking like we may end up re-working the payment flows as a part of upcoming work, so I opted to not do anything too invasive at this time. # Your bandwidth for additional changes to this PR _Please choose one of the following to help the project maintainers provide the appropriate level of support:_ - [x] I have the time and interest to make additional changes to this PR based on feedback. - [ ] I am interested in feedback but don't need to make the changes myself. - [ ] I don't have time or interest in making additional changes to this work. - [ ] Other or not sure (please describe): --- .../renewal/payments_controller.rb | 2 +- .../renewal/payments_controller_test.rb | 166 ++++++++++++++++++ 2 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 test/controllers/renewal/payments_controller_test.rb diff --git a/app/controllers/renewal/payments_controller.rb b/app/controllers/renewal/payments_controller.rb index be3d169d0..1bc98ae16 100644 --- a/app/controllers/renewal/payments_controller.rb +++ b/app/controllers/renewal/payments_controller.rb @@ -63,7 +63,7 @@ def callback end Rails.logger.error(errors) - reset_session + session.delete(:attempts) flash[:error] = "There was an error processing your payment. Please come into the library to complete signup." redirect_to renewal_confirmation_url end diff --git a/test/controllers/renewal/payments_controller_test.rb b/test/controllers/renewal/payments_controller_test.rb new file mode 100644 index 000000000..02abe1b7d --- /dev/null +++ b/test/controllers/renewal/payments_controller_test.rb @@ -0,0 +1,166 @@ +require "test_helper" + +module Renewal + class PaymentsControllerTest < ActionDispatch::IntegrationTest + include Devise::Test::IntegrationHelpers + + setup do + create(:agreement_document) + @member = create(:verified_member) + @membership = create(:membership, member: @member, started_at: 13.months.ago, ended_at: 1.month.ago) + create(:adjustment, + kind: Adjustment.kinds[:payment], + payment_source: Adjustment.payment_sources[:square], + amount: Money.new(50)) + create(:adjustment, + adjustable: @membership, + kind: Adjustment.kinds[:membership], + amount: Money.new(-50)) + sign_in @member.user + end + + test "creates a checkout_url" do + mock_result = Minitest::Mock.new + mock_result.expect :success?, true + mock_result.expect :value, "https://squareup.com/checkout/12345" + + mock_checkout = Minitest::Mock.new + Time.use_zone "America/Chicago" do + mock_checkout.expect :checkout_url, mock_result, [{ + amount: Money.new(1200), + email: @member.email, + return_to: "http://example.com/renewal/payments/callback", + member_id: @member.id, + date: Date.current + }] + + SquareCheckout.stub :new, mock_checkout do + post renewal_payments_url, params: {membership_payment_form: {amount_dollars: "12"}} + end + + assert_redirected_to "https://squareup.com/checkout/12345" + + assert_mock mock_result + assert_mock mock_checkout + end + end + + test "fails to create a checkout_url" do + mock_result = Minitest::Mock.new + mock_result.expect :success?, false + mock_result.expect :error, [{code: "SOMETHING_WENT_WRONG"}] + + mock_checkout = Minitest::Mock.new + mock_checkout.expect :checkout_url, mock_result, [Hash] + + SquareCheckout.stub :new, mock_checkout do + post renewal_payments_url, params: {membership_payment_form: {amount_dollars: "12"}} + end + + assert_redirected_to "http://example.com/renewal/payments/new" + follow_redirect! + + assert_select ".toast-error", /There was a problem connecting to our payment processor/ + + assert_mock mock_result + assert_mock mock_checkout + end + + test "successful callback invocation" do + mock_result = Minitest::Mock.new + mock_result.expect :success?, true + mock_result.expect :value, Money.new(1234) + + mock_checkout = Minitest::Mock.new + mock_checkout.expect :fetch_transaction, mock_result, [{ + member: @member, + transaction_id: "abcd1234" + }] + + SquareCheckout.stub :new, mock_checkout do + assert_difference "Membership.count" => 1, "Adjustment.count" => 2 do + get callback_renewal_payments_url, params: {transactionId: "abcd1234"} + end + end + + assert_redirected_to renewal_confirmation_url + assert_equal 1234, session[:amount] + refute session[:member_id] + + assert_mock mock_result + assert_mock mock_checkout + end + + test "failed callback invocation" do + mock_result = Minitest::Mock.new + mock_result.expect :success?, false + mock_result.expect :error, [{code: "ERROR_CODE"}] + + mock_checkout = Minitest::Mock.new + mock_checkout.expect :fetch_transaction, mock_result, [Hash] + + SquareCheckout.stub :new, mock_checkout do + assert_no_difference ["Membership.count", "Adjustment.count"] do + get callback_renewal_payments_url, params: {transactionId: "abcd1234"} + end + end + + assert_redirected_to "http://example.com/renewal/confirmation" + + follow_redirect! + assert_select ".toast-error", /There was an error processing your payment/ + + assert_mock mock_result + assert_mock mock_checkout + end + + test "failed callback invocation by not finding a transaction" do + mock_result = Minitest::Mock.new + mock_result.expect :success?, false + mock_result.expect :error, [{code: "NOT_FOUND"}] + + mock_checkout = Minitest::Mock.new + mock_checkout.expect :fetch_transaction, mock_result, [Hash] + + SquareCheckout.stub :new, mock_checkout do + assert_no_difference ["Membership.count", "Adjustment.count"] do + get callback_renewal_payments_url, params: {transactionId: "abcd1234"} + end + end + + assert_equal 200, response.status + + assert_equal 1, session[:attempts] + + assert_mock mock_result + assert_mock mock_checkout + end + + test "failed callback invocation by not finding a transaction 10 times" do + 11.times do |i| + mock_result = Minitest::Mock.new + mock_result.expect :success?, false + mock_result.expect :error, [{code: "NOT_FOUND"}] + + mock_checkout = Minitest::Mock.new + mock_checkout.expect :fetch_transaction, mock_result, [Hash] + + SquareCheckout.stub :new, mock_checkout do + get callback_renewal_payments_url, params: {transactionId: "abcd1234"} + end + + assert_mock mock_result + assert_mock mock_checkout + + if i < 10 + assert_equal 200, response.status + assert_equal i + 1, session[:attempts] + else + assert_redirected_to "http://example.com/renewal/confirmation" + assert_match(/There was an error processing your payment/, flash[:error]) + refute session[:attempts] + end + end + end + end +end