diff --git a/composer.json b/composer.json index d35ff3e2ad..f689c18d31 100644 --- a/composer.json +++ b/composer.json @@ -772,7 +772,7 @@ ], "va:test:phpunit-functional": [ "# Run PHPUnit (functional) tests.", - "! ./scripts/should-run-directly.sh || bin/phpunit --group foo-functional --exclude-group disabled tests/phpunit --", + "! ./scripts/should-run-directly.sh || bin/phpunit --group functional --exclude-group disabled tests/phpunit --", "./scripts/should-run-directly.sh || ddev composer va:test:phpunit-functional --" ], "va:test:phpunit-unit": [ diff --git a/docroot/modules/custom/va_gov_api/src/Controller/BannerAlertsController.php b/docroot/modules/custom/va_gov_api/src/Controller/BannerAlertsController.php index 3589e52337..3602f92388 100644 --- a/docroot/modules/custom/va_gov_api/src/Controller/BannerAlertsController.php +++ b/docroot/modules/custom/va_gov_api/src/Controller/BannerAlertsController.php @@ -82,10 +82,14 @@ public function bannerAlertsByPath(Request $request) { 'data' => array_merge($banners, $promo_banners, $full_width_banner_alerts), ]); - // @todo Add path to cache somehow... - // $item_path_context = (new CacheableMetadata())->addCacheContexts(['url.query_args:item-path']); + // Add the 'path' query parameter to the cache contexts. + $response->getCacheableMetadata()->addCacheContexts(['url.query_args:path']); + + // Add the cache tags from the banner nodes and set TTL. $cache_tags = array_merge($banner_cache_tags, $promo_cache_tags, $full_width_banner_alert_cache_tags); $response->getCacheableMetadata()->addCacheTags($cache_tags); + $one_day = 60 * 60 * 24; + $response->getCacheableMetadata()->setCacheMaxAge($one_day); return $response; } @@ -99,7 +103,7 @@ public function bannerAlertsByPath(Request $request) { * @param string $path * The path to the item to find banners for. */ - protected function collectBannerData(string $path) { + protected function collectBannerData(string $path): array { $node_storage = $this->entityTypeManager->getStorage('node'); // Get all published banner nodes. @@ -143,7 +147,7 @@ protected function collectBannerData(string $path) { * @param string $path * The path to the item to find promo_banners for. */ - protected function collectPromoBannerData(string $path) { + protected function collectPromoBannerData(string $path): array { $node_storage = $this->entityTypeManager->getStorage('node'); // Get all published promo_banner nodes. @@ -187,7 +191,7 @@ protected function collectPromoBannerData(string $path) { * @param string $path * The path to the item to find full_width_banner_alerts for. */ - protected function collectFullWidthBannerAlertData(string $path) { + protected function collectFullWidthBannerAlertData(string $path): array { // Find the first fragment of the path; this will correspond to a facility, // if this is a facility page of some kind. $region_fragment = '__not_a_real_url'; @@ -201,7 +205,7 @@ protected function collectFullWidthBannerAlertData(string $path) { if ($url === FALSE || !$url->isRouted() || !isset($url->getRouteParameters()['node'])) { // If the alias is invalid, it's not a routed URL, or there is not a node // in the route params, there's not much else that can be done here. - return; + return [[], []]; } // Load the system that we found. @@ -212,7 +216,7 @@ protected function collectFullWidthBannerAlertData(string $path) { // If it's not a published VAMC system node, bail early. if (is_null($system_node) || $system_node->getType() != 'health_care_region_page' || $system_node->isPublished() === FALSE) { - return; + return [[], []]; } // Find all operating status nodes which have this system as their office. @@ -225,7 +229,7 @@ protected function collectFullWidthBannerAlertData(string $path) { // If there are no operating status nids, bail. if (count($operating_status_nids) === 0) { - return; + return [[], []]; } // Find any facility banners connected to the operating status nodes. @@ -269,7 +273,7 @@ protected function collectFullWidthBannerAlertData(string $path) { * @return array * The flattened data. */ - private function flattenData(array $data): array { + private function flattenData(array $data = []): array { return array_map(function ($item) { $result = []; foreach ($item as $key => $value) { @@ -278,7 +282,8 @@ private function flattenData(array $data): array { // Get the first element of the array. $firstElement = reset($value); - // Check if the first element itself is an associative array with exactly one key. + // Check if the first element itself is an associative array + // with exactly one key. if (is_array($firstElement) && count($firstElement) === 1 && array_key_exists('value', $firstElement)) { @@ -286,7 +291,8 @@ private function flattenData(array $data): array { $result[$key] = $firstElement['value']; } else { - // Keep the first element as is, since it's an associative array with multiple keys. + // Keep the first element as is, + // since it's an associative array with multiple keys. $result[$key] = $firstElement; } } diff --git a/docroot/modules/custom/va_gov_api/src/EventSubscriber/FullWidthBannerAlertSubscriber.php b/docroot/modules/custom/va_gov_api/src/EventSubscriber/FullWidthBannerAlertSubscriber.php deleted file mode 100644 index 7c8e461648..0000000000 --- a/docroot/modules/custom/va_gov_api/src/EventSubscriber/FullWidthBannerAlertSubscriber.php +++ /dev/null @@ -1,89 +0,0 @@ -entityTypeManager = $entityTypeManager; - } - - /** - * {@inheritdoc} - */ - public static function getSubscribedEvents(): array { - return [ - KernelEvents::RESPONSE => 'onKernelResponse', - ]; - } - - /** - * Modify response to add "field_situation_updates" paragraph data. - */ - public function onKernelResponse(ResponseEvent $event): void { - // Only modify the "/jsonapi/banner-alerts" route. - $request = $event->getRequest(); - if ($request->get('_route') !== 'va_gov_api.banner_alerts') { - return; - } - - $response = $event->getResponse(); - $decoded_content = json_decode($response->getContent(), TRUE); - $base_domain = $request->getSchemeAndHttpHost(); - - // Loop through data array and add "field_situation_updates" paragraph data. - foreach ($decoded_content['data'] as $value) { - if ($situation_updates_meta = $value['relationships']['field_situation_updates']['data']) { - foreach ($situation_updates_meta as $situation_update_meta) { - $situation_update_id = $situation_update_meta['meta']['drupal_internal__target_id']; - /** @var \Drupal\paragraphs\Entity\Paragraph $paragraph */ - $paragraph = $this->entityTypeManager->getStorage('paragraph')->load($situation_update_id); - $revision_id = $paragraph->getRevisionId(); - $paragraph_type = $paragraph->getType(); - $uuid = $paragraph->uuid(); - - $paragraphData = [ - 'type' => 'paragraph--' . $paragraph_type, - 'id' => $uuid, - 'links' => [ - 'self' => [ - 'href' => "$base_domain/jsonapi/paragraph/$paragraph_type/$uuid?resourceVersion=id%3A$revision_id", - ], - ], - 'attributes' => [ - 'drupal_internal__id' => $paragraph->id(), - 'drupal_internal__revision_id' => $revision_id, - 'parent_id' => $paragraph->get('parent_id')->getValue()[0], - 'field_datetime_range_timezone' => $paragraph->get('field_datetime_range_timezone')->getValue()[0], - 'field_send_email_to_subscribers' => $paragraph->get('field_send_email_to_subscribers')->getValue()[0], - 'field_wysiwyg' => $paragraph->get('field_wysiwyg')->getValue()[0], - ], - 'relationships' => [], - ]; - - $decoded_content['included'][] = $paragraphData; - } - } - } - - $content = json_encode($decoded_content); - $response->setContent($content); - } - -} diff --git a/docroot/modules/custom/va_gov_api/src/Field/ComputedSituationUpdatesItemList.php b/docroot/modules/custom/va_gov_api/src/Field/ComputedSituationUpdatesItemList.php deleted file mode 100644 index 2fb85b9879..0000000000 --- a/docroot/modules/custom/va_gov_api/src/Field/ComputedSituationUpdatesItemList.php +++ /dev/null @@ -1,49 +0,0 @@ -getEntity(); - if ($parent->isNew()) { - return; - } - - // Get paragraph ids from 'field_situation_updates' field. - $situation_updates = $parent->get('field_situation_updates')->getValue(); - $situation_update_ids = array_column($situation_updates, 'target_id'); - - // Load paragraph entities. - $paragraphs = \Drupal::entityTypeManager() - ->getStorage('paragraph') - ->loadMultiple($situation_update_ids); - - foreach ($paragraphs as $key => $paragraph) { - $paragraphData = [ - 'revision_id' => $paragraph->getRevisionId(), - 'paragraph_type' => $paragraph->getType(), - 'uuid' => $paragraph->uuid(), - 'field_datetime_range_timezone' => $paragraph->get('field_datetime_range_timezone') - ->getValue()[0], - 'field_send_email_to_subscribers' => $paragraph->get('field_send_email_to_subscribers') - ->getValue()[0], - 'field_wysiwyg' => $paragraph->get('field_wysiwyg')->getValue()[0], - ]; - - $this->list[$key] = $this->createItem($key, $paragraphData); - } - } - -} diff --git a/docroot/modules/custom/va_gov_api/src/Resources/BannerAlerts.php b/docroot/modules/custom/va_gov_api/src/Resources/BannerAlerts.php deleted file mode 100644 index 7440f9eb05..0000000000 --- a/docroot/modules/custom/va_gov_api/src/Resources/BannerAlerts.php +++ /dev/null @@ -1,353 +0,0 @@ -pathMatcher = $path_matcher; - $this->pathValidator = $path_validator; - $this->pageCacheKillSwitch = $page_cache_kill_switch; - } - - /** - * {@inheritDoc} - */ - public static function create(ContainerInterface $container) { - return new static( - $container->get('path.matcher'), - $container->get('path.validator'), - $container->get('page_cache_kill_switch') - ); - } - - /** - * Process the resource request. - * - * @param \Symfony\Component\HttpFoundation\Request $request - * The request. - * @param \Drupal\jsonapi\ResourceType\ResourceType[] $resource_types - * The route resource types. - * @param mixed $resource_tag - * An arg that is passed. - * - * @return \Drupal\jsonapi\ResourceResponse - * The response. - */ - public function process(Request $request, array $resource_types, $resource_tag = NULL): ResourceResponse { - // Vary the response by item-path. - $this->addItemPathCacheableDependency(); - - // Make the resource parameter available to other methods. - if (!is_null($resource_tag)) { - // @phpstan-ignore-next-line - $this->addRouteParameter('resource_tag', $resource_tag); - } - - $path = $request->get('item-path'); - - // Collect the data. - if (!is_null($path)) { - foreach ($resource_types as $resource_type) { - switch ($resource_type->getTypeName()) { - case 'node--banner': - $this->collectBannerData($path, $resource_type); - break; - - case 'node--promo_banner': - $this->collectPromoBannerData($path, $resource_type); - break; - - case 'node--full_width_banner_alert': - $this->collectFullWidthBannerAlertData($path, $resource_type); - break; - } - } - } - - return $this->buildResponse($request); - } - - /** - * Build a resource response. - */ - protected function buildResponse($request) { - $resource_object_data = new ResourceObjectData($this->resourceObjects); - - /** @var \Drupal\Core\Cache\CacheableResponseInterface $response */ - $response = $this->createJsonapiResponse($resource_object_data, $request); - - foreach ($this->cacheableDependencies as $cacheable_dependency) { - $response->addCacheableDependency($cacheable_dependency); - } - - // If it's an empty response, then we shouldn't cache it at all -- we don't - // have a good way of invalidating the cache of an empty result (since the - // cache invlidation is based on the nodes that are actually included in the - // response). - if (empty($this->resourceObjects) || empty($this->cacheableDependencies)) { - $this->pageCacheKillSwitch->trigger(); - } - - return $response; - } - - /** - * Collect `banner` entities to be returned in the response. - * - * Given a path, retrieves any `banner` that should show there, constructs a - * ResponseObject for it, and adds it to cacheableDependencies. - * - * @param string $path - * The path to the item to find banners for. - * @param \Drupal\jsonapi\ResourceType\ResourceType $resource_type - * The ResourceType we want to collect data for. - */ - protected function collectBannerData(string $path, ResourceType $resource_type) { - $node_storage = $this->entityTypeManager->getStorage('node'); - - // Get all published banner nodes. - $banner_nids = $node_storage->getQuery() - ->condition('type', 'banner') - ->condition('status', TRUE) - ->accessCheck(FALSE) - ->execute(); - /** @var \Drupal\node\NodeInterface[] $banners */ - $banners = $node_storage->loadMultiple(array_values($banner_nids) ?? []); - - // Filter the banner list to just the ones that should be displayed for the - // provided item path. - $banners = array_filter($banners, function ($item) use ($path) { - // PathMatcher expects a newline delimited string for multiple paths. - $patterns = ''; - foreach ($item->field_target_paths->getValue() as $target_path) { - $patterns .= $target_path['value'] . "\n"; - } - - return $this->pathMatcher->matchPath($path, $patterns); - }); - - // Add the banners to the response. - foreach ($banners as $entity) { - $this->addEntityToResponse($resource_type, $entity); - } - } - - /** - * Collect `promo_banner` entities to be returned in the response. - * - * Given a path, retrieves any `promo_banner` that should show there, - * constructs a ResponseObject for it, and adds it to cacheableDependencies. - * - * @param string $path - * The path to the item to find promo_banners for. - * @param \Drupal\jsonapi\ResourceType\ResourceType $resource_type - * The ResourceType we want to collect data for. - */ - protected function collectPromoBannerData(string $path, ResourceType $resource_type) { - $node_storage = $this->entityTypeManager->getStorage('node'); - - // Get all published promo_banner nodes. - $promo_banner_nids = $node_storage->getQuery() - ->condition('type', 'promo_banner') - ->condition('status', TRUE) - ->accessCheck(FALSE) - ->execute(); - /** @var \Drupal\node\NodeInterface[] $promo_banners */ - $promo_banners = $node_storage->loadMultiple(array_values($promo_banner_nids) ?? []); - - // Filter the promo_banner list to just the ones that should be displayed - // for the provided item path. - $promo_banners = array_filter($promo_banners, function ($item) use ($path) { - // PathMatcher expects a newline delimited string for multiple paths. - $patterns = ''; - foreach ($item->field_target_paths->getValue() as $target_path) { - $patterns .= $target_path['value'] . "\n"; - } - - return $this->pathMatcher->matchPath($path, $patterns); - }); - - // Add the promo_banners to the response. - foreach ($promo_banners as $entity) { - $this->addEntityToResponse($resource_type, $entity); - } - } - - /** - * Collect `full_width_banner_alert` entities to be returned in the response. - * - * Given a path, retrieves any `full_width_banner_alert` that should show - * there, constructs a ResponseObject for it, and adds it to - * cacheableDependencies. - * - * @param string $path - * The path to the item to find full_width_banner_alerts for. - * @param \Drupal\jsonapi\ResourceType\ResourceType $resource_type - * The ResourceType we want to collect data for. - */ - protected function collectFullWidthBannerAlertData(string $path, ResourceType $resource_type) { - // Find the first fragment of the path; this will correspond to a facility, - // if this is a facility page of some kind. - $region_fragment = '__not_a_real_url'; - $path_pieces = explode("/", $path); - if (count($path_pieces) > 1) { - $region_fragment = "/" . $path_pieces[1]; - } - - // Resolve the region fragment to a URL object. - $url = $this->pathValidator->getUrlIfValidWithoutAccessCheck($region_fragment); - if ($url === FALSE || !$url->isRouted() || !isset($url->getRouteParameters()['node'])) { - // If the alias is invalid, it's not a routed URL, or there is not a node - // in the route params, there's not much else that can be done here. - return; - } - - // Load the system that we found. - $node_storage = $this->entityTypeManager->getStorage('node'); - $system_nid = $url->getRouteParameters()['node']; - /** @var \Drupal\node\NodeInterface $system_node */ - $system_node = $node_storage->load($system_nid); - - // If it's not a published VAMC system node, bail early. - if (is_null($system_node) || $system_node->getType() != 'health_care_region_page' || $system_node->isPublished() === FALSE) { - return; - } - - // Find all operating status nodes which have this system as their office. - $operating_status_nids = $node_storage->getQuery() - ->condition('type', 'vamc_operating_status_and_alerts') - ->condition('status', TRUE) - ->condition('field_office', $system_node->id()) - ->accessCheck(FALSE) - ->execute(); - - // If there are no operating status nids, bail. - if (count($operating_status_nids) === 0) { - return; - } - - // Find any facility banners connected to the operating status nodes. - $facility_banner_nids = $node_storage->getQuery() - ->condition('type', 'full_width_banner_alert') - ->condition('status', TRUE) - ->condition('field_banner_alert_vamcs', array_values($operating_status_nids), 'IN') - ->accessCheck(FALSE) - ->execute(); - - /** @var \Drupal\node\NodeInterface[] $facility_banners */ - $facility_banners = $node_storage->loadMultiple($facility_banner_nids); - - // Add the banners to the response. - foreach ($facility_banners as $entity) { - $this->addEntityToResponse($resource_type, $entity); - } - } - - /** - * Add a cacheable dependency and resource object for an entity. - * - * @param \Drupal\jsonapi\ResourceType\ResourceType $resource_type - * The resource type of the entity. - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity object to add to the response. - */ - protected function addEntityToResponse(ResourceType $resource_type, EntityInterface $entity) { - $this->addCacheableDependency($entity); - $this->addResourceObject(ResourceObject::createFromEntity($resource_type, $entity)); - } - - /** - * The endpoint cache must vary on the item-path. - */ - protected function addItemPathCacheableDependency() { - $item_path_context = (new CacheableMetadata())->addCacheContexts(['url.query_args:item-path']); - $this->addCacheableDependency($item_path_context); - } - - /** - * Add a CacheableDependency object to be used in constructing our response. - * - * @param mixed $cacheable_dependency - * The dependency object to add to our response. - */ - protected function addCacheableDependency($cacheable_dependency) { - if (!($cacheable_dependency instanceof CacheableMetadata)) { - $cacheable_dependency = CacheableMetadata::createFromObject($cacheable_dependency); - } - $this->cacheableDependencies[] = $cacheable_dependency; - } - - /** - * Add a response object to be used in constructing our response. - * - * @param \Drupal\jsonapi\JsonApiResource\ResourceObject $resource_object - * The ResourceObject to add to our response. - */ - protected function addResourceObject(ResourceObject $resource_object) { - $this->resourceObjects[] = $resource_object; - } - -} diff --git a/docroot/modules/custom/va_gov_api/va_gov_api.routing.yml b/docroot/modules/custom/va_gov_api/va_gov_api.routing.yml index c7c5d584d3..96bcd6b699 100644 --- a/docroot/modules/custom/va_gov_api/va_gov_api.routing.yml +++ b/docroot/modules/custom/va_gov_api/va_gov_api.routing.yml @@ -1,14 +1,3 @@ -va_gov_api.banner_alerts: - path: '/%jsonapi%/banner-alerts' - methods: ['GET'] - defaults: - _jsonapi_resource: Drupal\va_gov_api\Resources\BannerAlerts - _jsonapi_resource_types: ['node--banner', 'node--full_width_banner_alert', 'node--promo_banner'] - requirements: - _permission: 'access content' - _content_type_format: api_json - _format: api_json - va_gov_api.new_banner_alerts: path: '/api/v1/banner-alerts' defaults: diff --git a/docroot/modules/custom/va_gov_api/va_gov_api.services.yml b/docroot/modules/custom/va_gov_api/va_gov_api.services.yml index b4be74fe78..0ef9a7810e 100644 --- a/docroot/modules/custom/va_gov_api/va_gov_api.services.yml +++ b/docroot/modules/custom/va_gov_api/va_gov_api.services.yml @@ -7,8 +7,3 @@ services: arguments: ['@request_stack'] tags: - { name: event_subscriber } -# va_gov_api.full_width_banner_alert_subscriber: -# class: Drupal\va_gov_api\EventSubscriber\FullWidthBannerAlertSubscriber -# arguments: ['@entity_type.manager'] -# tags: -# - { name: event_subscriber } diff --git a/tests/phpunit/API/BannerEndpointTest.php b/tests/phpunit/API/BannerEndpointTest.php index b4a52f1f36..92ba2331be 100644 --- a/tests/phpunit/API/BannerEndpointTest.php +++ b/tests/phpunit/API/BannerEndpointTest.php @@ -1,7 +1,8 @@ drupalLogin($this->createUser(['access content'])); + } + + /** + * Test that the banner endpoint handles full width alert banners. + */ + public function testFullWidthAlertBanner() { + // Look for a 'full_width_banner_alert' node. + $node_storage = \Drupal::entityTypeManager()->getStorage('node'); + $banner_nids = $node_storage->getQuery() + ->condition('type', 'full_width_banner_alert') + // ->condition('status', TRUE) + ->exists('field_banner_alert_vamcs') + ->range(0, 1) + ->accessCheck(FALSE) + ->execute(); + + // Load and publish the node. + $banner_nid = reset($banner_nids); + $banner = $node_storage->load($banner_nid); + + // Get 'field_banner_alert_vamcs' data. + $banner_alert_vamcs = $banner->get('field_banner_alert_vamcs')->getValue(); + + $banner->set('status', TRUE); + $banner->save(); + + // Look for a published node of type "vamc_operating_status_and_alerts". + $system_nids = $node_storage->getQuery() + ->condition('type', 'vamc_operating_status_and_alerts') + ->condition('status', TRUE) + ->condition('nid', $banner_alert_vamcs[0]['target_id']) + ->range(0, 1) + ->accessCheck(FALSE) + ->execute(); + + // Get first array value. + $system_nid = reset($system_nids); + + // Load the entity. + $system_node = $node_storage->load($system_nid); + // Get entity id from "field_office" field. + $office_nid = $system_node->get('field_office')->target_id; + $path_alias = \Drupal::database()->select('path_alias', 'pa') + ->fields('pa', ['alias']) + ->condition('path', '/node/' . $office_nid) + ->execute() + ->fetchField(); + + // Create 'situation_update' paragraph. + $situation_update = Paragraph::create([ + 'type' => 'situation_update', + 'status' => 1, + 'field_datetime_range_timezone' => [ + [ + 'value' => '2024-01-23T12:22:00+00:00', + 'end_value' => '2024-01-23T13:22:00+00:00', + ], + ], + 'field_send_email_to_subscribers' => [ + [ + 'value' => FALSE, + ], + ], + 'field_wysiwyg' => [ + [ + 'value' => '

!!!: Situation updates are included in the response.

', + 'format' => 'rich_text', + ], + ], + ]); + + // Add 'situation_update' paragraph to 'field_situation_updates' field. + $banner->get('field_situation_updates')->appendItem($situation_update); + $banner->save(); + + // Visit the banner endpoint using the path alias. + $this->visit('/api/v1/banner-alerts?path=' . $path_alias); + $this->assertEquals(200, $this->getSession()->getStatusCode()); + + $json = json_decode($this->getSession()->getPage()->getContent(), TRUE); + + // Confirm that the banner is included in the response. + $this->assertIsArray($json['data']); + + $filtered_nodes = array_filter($json['data'], function ($item) use ($banner) { + return isset($item['nid']) && $item['nid'] == $banner->id(); + }); + $this->assertNotEmpty($filtered_nodes, 'Node with nid ' . $banner->id() . ' found in response.'); + + // Confirm that the string "65130" is in the response. + $this->assertStringContainsString( + '!!!: Situation updates are included in the response.', + $this->getSession()->getPage()->getContent() + ); + + // Delete the paragraph. + $situation_update->delete(); + } + /** * Provides data to testBanner(). */ @@ -42,12 +148,9 @@ public function provideBannerTestData() { * @dataProvider provideBannerTestData */ public function testBanner($path, $shouldBeIncluded) { - $author = $this->createUser(); - $banner_data = [ 'field_alert_type' => 'information', 'title' => 'Test Banner', - 'uid' => $author->id(), 'field_target_paths' => [], 'type' => 'banner', ]; @@ -66,25 +169,93 @@ public function testBanner($path, $shouldBeIncluded) { // Make sure the banner is found in all the requests that it _should_ be // included in (and not in the places where it should not be). - $response = \Drupal::httpClient()->get($url . '/jsonapi/banner-alerts?item-path=' . $path); + $response = \Drupal::httpClient()->get($url . '/api/v1/banner-alerts?path=' . $path); $this->assertEquals('200', $response->getStatusCode(), 'request returned status code ' . $response->getStatusCode()); - $json = json_decode($response->getBody()); + $json = json_decode($response->getBody(), TRUE); + + $filtered_nodes = array_filter($json['data'], function ($item) use ($banner) { + return isset($item['nid']) && $item['nid'] == $banner->id(); + }); + + if ($shouldBeIncluded) { + $this->assertNotEmpty($filtered_nodes, 'Node with nid ' . $banner->id() . ' found in response.'); + } + else { + $this->assertEmpty($filtered_nodes, 'Node with nid ' . $banner->id() . ' not found in response.'); + } + } + + /** + * Provides data to testPromoBanner(). + */ + public function providePromorBannerTestData() { + return [ + 'first level path' => [ + '/banner-endpoint-test-path', + TRUE, + ], + 'second level path' => [ + '/banner-endpoint-test-path/second-level-path', + TRUE, + ], + 'third level path' => [ + '/banner-endpoint-test-path/second-level-path/one-more-segment', + TRUE, + ], + 'banner not present' => [ + '/banner-should-not-be-here', + FALSE, + ], + ]; + } - $found = FALSE; - foreach ($json->data as $item) { - if ((string) $item->attributes->drupal_internal__nid === $banner->id()) { - $found = TRUE; - break; - } + /** + * Test that promo banners are included in the banner endpoint response. + * + * @dataProvider providePromorBannerTestData + */ + public function testPromoBanner($path, $shouldBeIncluded) { + $banner_data = [ + 'field_promo_type' => 'announcement', + 'title' => 'Test Promo Banner', + 'field_link' => [ + ['uri' => 'internal:/node/50621'], + ], + 'field_target_paths' => [], + 'type' => 'promo_banner', + ]; + if ($shouldBeIncluded) { + $banner_data['field_target_paths'][] = ['value' => $path]; } + $banner = $this->createNode($banner_data); + $banner->set('moderation_state', 'published')->setPublished(TRUE)->save(); + + // This assertion isn't strictly necessary, but we need to have at least one + // per test. If the request below fails, we wouldn't have one. + $this->assertTrue($banner->isPublished(), 'banner ' . $banner->id() . ' is published'); + + $url = $this->baseUrl; + + // Make sure the banner is found in all the requests that it _should_ be + // included in (and not in the places where it should not be). + $response = \Drupal::httpClient()->get($url . '/api/v1/banner-alerts?path=' . $path); + $this->assertEquals('200', $response->getStatusCode(), 'request returned status code ' . $response->getStatusCode()); + + $json = json_decode($response->getBody(), TRUE); + + $filtered_nodes = array_filter($json['data'], function ($item) use ($banner) { + return isset($item['nid']) && $item['nid'] == $banner->id(); + }); + if ($shouldBeIncluded) { - $this->assertTrue($found, 'banner id ' . $banner->id() . ' was found in JSON API response for ' . $path); + $this->assertNotEmpty($filtered_nodes, 'Node with nid ' . $banner->id() . ' found in response.'); } else { - $this->assertFalse($found, 'banner id ' . $banner->id() . ' was not found in JSON API response for ' . $path); + $this->assertEmpty($filtered_nodes, 'Node with nid ' . $banner->id() . ' not found in response.'); } + } } diff --git a/tests/phpunit/API/NewBannerEndpointTest.php b/tests/phpunit/API/NewBannerEndpointTest.php deleted file mode 100644 index 8c617fa6e7..0000000000 --- a/tests/phpunit/API/NewBannerEndpointTest.php +++ /dev/null @@ -1,114 +0,0 @@ -drupalLogin($this->createUser(['access content'])); - } - - /** - * Test that the banner endpoint handles full width alert banners. - */ - public function testFullWidthAlertBanner() { - // Create 'situation_update' paragraph. - $situation_update = Paragraph::create([ - 'type' => 'situation_update', - 'status' => 1, - 'field_datetime_range_timezone' => [ - [ - 'value' => '2024-01-23T12:22:00+00:00', - 'end_value' => '2024-01-23T13:22:00+00:00', - ], - ], - 'field_send_email_to_subscribers' => [ - [ - 'value' => FALSE, - ], - ], - 'field_wysiwyg' => [ - [ - 'value' => '

blah blah blah

', - 'format' => 'rich_text', - ], - ], - ]); - - // Look for a 'full_width_banner_alert' node. - $node_storage = \Drupal::entityTypeManager()->getStorage('node'); - $banner_nids = $node_storage->getQuery() - ->condition('type', 'full_width_banner_alert') - // ->condition('status', TRUE) - ->range(0, 1) - ->accessCheck(FALSE) - ->execute(); - - // Load and publish the node. - $banner_nid = reset($banner_nids); - $banner = $node_storage->load($banner_nid); - - // Get 'field_banner_alert_vamcs' data. - $banner_alert_vamcs = $banner->get('field_banner_alert_vamcs')->getValue(); - - $banner->set('status', TRUE); - $banner->save(); - - // Look for a published node of type "vamc_operating_status_and_alerts". - $system_nids = $node_storage->getQuery() - ->condition('type', 'vamc_operating_status_and_alerts') - ->condition('status', TRUE) - ->condition('id', $banner_alert_vamcs[0]['target_id']) - ->range(0, 1) - ->accessCheck(FALSE) - ->execute(); - - // Get first array value. - $system_nid = reset($system_nids); - - // Load the entity. - $system_node = $node_storage->load($system_nid); - // Get entity id from "field_office" field. - $office_nid = $system_node->get('field_office')->target_id; - $path_alias = \Drupal::database()->select('path_alias', 'pa') - ->fields('pa', ['alias']) - ->condition('path', '/node/' . $office_nid) - ->execute() - ->fetchField(); - - // Visit the banner endpoint using the path alias. - $this->visit('/api/v1/banner-alerts?path=' . $path_alias); - $this->assertEquals(200, $this->getSession()->getStatusCode()); - - $json = json_decode($this->getSession()->getPage()->getContent(), TRUE); - - // Confirm that the banner is included in the response. - $this->assertIsArray($json['data']); - - $filtered_nodes = array_filter($json['data'], function ($item) use ($banner) { - return isset($item['nid']) && $item['nid'] == $banner->id(); - }); - - $this->assertNotEmpty($filtered_nodes, 'Node with nid ' . $banner->id() . ' found in response.'); - - // Confirm that the string "65130" is in the response. - $this->assertStringContainsString('"nid":' . $banner->id(), $this->getSession()->getPage()->getContent()); - - // Delete the paragraph. - $situation_update->delete(); - } - -}