Update ContributionMainTest to use full form flow
authorEileen McNaughton <emcnaughton@wikimedia.org>
Thu, 27 Jul 2023 23:14:02 +0000 (11:14 +1200)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Thu, 27 Jul 2023 23:21:45 +0000 (11:21 +1200)
This updates the test to use postProcess and to check is_recur is passed to the
preApprove function rather than proxy that check by checking if is_recur
is set in the _params property (which is not used again after the preApprove

CRM/Contribute/Form/Contribution/Main.php
CRM/Core/Payment/Dummy.php
tests/phpunit/CRM/Contribute/Form/Contribution/MainTest.php
tests/phpunit/CiviTest/CiviUnitTestCase.php

index d8c99607608c3667e0170f46297de5b9695f06a0..2a712ad4d545fa2824eda11952dfc368827ccc0b 100644 (file)
@@ -1370,6 +1370,9 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu
   /**
    * Function for unit tests on the postProcess function.
    *
+   * @deprecated - we are ditching this approach in favour of 'full form flow'
+   * = ie simulating postProcess.
+   *
    * @param array $params
    *
    * @throws \CRM_Core_Exception
index 4b6735d8195e454eb06e750a89e4a7ef456c6048..d2d3195c689b1a2d2d7f1c81ce866493e7b920c0 100644 (file)
@@ -167,6 +167,21 @@ class CRM_Core_Payment_Dummy extends CRM_Core_Payment {
     return $this->supports['CancelRecurringNotifyOptional'];
   }
 
+  /**
+   * Does this processor support pre-approval.
+   *
+   * This would generally look like a redirect to enter credentials which can then be used in a later payment call.
+   *
+   * Currently Paypal express supports this, with a redirect to paypal after the 'Main' form is submitted in the
+   * contribution page. This token can then be processed at the confirm phase. Although this flow 'looks' like the
+   * 'notify' flow a key difference is that in the notify flow they don't have to return but in this flow they do.
+   *
+   * @return bool
+   */
+  protected function supportsPreApproval(): bool {
+    return $this->supports['PreApproval'] ?? FALSE;
+  }
+
   /**
    * Set the return value of support functions. By default it is TRUE
    *
@@ -261,6 +276,21 @@ class CRM_Core_Payment_Dummy extends CRM_Core_Payment {
    */
   public function doRefund(&$params) {}
 
+  /**
+   * Function to action pre-approval if supported
+   *
+   * @param array $params
+   *   Parameters from the form
+   *
+   * This function returns an array which should contain
+   *   - pre_approval_parameters (this will be stored on the calling form & available later)
+   *   - redirect_url (if set the browser will be redirected to this.
+   */
+  public function doPreApproval(&$params): void {
+    // We set this here to allow the test to check what is set.
+    \Civi::$statics[__CLASS__][__FUNCTION__] = $params;
+  }
+
   /**
    * This function checks to see if we have the right config values.
    *
index e450e5ce40a727888fae0409e66113c28ffbd539..0bb03f4988faec3e683bf16e2e1afa72b760be32 100644 (file)
@@ -9,6 +9,8 @@
  +--------------------------------------------------------------------+
  */
 
+use Civi\Api4\PriceField;
+
 /**
  *  Test APIv3 civicrm_contribute_* functions
  *
@@ -41,8 +43,8 @@ class CRM_Contribute_Form_Contribution_MainTest extends CiviUnitTestCase {
   /**
    * Given a membership type ID, return the price field value.
    */
-  private function getPriceFieldValue($membershipTypeId) {
-    return $this->callAPISuccessGetValue('PriceFieldValue', ['membership_type_id' => $membershipTypeId, 'return' => 'id']);
+  private function getPriceFieldValue($membershipTypeID): int {
+    return (int) $this->callAPISuccessGetSingle('PriceFieldValue', ['membership_type_id' => $membershipTypeID, 'return' => 'id', 'price_field_id' => $this->ids['PriceField']['membership']])['id'];
   }
 
   /**
@@ -61,7 +63,7 @@ class CRM_Contribute_Form_Contribution_MainTest extends CiviUnitTestCase {
       'credit_card_exp_date' => ['M' => 9, 'Y' => 2040],
       'cvv2' => 123,
       'auto_renew' => 1,
-      'priceSetId' => $this->priceSetId,
+      'priceSetId' => $this->ids['PriceSet']['membership'],
     ];
   }
 
@@ -69,53 +71,40 @@ class CRM_Contribute_Form_Contribution_MainTest extends CiviUnitTestCase {
    * Test that the membership is set to recurring if the membership type is always autorenew.
    */
   public function testSetRecurFunction(): void {
-    $membershipTypeID = $this->membershipTypeCreate(['auto_renew' => 2, 'minimum_fee' => 80]);
+    $this->membershipTypeCreate(['auto_renew' => 2, 'minimum_fee' => 80]);
     $form = $this->getContributionForm();
-    $priceFieldValueId = $this->getPriceFieldValue($membershipTypeID);
-    $form->testSubmit(array_merge($this->getSubmitParams(), [
-      'price_' . $this->priceSetId => $priceFieldValueId,
-    ]));
-    $this->assertEquals(1, $form->_params['is_recur']);
+    $form->postProcess();
+    $this->assertIsRecur(1);
   }
 
   /**
    * Test that the membership is set to recurring if the membership type is optionally autorenew and is_recur is true.
    */
   public function testSetRecurFunctionOptionalYes(): void {
-    $membershipTypeID = $this->membershipTypeCreate(['auto_renew' => 1, 'minimum_fee' => 80]);
+    $this->membershipTypeCreate(['auto_renew' => 1, 'minimum_fee' => 80]);
     $form = $this->getContributionForm();
-    $priceFieldValueId = $this->getPriceFieldValue($membershipTypeID);
-    $form->testSubmit(array_merge($this->getSubmitParams(), [
-      'price_' . $this->priceSetId => $priceFieldValueId,
-    ]));
-    $this->assertEquals(1, $form->_params['is_recur']);
+    $form->postProcess();
+    $this->assertIsRecur(1);
   }
 
   /**
    * Test that the membership is not set to recurring if the membership type is optionally autorenew and is_recur is false.
    */
   public function testSetRecurFunctionOptionalNo(): void {
-    $membershipTypeID = $this->membershipTypeCreate(['auto_renew' => 1, 'minimum_fee' => 80]);
-    $form = $this->getContributionForm();
-    $priceFieldValueId = $this->getPriceFieldValue($membershipTypeID);
-    $form->testSubmit(array_merge($this->getSubmitParams(), [
-      'price_' . $this->priceSetId => $priceFieldValueId,
-      'auto_renew' => 0,
-    ]));
-    $this->assertEquals(0, $form->_params['is_recur']);
+    $this->membershipTypeCreate(['auto_renew' => 1, 'minimum_fee' => 80]);
+    $form = $this->getContributionForm(['auto_renew' => 0]);
+    $form->postProcess();
+    $this->assertIsRecur(0);
   }
 
   /**
    * Test that the membership doesn't have an "is_recur" key if the membership type can never autorenew.
    */
-  public function testSetRecurFunctionNotAvailable() {
-    $membershipTypeID = $this->membershipTypeCreate(['auto_renew' => 0, 'minimum_fee' => 80]);
+  public function testSetRecurFunctionNotAvailable(): void {
+    $this->membershipTypeCreate(['auto_renew' => 0, 'minimum_fee' => 80]);
     $form = $this->getContributionForm();
-    $priceFieldValueId = $this->getPriceFieldValue($membershipTypeID);
-    $form->testSubmit(array_merge($this->getSubmitParams(), [
-      'price_' . $this->priceSetId => $priceFieldValueId,
-    ]));
-    $this->assertArrayNotHasKey('is_recur', $form->_params);
+    $form->postProcess();
+    $this->assertIsRecur(NULL);
   }
 
   /**
@@ -128,10 +117,11 @@ class CRM_Contribute_Form_Contribution_MainTest extends CiviUnitTestCase {
    */
   protected function getContributionForm(array $submittedValues = [], $params = []): CRM_Contribute_Form_Contribution_Main {
     try {
-      $this->priceSetId = $params['priceSetID'] ?? $this->callAPISuccessGetValue('PriceSet', [
+      $this->ids['PriceSet']['membership'] = $params['priceSetID'] ?? $this->callAPISuccessGetValue('PriceSet', [
         'name' => 'default_membership_type_amount',
         'return' => 'id',
       ]);
+      $this->ids['PriceField']['membership'] = PriceField::get(FALSE)->addWhere('price_set_id', '=', $this->ids['PriceSet']['membership'])->execute()->first()['id'];
 
       $paymentProcessor = $submittedValues['payment_processor_id'] = $this->paymentProcessorCreate([
         'payment_processor_type_id' => 'Dummy',
@@ -150,12 +140,16 @@ class CRM_Contribute_Form_Contribution_MainTest extends CiviUnitTestCase {
         'amount_block_is_active' => 1,
       ]));
       $contributionPage = $this->contributionPageCreate($contributionPageParams);
+      CRM_Price_BAO_PriceSet::addTo('civicrm_contribution_page', $contributionPage['id'], $this->ids['PriceSet']['membership']);
+
+      $submittedValues = array_merge($this->getSubmitParams(), [
+        'price_' . $this->ids['PriceField']['membership'] => $this->getPriceFieldValue($this->ids['MembershipType']['test']),
+      ], $submittedValues);
       $submittedValues['id'] = $_REQUEST['id'] = (int) $contributionPage['id'];
       /** @var \CRM_Contribute_Form_Contribution_Main $form */
       $form = $this->getFormObject('CRM_Contribute_Form_Contribution_Main', $submittedValues);
-      $form->set('id', $contributionPage['id']);
-      CRM_Price_BAO_PriceSet::addTo('civicrm_contribution_page', $contributionPage['id'], $this->priceSetId);
       $form->preProcess();
+      $form->_paymentProcessor['object']->setSupports(['PreApproval' => TRUE, 'BackOffice' => TRUE]);
       $form->buildQuickForm();
       // Need these values to create more realistic submit params (in getSubmitParams).
       $this->paymentProcessorId = $paymentProcessor;
@@ -167,7 +161,7 @@ class CRM_Contribute_Form_Contribution_MainTest extends CiviUnitTestCase {
   }
 
   /**
-   * Test expired priceset are not returned from buildPriceSet() Function
+   * Test expired priceset are not returned from buildPriceSet() Function.
    */
   public function testExpiredPriceSet(): void {
     $priceSetParams1 = [
@@ -179,39 +173,38 @@ class CRM_Contribute_Form_Contribution_MainTest extends CiviUnitTestCase {
       'is_quick_config' => 1,
       'is_reserved' => 1,
     ];
-    $priceSet = $this->callAPISuccess('price_set', 'create', $priceSetParams1);
+    $priceSet = $this->createTestEntity('PriceSet', $priceSetParams1);
 
     // Create valid price field.
     $params = [
-      'price_set_id' => $priceSet['id'],
-      'name' => 'testvalidpf',
-      'label' => 'test valid pf',
+      'price_set_id' => $this->ids['PriceSet']['default'],
+      'name' => 'test_valid_price_field',
+      'label' => 'test valid price field',
       'html_type' => 'Radio',
       'is_enter_qty' => 1,
       'is_active' => 1,
     ];
-    $priceField1 = $this->callAPISuccess('PriceField', 'create', $params);
+    $priceField1 = $this->createTestEntity('PriceField', $params);
 
     // Create expired price field.
     $params = [
       'price_set_id' => $priceSet['id'],
-      'name' => 'testexpiredpf',
-      'label' => 'test expired pf',
+      'name' => 'test_expired_price_field',
+      'label' => 'test expired price field',
       'html_type' => 'Radio',
       'is_enter_qty' => 1,
       'is_active' => 1,
-      'expire_on' => date('Y-m-d', strtotime("-1 days")),
+      'expire_on' => date('Y-m-d', strtotime('-1 days')),
     ];
-    $priceField2 = $this->callAPISuccess('PriceField', 'create', $params);
+    $priceField2 = $this->createTestEntity('PriceField', $params, 'expired');
 
     //Create price options.
-    $membershipOrgId = $this->organizationCreate();
-    $memtype = $this->membershipTypeCreate(['member_of_contact_id' => $membershipOrgId]);
+    $this->membershipTypeCreate(['member_of_contact_id' => $this->organizationCreate()]);
     foreach ([$priceField1, $priceField2] as $priceField) {
       $priceFieldValueParams = [
         'price_field_id' => $priceField['id'],
         'name' => 'rye grass',
-        'membership_type_id' => $memtype,
+        'membership_type_id' => $this->ids['MembershipType']['test'],
         'label' => 'juicy and healthy',
         'amount' => 1,
         'membership_num_terms' => 2,
@@ -221,8 +214,8 @@ class CRM_Contribute_Form_Contribution_MainTest extends CiviUnitTestCase {
     }
 
     $form = $this->getContributionForm([], ['priceSetID' => $priceSet['id']]);
-    foreach ($form->_priceSet['fields'] as $pField) {
-      foreach ($pField['options'] as $opId => $opValues) {
+    foreach ($form->_priceSet['fields'] as $priceField) {
+      foreach ($priceField['options'] as $opValues) {
         $membershipTypeIds[$opValues['membership_type_id']] = $opValues['membership_type_id'];
       }
     }
@@ -231,9 +224,17 @@ class CRM_Contribute_Form_Contribution_MainTest extends CiviUnitTestCase {
     //This function should not update form priceSet with the expired one.
     CRM_Price_BAO_PriceSet::buildPriceSet($form);
 
-    $this->assertEquals(1, count($form->_priceSet['fields']));
+    $this->assertCount(1, $form->_priceSet['fields']);
     $field = current($form->_priceSet['fields']);
-    $this->assertEquals('testvalidpf', $field['name']);
+    $this->assertEquals('test_valid_price_field', $field['name']);
+  }
+
+  /**
+   * @param int|null $expected
+   */
+  protected function assertIsRecur(?int $expected): void {
+    $isRecur = \Civi::$statics['CRM_Core_Payment_Dummy']['doPreApproval']['is_recur'] ?? NULL;
+    $this->assertEquals($expected, $isRecur);
   }
 
 }
index abc2e372c1ed5f1c1eaa80dfc4abb8205df0255d..973a120a5f4339a3f86274ae46d60fb867ccafd7 100644 (file)
@@ -563,10 +563,11 @@ class CiviUnitTestCase extends PHPUnit\Framework\TestCase {
 
   /**
    * @param array $params
+   * @param string $identifer
    *
    * @return int
    */
-  public function membershipTypeCreate($params = []) {
+  public function membershipTypeCreate(array $params = [], $identifer = 'test'): int {
     CRM_Member_PseudoConstant::flush('membershipType');
     CRM_Core_Config::clearDBCache();
     $this->setupIDs['contact'] = $memberOfOrganization = $this->organizationCreate();
@@ -587,7 +588,7 @@ class CiviUnitTestCase extends PHPUnit\Framework\TestCase {
 
     CRM_Member_PseudoConstant::flush('membershipType');
     CRM_Utils_Cache::singleton()->flush();
-
+    $this->ids['MembershipType'][$identifer] = (int) $result['id'];
     return (int) $result['id'];
   }