diff --git a/composer.json b/composer.json index e04b5ee097..55c2569640 100644 --- a/composer.json +++ b/composer.json @@ -80,7 +80,7 @@ "drupal/entityqueue": "^1.2", "drupal/environment_indicator": "^4.0", "drupal/epp": "^1.1", - "drupal/expirable_content": "1.0.x-dev@dev", + "drupal/expirable_content": "^1.0@alpha", "drupal/fast_404": "^3.0", "drupal/feature_toggle": "^2.0", "drupal/field_group": "^3.4", diff --git a/composer.lock b/composer.lock index 7330347e10..8e802248ed 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "47cf0b96e9848155990d8b6eb316d442", + "content-hash": "d4a8e6fee6064073a5f736e456c263c9", "packages": [ { "name": "asm89/stack-cors", @@ -6361,23 +6361,26 @@ }, { "name": "drupal/expirable_content", - "version": "dev-1.0.x", + "version": "1.0.0-alpha4", "source": { "type": "git", "url": "https://git.drupalcode.org/project/expirable_content.git", - "reference": "ecf4bd5662851f58c531fc1c71a03f7687905fad" + "reference": "1.0.0-alpha4" + }, + "dist": { + "type": "zip", + "url": "https://ftp.drupal.org/files/projects/expirable_content-1.0.0-alpha4.zip", + "reference": "1.0.0-alpha4", + "shasum": "49483d13aca9c5fedfb1961483ba02b9759d846a" }, "require": { "drupal/core": "^9 || ^10" }, "type": "drupal-module", "extra": { - "branch-alias": { - "dev-1.0.x": "1.0.x-dev" - }, "drupal": { - "version": "1.0.0-alpha2+3-dev", - "datestamp": "1714075716", + "version": "1.0.0-alpha4", + "datestamp": "1718733572", "security-coverage": { "status": "not-covered", "message": "Project has not opted into security advisory coverage!" @@ -26999,7 +27002,7 @@ "drupal/entity_reference_validators": 15, "drupal/entity_route_context": 5, "drupal/entity_usage": 10, - "drupal/expirable_content": 20, + "drupal/expirable_content": 15, "drupal/fieldhelptext": 10, "drupal/flag": 10, "drupal/graphql_menu": 15, diff --git a/tests/phpunit/va_gov_notifications/functional/AgingContentFullWidthBannerTest.php b/tests/phpunit/va_gov_notifications/functional/AgingContentFullWidthBannerTest.php new file mode 100644 index 0000000000..f0516b7ed1 --- /dev/null +++ b/tests/phpunit/va_gov_notifications/functional/AgingContentFullWidthBannerTest.php @@ -0,0 +1,107 @@ +createUser([], 'Admin', TRUE); + $this->drupalLogin($user); + + $node_base = [ + 'title' => 'Expirable Content Test Node', + 'status' => 1, + 'moderation_state' => 'published', + 'type' => 'banner', + 'uid' => 1, + 'revision_default' => 1, + 'field_administration' => ['target_id' => 194], + ]; + + $base_date = DrupalDateTime::createFromTimestamp(time()); + $warn_node = clone $base_date; + $exp_node = clone $base_date; + + $dates = [ + 'not expired or warn' => $base_date->getTimestamp(), + 'warn' => $warn_node->sub(new \DateInterval('P5D'))->getTimestamp(), + 'expired' => $exp_node->sub(new \DateInterval('P8D'))->getTimestamp(), + ]; + + foreach ($dates as $key => $date) { + $node = $this->createNode($node_base); + $node->set('field_last_saved_by_an_editor', $date); + $node->set('title', $node->getTitle() . ':' . $key); + $node->save(); + } + } + + /** + * Data provider for expiration and warning tests. + */ + #[ArrayShape(['expired' => "string[]", 'warn' => "string[]"])] + public function dataProvider(): array { + return [ + 'expired' => ['expired'], + 'warn' => ['warn'], + ]; + } + + /** + * Tests that Full Width Alerts (banner) notifications are sent. + * + * @param string $type + * The type of test either 'warn' or 'expired'. + * + * @dataProvider dataProvider + * + * @throws \Behat\Mink\Exception\ResponseTextException + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException + * @throws \Drupal\Core\Entity\EntityStorageException + */ + public function testFullWidthBannerJobQueued(string $type) { + // Enable the ECA if it is not already. + /** @var \Drupal\eca\Entity\Eca $eca */ + $eca = \Drupal::entityTypeManager()->getStorage('eca')->load("aging_content_{$type}_fwb"); + $status = $eca->status(); + $eca->enable(); + $eca->save(); + + // Run cron to queue the job. + $this->drupalGet('admin/reports/status'); + $this->clickLink($this->t('Run cron')); + + // Check that the job is queued. + $this->drupalGet('admin/config/system/queues/jobs/aging_content'); + $this->assertSession()->pageTextContains("Expirable Content Test Node:{$type}"); + + // Set ECA to previous state. This is to prevent duplicate queued items. + $eca->setStatus($status); + $eca->save(); + + // Run cron again to execute the job, which sends the notification. + $this->drupalGet('admin/reports/status'); + $this->clickLink($this->t('Run cron')); + + $this->assertSession()->pageTextContains('Success'); + } + +} diff --git a/tests/phpunit/va_gov_notifications/kernel/JobTypeMessageNotifyBaseTest.php b/tests/phpunit/va_gov_notifications/kernel/JobTypeMessageNotifyBaseTest.php new file mode 100644 index 0000000000..520edcddd7 --- /dev/null +++ b/tests/phpunit/va_gov_notifications/kernel/JobTypeMessageNotifyBaseTest.php @@ -0,0 +1,138 @@ +installEntitySchema('user'); + $this->installEntitySchema('message'); + $this->createUser(admin: FALSE); + + // Create message template. + $message_template = MessageTemplate::create([ + 'template' => 'foo_template', + 'label' => 'Example Template', + ]); + $message_template->save(); + + // Instantiate the job type. + $this->jobType = new JobTypeMessageNotifyBase( + ['id' => 'test_job_type'], + 'test_job_type', + ['provider' => 'va_gov_notifications'], + $this->container->get('logger.factory'), + $this->container->get('message_notify.sender') + ); + } + + /** + * Tests the process method for a successful message send. + */ + public function testProcessSuccess() { + $payload = [ + 'values' => [], + 'template_values' => [ + 'uid' => 1, + 'template' => 'foo_template', + ], + 'restrict_delivery_to' => [1], + ]; + $job = new Job([ + 'type' => 'test_job_type', + 'payload' => $payload, + 'state' => Job::STATE_QUEUED, + ]); + + $result = $this->jobType->process($job); + $this->assertEquals(Job::STATE_SUCCESS, $result->getState()); + $this->assertEquals('Message 1 sent successfully.', $result->getMessage()); + } + + /** + * Tests the process method with an error due to missing template values. + */ + public function testProcessFailureRecipientAllowList() { + $payload = [ + 'values' => [], + 'template_values' => [ + 'uid' => 1, + 'template' => 'foo_template', + ], + 'restrict_delivery_to' => [2], + ]; + $job = new Job([ + 'type' => 'test_job_type', + 'payload' => $payload, + 'state' => Job::STATE_QUEUED, + ]); + + $result = $this->jobType->process($job); + $this->assertEquals(Job::STATE_FAILURE, $result->getState()); + $this->assertEquals('Recipient is not on the allow list for message 1.', $result->getMessage()); + } + + /** + * Tests the process method with an error due to missing template values. + */ + public function testProcessFailureMissingTemplateValues() { + $payload = [ + 'values' => [], + ]; + $job = new Job([ + 'type' => 'test_job_type', + 'payload' => $payload, + 'state' => Job::STATE_QUEUED, + ]); + $this->expectException(MissingDataException::class); + $this->expectExceptionMessage('Missing template_values in payload for job id'); + $result = $this->jobType->process($job); + $this->assertEquals(Job::STATE_FAILURE, $result->getState()); + + } + +}