--- /dev/null
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved. |
+ | |
+ | This work is published under the GNU AGPLv3 license with some |
+ | permitted exceptions and without any warranty. For full license |
+ | and copyright information, see https://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * Class CRM_Core_Payment_AuthorizeNetTest
+ * @group headless
+ */
+trait CRM_Core_Payment_AuthorizeNetTrait {
+ use \Civi\Test\GuzzleTestTrait;
+
+ /**
+ * @var \CRM_Core_Payment_AuthorizeNet
+ */
+ protected $processor;
+
+ /**
+ * Is this a recurring transaction.
+ *
+ * @var bool
+ */
+ protected $isRecur = FALSE;
+
+ /**
+ * Get the expected response from Authorize.net.
+ *
+ * @return string
+ */
+ public function getExpectedSinglePaymentResponse() {
+ return '"1","1","1","(TESTMODE) This transaction has been approved.","000000","P","0","","","5.24","CC","auth_capture","","John","O'Connor","","","","","","","","","","","","","","","","","","","","","","","",""';
+ }
+
+ /**
+ * Get the expected request from Authorize.net.
+ *
+ * @return string
+ */
+ public function getExpectedSinglePaymentRequest() {
+ return 'x_login=4y5BfuW7jm&x_tran_key=4cAmW927n8uLf5J8&x_email_customer=&x_first_name=John&x_last_name=O%27Connor&x_address=&x_city=&x_state=&x_zip=&x_country=&x_customer_ip=&x_email=&x_invoice_num=&x_amount=5.24&x_currency_code=&x_description=&x_cust_id=&x_relay_response=FALSE&x_delim_data=TRUE&x_delim_char=%2C&x_encap_char=%22&x_card_num=4444333322221111&x_card_code=123&x_exp_date=10%2F2022&x_test_request=TRUE';
+ }
+
+ /**
+ * Add a mock handler to the authorize.net processor for testing.
+ *
+ * @param int|null $id
+ *
+ * @throws \CiviCRM_API3_Exception
+ */
+ protected function setupMockHandler($id = NULL) {
+ if ($id) {
+ $this->processor = Civi\Payment\System::singleton()->getById($id);
+ }
+ $response = $this->isRecur ? $this->getExpectedRecurResponse() : $this->getExpectedSinglePaymentResponse();
+ $this->createMockHandler([$response]);
+ $this->setUpClientWithHistoryContainer();
+ $this->processor->setGuzzleClient($this->getGuzzleClient());
+ }
+
+ /**
+ * Get a successful response to setting up a recurring.
+ *
+ * @return string
+ */
+ public function getExpectedRecurResponse() {
+ return '<?xml version="1.0" encoding="utf-8"?><ARBCreateSubscriptionResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd"><refId>8d468ca1b1dd5c2b56c7</refId><messages><resultCode>Ok</resultCode><message><code>I00001</code><text>Successful.</text></message></messages><subscriptionId>6632052</subscriptionId><profile><customerProfileId>1512023280</customerProfileId><customerPaymentProfileId>1512027350</customerPaymentProfileId></profile></ARBCreateSubscriptionResponse>';
+ }
+
+}
--- /dev/null
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved. |
+ | |
+ | This work is published under the GNU AGPLv3 license with some |
+ | permitted exceptions and without any warranty. For full license |
+ | and copyright information, see https://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * Test various payment forms.
+ *
+ * This class is intended to be a place to build out testing of various forms - with the
+ * hope being to ensure all payment forms are consistently tested and to refine
+ * helper functions into a trait that could be available to
+ * extensions for testing - notably the eventcart which ideally should interact with core
+ * through approved interfaces - ideally even in tests.
+ *
+ * An approved interface would sit in the Civi directory and would at minimum support some functions
+ * to support using our processors in tests so we are testing a broader swath than just Dummy.
+ * Currently Authorize.net is also testable (uses Guzzle). At some point PaypalPro & Std should also be testable
+ * - allowing us to easily check payment forms work with the core processors which cover a reasonable amount of the
+ * expectations held by non-core processors .
+ *
+ * Note that this tests eventcart but is not in eventcart because I want to be sure about whether the
+ * traits supporting it make sense before making them available to extensions.
+ */
+class CRM_Financial_Form_PaymentFormsTest extends CiviUnitTestCase {
+
+ use CRM_Core_Payment_AuthorizeNetTrait;
+
+ /**
+ * Generic test on event payment forms to make sure they submit without error with payment processing.
+ *
+ * @throws \CRM_Core_Exception
+ * @throws \CiviCRM_API3_Exception
+ */
+ public function testEventPaymentForms() {
+ $processors = [$this->paymentProcessorAuthorizeNetCreate(['is_test' => FALSE])];
+ $this->setupMockHandler($processors[0]);
+ $eventID = $this->eventCreatePaid([
+ 'end_date' => '+ 1 month',
+ 'registration_end_date' => '+ 1 month',
+ 'payment_processor' => $processors,
+ ])['id'];
+ $this->createLoggedInUser();
+
+ $forms = [
+ 'CRM_Event_Cart_Form_Checkout_ParticipantsAndPrices' => [
+ 'forms' => ['CRM_Event_Cart_Form_Checkout_ParticipantsAndPrices', 'CRM_Event_Cart_Form_Checkout_Payment'],
+ 'controller' => [],
+ 'submitValues' => [
+ 'event' => [$eventID => ['participant' => [1 => ['email' => 'bob@example.com']]]],
+ 'event_' . $eventID . '_price_' . $this->_ids['price_field'][0] => $this->_ids['price_field_value'][0],
+ ],
+ 'REQUEST' => [],
+ ],
+ ];
+ $genericParams = [
+ 'credit_card_number' => 4111111111111111,
+ 'processor_id' => $processors[0],
+ 'cvv2' => '123',
+ 'credit_card_exp_date' => [
+ 'M' => '1',
+ 'Y' => date('Y') + 1,
+ ],
+ 'credit_card_type' => 'Visa',
+ 'billing_contact_email' => 'bobby@example.com',
+ 'billing_first_name' => 'John',
+ 'billing_middle_name' => '',
+ 'billing_last_name' => "O'Connor",
+ 'billing_street_address-5' => '8 Hobbitton Road',
+ 'billing_city-5' => 'The Shire',
+ 'billing_state_province_id-5' => 1012,
+ 'billing_postal_code-5' => 5010,
+ 'billing_country_id-5' => 1228,
+ ];
+
+ $cart = CRM_Event_Cart_BAO_Cart::find_or_create_for_current_session();
+ $cart->add_event($eventID);
+
+ foreach ($forms as $values) {
+ $_REQUEST = $values['REQUEST'];
+ $qfKey = NULL;
+ foreach ($values['forms'] as $formName) {
+ $formValues = array_merge($genericParams, $values['submitValues'], ['qfKey' => $qfKey]);
+ $form = $this->getFormObject($formName, $formValues);
+ $form->preProcess();
+ $form->buildQuickForm();
+ $form->postProcess();
+ $qfKey = $form->controller->_key;
+ }
+ $this->callAPISuccessGetSingle('Participant', ['participant_status_id' => 'Registered']);
+ $request = explode('&', $this->getRequestBodies()[0]);
+ // This is stand in for now just to check a request happened. We can improve later.
+ $this->assertContains('x_card_num=4111111111111111', $request);
+ }
+ }
+
+}