From 033abfb993566f48ea00e56d94e1183249f00025 Mon Sep 17 00:00:00 2001 From: Eileen McNaughton Date: Fri, 2 Jun 2023 18:19:07 +1200 Subject: [PATCH] Add Event test trait --- Civi/Test/Api4TestTrait.php | 2 +- Civi/Test/EventTestTrait.php | 326 ++++++++++++++++++ Civi/Test/ExampleData/Event/PaidEvent.php | 5 +- tests/phpunit/CRM/Core/CopyTest.php | 2 +- .../CRM/Event/Form/ParticipantTest.php | 9 - .../CRM/Utils/TokenConsistencyTest.php | 2 +- tests/phpunit/CiviTest/CiviUnitTestCase.php | 17 +- 7 files changed, 344 insertions(+), 19 deletions(-) create mode 100644 Civi/Test/EventTestTrait.php diff --git a/Civi/Test/Api4TestTrait.php b/Civi/Test/Api4TestTrait.php index 1f9b9e2ba7..43a12ea68e 100644 --- a/Civi/Test/Api4TestTrait.php +++ b/Civi/Test/Api4TestTrait.php @@ -25,7 +25,7 @@ trait Api4TestTrait { * * @var array */ - private $testRecords = []; + protected $testRecords = []; /** * Inserts a test record, supplying all required values if not provided. diff --git a/Civi/Test/EventTestTrait.php b/Civi/Test/EventTestTrait.php new file mode 100644 index 0000000000..a50b818b20 --- /dev/null +++ b/Civi/Test/EventTestTrait.php @@ -0,0 +1,326 @@ +ids = ['Event' => ['descriptive_key' => $eventID], 'Group' => [$groupID]]; + * + * @var array + */ + protected $ids = []; + + /** + * Records created which will be deleted during tearDown + * + * @var array + */ + protected $testRecords = []; + + /** + * Track tables we have modified during a test. + * + * Set up functions that add entities can register the relevant tables here for + * the cleanup process. + * + * @var array + */ + protected $tablesToCleanUp = []; + + /** + * Create a paid event. + * + * @param array $eventParameters + * Values to + * + * @param array $priceSetParameters + * + * @param string $identifier + * Index for storing event ID in ids array. + * + * @return array + */ + protected function eventCreatePaid(array $eventParameters = [], array $priceSetParameters = [], string $identifier = 'PaidEvent'): array { + $eventParameters = array_merge($this->getEventExampleData(), $eventParameters); + $event = $this->eventCreate($eventParameters, $identifier); + if (array_keys($priceSetParameters) !== ['id']) { + try { + + // @todo - eventPriceSetCreate is only available from core tests so this can't yet + // be used in extensions. + $this->setTestEntityID('PriceSet', $this->eventPriceSetCreate(8000.67, 0, 'Radio', [['name' => 'family_package', 'amount' => 1550.55], ['name' => 'corporate_table', 'amount' => 8000.67]]), $identifier); + $this->setTestEntityID('PriceSetEntity', PriceSetEntity::create(FALSE) + ->setValues([ + 'entity_table' => 'civicrm_event', + 'entity_id' => $event['id'], + 'price_set_id' => $this->ids['PriceSet'][$identifier], + ]) + ->execute() + ->first()['id'], $identifier); + } + + catch (\CRM_Core_Exception $e) { + $this->fail('Failed to create PriceSetEntity: ' . $e->getMessage()); + } + } + return $event; + } + + /** + * Create a paid event. + * + * @param array $eventParameters + * Values to + * + * @param string $identifier + * Index for storing event ID in ids array. + * + * @return array + */ + protected function eventCreateUnpaid(array $eventParameters = [], string $identifier = 'event'): array { + $eventParameters = array_merge($this->getEventExampleData(), $eventParameters); + $eventParameters['is_monetary'] = FALSE; + return $this->eventCreate($eventParameters, $identifier); + } + + /** + * Set the test entity on the class for access. + * + * This follows the ids patter and also the api4TestTrait pattern. + * + * @param string $entity + * @param array $values + * @param string $identifier + */ + protected function setTestEntity(string $entity, array $values, string $identifier): void { + $this->ids[$entity][$identifier] = $values['id']; + $this->testRecords[] = [$entity, [[$values['id'] => $values]]]; + $tableName = \CRM_Core_DAO_AllCoreTables::getTableForEntityName($entity); + $this->tablesToCleanUp[$tableName] = $tableName; + } + + /** + * @param string $entity + * @param int $id + * @param string $identifier + */ + protected function setTestEntityID(string $entity, int $id, string $identifier): void { + $this->setTestEntity($entity, ['id' => $id], $identifier); + } + + /** + * Get the event id of the event created in set up. + * + * If only one has been created it will be selected. Otherwise + * you should pass in the appropriate identifier. + * + * @param string $identifier + * + * @return int + */ + protected function getEventID(string $identifier = 'event'): int { + if (isset($this->ids['Event'][$identifier])) { + return $this->ids['Event'][$identifier]; + } + if (count($this->ids['Event']) === 1) { + return reset($this->ids['Event']); + } + $this->fail('Could not identify event ID'); + // Unreachable but reduces IDE noise. + return 0; + } + + /** + * Get a value from an event used in setup. + * + * @param string $value + * @param string $identifier + * + * @return mixed|null + */ + protected function getEventValue(string $value, string $identifier) { + return $this->getEvent($identifier)[$value] ?? NULL; + } + + /** + * This retrieves the values used to create the event. + * + * Note this does not actually retrieve the event from the database + * although it arguably might be more useful. + * + * @param string $identifier + * + * @return array + */ + protected function getEvent(string $identifier): array { + foreach ($this->testRecords as $record) { + if ($record[0] === 'Event') { + $values = $record[1][0] ?? []; + if ($this->getEventID($identifier) === array_key_first($values)) { + return (reset($values)); + } + } + } + return []; + } + + /** + * Create an Event. + * + * Note this is not expected to be called directly - call + * - eventCreatePaid + * - eventCreateUnpaid + * + * @param array $params + * Name-value pair for an event. + * @param string $identifier + * + * @return array + */ + protected function eventCreate(array $params = [], string $identifier = 'event'): array { + try { + $event = Event::create(FALSE)->setValues($params)->execute()->first(); + $this->setTestEntity('Event', $event, $identifier); + $this->addProfilesToEvent($identifier); + return $event; + } + catch (\CRM_Core_Exception $e) { + $this->fail('Event creation failed with error ' . $e->getMessage()); + } + // Unreachable but reduces IDE noise. + return []; + } + + /** + * Get example data with which to create the event. + * + * @param string $name + * + * @return array + */ + protected function getEventExampleData(string $name = 'PaidEvent'): array { + try { + $data = ExampleData::get(FALSE) + ->addSelect('data') + ->addWhere('name', '=', 'entity/Event/' . $name) + ->execute()->first()['data']; + unset($data['id']); + return $data; + } + catch (\CRM_Core_Exception $e) { + $this->fail('Event example data retrieval failed with error ' . $e->getMessage()); + } + // Unreachable but reduces IDE noise. + return []; + } + + /** + * Add profiles to the event. + * + * This function is designed to reflect the + * normal use case where events do have profiles. + * + * Note if any classes do not want profiles, or want something different, + * the thinking is they should override this. Once that arises we can review + * making it protected rather than private & checking we are happy with the + * signature. + * + * @param string $identifier + * + * @throws \CRM_Core_Exception + */ + private function addProfilesToEvent(string $identifier = 'event'): void { + $profiles = [ + ['name' => '_pre', 'title' => 'Event Pre Profile', 'weight' => 1, 'fields' => ['email']], + ['name' => '_post', 'title' => 'Event Post Profile', 'weight' => 2, 'fields' => ['first_name', 'last_name']], + ['name' => '_post_post', 'title' => 'Event Post Post Profile', 'weight' => 3, 'fields' => ['job_title']], + ]; + foreach ($profiles as $profile) { + $this->createEventProfile($profile, $identifier); + if ($this->getEventValue('is_multiple_registrations', $identifier)) { + $this->createEventProfile($profile, $identifier, TRUE); + } + } + } + + /** + * Create a profile attached to an event. + * + * @param array $profile + * @param string $identifier + * @param bool $isAdditional + * + * @throws \CRM_Core_Exception + */ + private function createEventProfile(array $profile, string $identifier, bool $isAdditional = FALSE): void { + $profileName = $identifier . ($isAdditional ? $profile['name'] . '_additional' : $profile['name']); + $profileIdentifier = $profileName . '_' . $identifier; + $additionalSuffix = $isAdditional ? ' (Additional) ' : ''; + try { + $this->setTestEntity('UFGroup', UFGroup::create(FALSE)->setValues([ + 'group_type' => 'Individual,Contact', + 'name' => $profileName, + 'title' => $profile['title'] . $additionalSuffix, + 'frontend_title' => 'Public ' . $profile['title'] . $additionalSuffix, + ])->execute()->first(), + $profileIdentifier); + } + catch (\CRM_Core_Exception $e) { + $this->fail('UF group creation failed for ' . $profileName . ' with error ' . $e->getMessage()); + } + foreach ($profile['fields'] as $field) { + $this->setTestEntity('UFField', UFField::create(FALSE) + ->setValues([ + 'uf_group_id:name' => $profileName, + 'field_name' => $field, + 'label' => $field, + ]) + ->execute() + ->first(), $field . '_' . $profileIdentifier); + } + try { + $this->setTestEntity('UFJoin', UFJoin::create(FALSE)->setValues([ + 'module' => $additionalSuffix ? 'CiviEvent_Additional' : 'CiviEvent', + 'uf_group_id:name' => $profileName, + 'entity_id' => $this->getEventID($identifier), + ])->execute()->first(), $profileIdentifier); + } + catch (\CRM_Core_Exception $e) { + $this->fail('UF join creation failed for UF Group ' . $profileName . ' with error ' . $e->getMessage()); + } + } + +} diff --git a/Civi/Test/ExampleData/Event/PaidEvent.php b/Civi/Test/ExampleData/Event/PaidEvent.php index d6c2a71b07..39bd2c3cf7 100644 --- a/Civi/Test/ExampleData/Event/PaidEvent.php +++ b/Civi/Test/ExampleData/Event/PaidEvent.php @@ -25,10 +25,11 @@ class PaidEvent extends EntityExample { 'is_online_registration' => TRUE, 'registration_start_date' => 20080601, 'registration_end_date' => '+ 1 month', - 'max_participants' => 100, + 'is_multiple_registrations' => TRUE, + 'max_participants' => 5, 'event_full_text' => 'Sorry! We are already full', 'is_monetary' => TRUE, - 'financial_type_id' => 3, + 'financial_type_id:name' => 'Event Fee', 'is_active' => 1, 'default_role_id' => 1, 'is_show_location' => TRUE, diff --git a/tests/phpunit/CRM/Core/CopyTest.php b/tests/phpunit/CRM/Core/CopyTest.php index 993b0b8a39..a556bb4751 100644 --- a/tests/phpunit/CRM/Core/CopyTest.php +++ b/tests/phpunit/CRM/Core/CopyTest.php @@ -22,7 +22,7 @@ class CRM_Core_CopyTest extends CiviUnitTestCase { public function testEventCopy(): void { $this->createCustomGroupWithFieldOfType(['extends' => 'Event']); - $event = $this->eventCreate([$this->getCustomFieldName('text', 4) => 'blah']); + $event = $this->eventCreateUnpaid([$this->getCustomFieldName('text', 4) => 'blah']); $eventId = $event['id']; $eventRes = $event; $params[$this->getCustomFieldName('text') . '_1'] = 'blah'; diff --git a/tests/phpunit/CRM/Event/Form/ParticipantTest.php b/tests/phpunit/CRM/Event/Form/ParticipantTest.php index 4703791ab7..86dd209864 100644 --- a/tests/phpunit/CRM/Event/Form/ParticipantTest.php +++ b/tests/phpunit/CRM/Event/Form/ParticipantTest.php @@ -834,15 +834,6 @@ class CRM_Event_Form_ParticipantTest extends CiviUnitTestCase { $this->callAPISuccessGetCount('ParticipantPayment', ['participant_id' => $participantId], 0); } - /** - * Get the id of the created event. - * - * @return int - */ - protected function getEventID(): int { - return reset($this->ids['Event']); - } - /** * Get created contact ID. * diff --git a/tests/phpunit/CRM/Utils/TokenConsistencyTest.php b/tests/phpunit/CRM/Utils/TokenConsistencyTest.php index 645a9d6678..7f8ba1af5b 100644 --- a/tests/phpunit/CRM/Utils/TokenConsistencyTest.php +++ b/tests/phpunit/CRM/Utils/TokenConsistencyTest.php @@ -1042,7 +1042,7 @@ United States', $tokenProcessor->getRow(0)->render('message')); 'phone_id' => $phoneID, ], ])->execute()->first()['id']; - $this->ids['Event'][0] = $this->eventCreate([ + $this->ids['Event'][0] = $this->eventCreateUnpaid([ 'description' => 'event description', 'end_date' => 20081023, 'registration_end_date' => 20081015, diff --git a/tests/phpunit/CiviTest/CiviUnitTestCase.php b/tests/phpunit/CiviTest/CiviUnitTestCase.php index 4b4b081ff3..2804ff2256 100644 --- a/tests/phpunit/CiviTest/CiviUnitTestCase.php +++ b/tests/phpunit/CiviTest/CiviUnitTestCase.php @@ -46,6 +46,12 @@ use Civi\Core\Transaction\Manager; use Civi\Payment\System; use Civi\Api4\OptionValue; use Civi\Test\Api3DocTrait; +use Civi\Test\ContactTestTrait; +use Civi\Test\DbTestTrait; +use Civi\Test\EventTestTrait; +use Civi\Test\GenericAssertionsTrait; +use Civi\Test\LocaleTestTrait; +use Civi\Test\MailingTestTrait; use League\Csv\Reader; /** @@ -75,11 +81,12 @@ define('API_LATEST_VERSION', 3); class CiviUnitTestCase extends PHPUnit\Framework\TestCase { use Api3DocTrait; - use \Civi\Test\GenericAssertionsTrait; - use \Civi\Test\DbTestTrait; - use \Civi\Test\ContactTestTrait; - use \Civi\Test\MailingTestTrait; - use \Civi\Test\LocaleTestTrait; + use EventTestTrait; + use GenericAssertionsTrait; + use DbTestTrait; + use ContactTestTrait; + use MailingTestTrait; + use LocaleTestTrait; /** * API version in use. -- 2.25.1